关于jsx:为什么浏览器无法读取JSX

浏览器只能解决 JavaScript 对象,而不能读取惯例 JavaScript 对象中的 JSX。所以为了使浏览器可能读取 JSX,首先,须要用像 Babel 这样的 JSX 转换器将 JSX 文件转换为 JavaScript 对象,而后再将其传给浏览器。

February 15, 2022 · 1 min · jiezi

React基础3不可不知的JSX

前言JSX中添加属性有什么要注意的?以及JSX中的子元素是怎么操作的?组件的大小写问题,使用拓展运算符,以及怎么循坏遍历一个对象JSX中的prop指的是什么?以及表单的labe应该要注意什么?以上问题即使自己很清楚,但是否有时却总是道不清,说不明?那么读完本文,就豁然开朗了 JSX添加特定属性自定义标签拓展了原生HTML标签不具备的能力,最大的一个用处就是属性传值,标签的属性值,可以是字符串,变量对象 例如:如下所示 const element = <div divIndex ="0"></div>当然也可以使用下面这种方式,是等价的,用一个大括号{ }将变量包裹起来 const element = <div divIndex={"0"}></div>至于更多插值表达式内容,你可以看上一节 React学习(2)-深入浅出JSX这里要提一下,在属性中嵌入javascript表达式,不要在双大括号外面加上引号,例如,下面的是错误的 const element = <div divIndex="{ variable }"></div>也就是说,对于字符串或者双大括号中的表达式,对于同一属性,不能同时使用这两种符号 注意 JSX语法是更接近Javascript而不是HTML,只是长得像而已,对于Reat中自定义组件的属性名称,使用 camelCase驼峰式命名来定义属性的名称,例如:定义JSX里的class属性className,而divindex变成 divIndex JSX中的子元素在原生HTML标签中,要是对于DOM结构树熟悉的话,理解JSX的子元素也是比较容易的 原生HTML的标签叫做节点,节点有节点属性,以及节点的内容 如果一个标签或者React组件没有内容,你是可以使用 />,单标签来闭合的,就像XML语法一样,例如如下所示 const element = <img src={ user.avatarUrl} />JSX标签里面能够包含很多个子元素 例如:如下所示 const element = ( <div> <h1 title="我是子h1元素属性的内容">我是子h1元素的节点内容</h1> <h2>欢迎关注微信itclanCoder公众号</h2> <h3>川川是全宇宙最帅的小伙子</h3> </div>)包含在开始和结束标签之间的 JSX 表达式内容将会被作为特定属性 props.children传递给外层组件 其中,有下面几种不同的方法来传递子元素 字符串字面量你可以将字符串放在开始和结束标签之间,此时 props.children就只是该字符串,对于内置的HTML元素是很有用的,但同时要注意怎么接收这个内容 <MyComponent>itclanCoder</MyComponent>上面的JSX,MyComponent的子元素内容是itclanCoder,可以通过 props.children来获取,它是一个没有转移的字符串 itclanCoder JSX会移除首尾行以及空行,与标签相邻的空行都会被删除,文本字符串之间的新航都会被压缩一个空格 所以下面的这几种写法都是等价的,但是笔者建议,该换行就换行的 <div>itclanCoder</div><div> itclanCoder</div><div> 川川 itclanCoder</div><div> itclanCoder</div>JSX子元素嵌套在React中,子元素允许由多个JSX元素组成,组件可以嵌套组件,例如:如下所示 <MyContainer> <Header /> <Navigator /> <Aside /> <Footer /></MyContainer>在React中,是可以将不同类型的子元素混合在一起的,这跟在以前写HTML是一样的 ...

November 5, 2019 · 3 min · jiezi

使用jsx配置elementui的table

背景由于表格数据比较同构,有时候列配置是动态的,此时希望使用v-for来配置column <template><el-table :data="tableData"> <el-table-column v-for="col in columns" :key="col.dataIndex" :label="col.title" :prop="col.dataIndex" :formatter="col.render" /></el-table></template><script>const PHONE_COLS = [ { title: '录音id', dataIndex: 'attach_id' }, { title: '接听客服', dataIndex: 'handle_user_info' }, { title: '呼叫类型', dataIndex: 'type_desc' }, { title: '通话时长', dataIndex: 'duration' },];const WORK_COLS = [ { title: '工单id', dataIndex: 'attach_id' }, { title: '创建客服', dataIndex: 'handle_user_info' }, { title: '创建时间', dataIndex: 'c_t' }, { title: '工单来源', dataIndex: 'source' }, { title: '工单分类', dataIndex: 'ws_type', render: (row, column, cell) => (cell || []).join(',') }];export default { data () { return { columns: PHONE_COLS, tableData: [], tableTotal: 0, } },}</script>可以看到代码比直接使用template更加简洁,另外也可以利用formatter函数处理简单的自定义字符串 ...

October 15, 2019 · 2 min · jiezi

Vue中jsx不完全应用指南

前言:文章不介绍任务背景知识,没有原理说明,偏向于实践的总结和经验分享。文章所有的代码是基于Vue CLI 3.x版本,不会涉及到一步步通过Webpack来配置JSX所需要的知识点。 在使用Vue开发项目时绝大多数情况下都是使用模板来写HTML,但是有些时候页面复杂又存在各种条件判断来显示/隐藏和拼凑页面内容,或者页面中很多部分存在部分DOM结构一样的时候就略显捉襟见肘,会写大量重复的代码,会出现单个.vue文件过长的情况,这个时候我们就需要更多的代码控制,这时候可以使用渲染函数。 渲染函数想必平时几乎没有人去写,因为写起来很痛苦(本人也没有写过)。更多的是在Vue中使用JSX语法。写法上和在React中差不多,但是功能上还是没有React中那么完善。 在写JSX的过程中不得考虑一个样式的问题,虽然可以直接在.vue文件中不写<tempate>部分,只写<script>和<style>部分,而不用担心样式作用域问题。但是更多的时候还是推荐直接使用.js的方式来写组件,这个时候就涉及到样式作用域的问题了。 在React的生态中,有很多CSS-IN-JS的解决方案,比如styled-jsx、emotion、styled-components等,目前最活跃和用户量最多的是styled-components,目前已经拥有良好的生态圈子。如果需要在样式中作一些像Sass/Less中的颜色计算,可以使用polished来实现,当然不止这么简单的功能。但是在Vue中可使用的方案就太少了,因为Vue使用模板来写HTML本身是开箱即用的样式scoped,在使用JSX写组件的时候就面临着样式问题,一种方案是在组件包裹<div>中取一个特殊的名字,然后样式都嵌套写在这个class下面,但是难免会遇到命名冲突的情况,而且每次还得变着花样取名称。此外,就是引入CSS-IN-JS在Vue对应的实现,但目前来看Styled-components官方提供了一个Vue版本的叫vue-styled-components和emotion的vue-emotion,但是用的人实在太少。像styled-components进行了重大更新和变化,但是Vue版本的还是最初的版本,而且有时候还出现样式不生效的情况。 接下来进入正题,从简单语法到经验分享(大牛请绕行) 基本用法首先需要约定一下,使用JSX组件命名采用首字母大写的驼峰命名方式,样式可以少的可以直接基于vue-styled-components写在同一个文件中,复杂的建议放在单独的_Styles.js_文件中,当然也可以不采用CSS-IN-JS的方式,使用Less/Sass来写,然后在文件中import进来。 下面是一个通用的骨架: import styled from 'vue-styled-components'const Container = styled.div` heigth: 100%;`const Dashboard = { name: 'Dashboard', render() { return ( <Container>内容</Container> ) }}export default Dashboard插值在JSX中使用单个括号来绑定文本插值 <span>Message: {this.messsage}</span><!-- 类似于v-html --><div domPropsInnerHTML={this.dangerHtml}/><!-- v-model --><el-input v-model={this.vm.name} />在jsx中不需要把v-model分成事件绑定和赋值二部分分开来写,因为有相应的babel插件来专门处理。 样式在JSX中可以直接使用class="xx"来指定样式类,内联样式可以直接写成style="xxx" <div class="btn btn-default" style="font-size: 12px;">Button</div><!-- 动态指定 --><div class={`btn btn-${this.isDefault ? 'default' : ''}`}></div><div class={{'btn-default': this.isDefault, 'btn-primary': this.isPrimary}}></div><div style={{color: 'red', fontSize: '14px'}}></div>遍历在JSX中没有v-for和v-if等指令的存在,这些全部需要采用Js的方式来实现 {/* 类似于v-if */}{this.withTitle && <Title />}{/* 类似于v-if 加 v-else */}{this.isSubTitle ? <SubTitle /> : <Title />}{/* 类似于v-for */}{this.options.map(option => { <div>{option.title}</div>})}事件绑定事件绑定需要在事件名称前端加上on前缀,原生事件添加nativeOn ...

July 4, 2019 · 5 min · jiezi

一种让小程序支持JSX语法的新思路

React社区一直在探寻使用React语法开发小程序的方式,其中比较著名的项目有Taro,nanachi。而使用React语法开发小程序的难点主要就是在JSX语法上,JSX本质上是JS,相比于小程序静态模版来说太灵活。本文所说的新思路就是在处理JSX语法上的新思路,这是一种更加动态的处理思路,相比于现有方案,基本上不会限制任何JSX的写法,让你以真正的React方式处理小程序,希望这个新思路可以给任何有志于用React开发小程序的人带来启发。 现有思路的局限在介绍新的思路之前,我们先来看下Taro(最新版1.3),nanachi是怎么在小程序端处理JSX语法的。简单来说,主要是通过在编译阶段把JSX转化为等效的小程序wxml来把React代码运行在小程序端的。 举个例子,比如React逻辑表达式: xx && <Text>Hello</Text>将会被转化为等效的小程序wx:if指令: <Text wx:if="{{xx}}">Hello</Text>这种方式把对JSX的处理,主要放在了编译阶段,他依赖于编译阶段的信息收集,以上面为例,它必须识别出逻辑表达式,然后做对应的wx:if转换处理。 那编译阶段有什么问题和局限呢?我们以下面的例子说明: class App extends React.Component { render () { const a = <Text>Hello</Text> const b = a return ( <View> {b} </View> ) }}首先我们声明 const a = <Text>Hello</Text>,然后把a赋值给了b,我们看下最新版本Taro 1.3的转换,如下图: 这个例子不是特别复杂,却报错了。 要想理解上面的代码为什么报错,我们首先要理解编译阶段。本质上来说在编译阶段,代码其实就是‘字符串’,而编译阶段处理方案,就需要从这个‘字符串’中分析出必要的信息(通过AST,正则等方式)然后做对应的等效转换处理。 而对于上面的例子,需要做什么等效处理呢?需要我们在编译阶段分析出b是JSX片段:b = a = <Text>Hello</Text>,然后把<View>{b}</View>中的{b}等效替换为<Text>Hello</Text>。然而在编译阶段要想确定b的值是很困难的,有人说可以往前追溯来确定b的值,也不是不可以,但是考虑一下 由于b = a,那么就先要确定a的值,这个a的值怎么确定呢?需要在b可以访问到的作用域链中确定a,然而a可能又是由其他变量赋值而来,循环往复,期间一旦出现不是简单赋值的情况,比如函数调用,三元判断等运行时信息,追溯就宣告失败,要是a本身就是挂在全局对象上的变量,追溯就更加无从谈起。 所以在编译阶段 是无法简单确定b的值的。 我们再仔细看下上图的报错信息:a is not defined。 为什么说a未定义呢?这是涉及到另外一个问题,我们知道<Text>Hello</Text>,其实等效于React.createElement(Text, null, 'Hello'),而React.createElement方法的返回值就是一个普通JS对象,形如 // ReactElement对象{ tag: Text, props: null, children: 'Hello' ...}所以上面那一段代码在JS环境真正运行的时候,大概等效如下: ...

June 15, 2019 · 2 min · jiezi

react本质JSX如何转化为javascript

react中基本都使用JSX来开发,但JSX其实是javascript的一种语法糖。 什么是语法糖?语法糖就是提供了一种全新的方式书写代码,但是其实现原理与之前的写法相同。语法糖可以说是广泛存在于各种计算机代码中,包括C语言中的a[i]其实就是*a+i的语法糖。而今天对于我们来说,a[i]其实已经很普遍和常用了,所以也没有人提这是语法糖这回事了。因为终极来说,所有语言都是汇编语言的语法糖:) 简单说,JSX是一种更简便书写javascript的方式由于DOM结构被我们写到了javascript文件里,由javascript来生成DOM结构如果一直使用javascript来写DOM结构,那么render函数里就是一堆React.createElement这样既不美观也不实用。 但是我们必须知道,JSX本质上就是javascript在编译的时候,会由babel将JSX转化为javascript。 比如 <div className="aaa"> <span>222</span> <span>333</span></div>生成了 "use strict";React.createElement("div", { className: "aaa"}, React.createElement("span", null, "222"), React.createElement("span", null, "333"));比如 function Comp(){ return <div className='test'>test</div>}<Comp className="test2">222</Comp>生成 "use strict";function Comp() { return React.createElement("div", { className: "test" }, "test");}React.createElement(Comp, { className: "test2"}, "222");了解JSX的本质,只需要记住:JSX本质就是javascript 附录babel提供的一个在线转换JSX为javascript的地址https://babeljs.io/repl/

May 12, 2019 · 1 min · jiezi

重拾JSX

React.createElement语法糖JSX是一种JavaScript的语法拓展,可以使用它来进行UI的展示:const element = <h1>Hello, world!</h1>;我们一般会在组件的render方法里使用JSX进行布局和事件绑定:class Home extends Component { render() { return ( <div onClick={() => console.log(‘hello’)}> <h1>Hello, world!</h1> <Blog title=“deepred” /> </div> ); }}React的核心机制之一就是可以创建虚拟的DOM元素,利用虚拟DOM来减少对实际DOM的操作从而提升性能,JSX正是为了虚拟DOM而存在的语法糖我们在平时的组件编写中,通常都这么写:import React, { Component } from ‘react’;class Demo extends Component { render() { return ( <h1>Hello, world!</h1> ) }}然而代码里面并没有用到React,为什么要引入这个变量呢?因为JSX是React.createElement这个方法的语法糖:const element = <h1 id=“container” className=“home”>Hello</h1>;// 等价于const element = React.createElement(“h1”, { id: “container”, className: “home”}, “Hello”);推荐大家在babeljs.io上看下JSX编译后的实际效果React.createElement有三个参数:React.createElement( type, // dom类型,比如div,h1 [props], // dom属性,比如id,class,事件 […children] // 子节点,字符串或者React.createElement生成的一个对象)JSX用一种类似HTML的语法替代了比较繁琐的React.createElement纯JS方法,而@babel/preset-react插件就起到了最关键的一步:负责在webpack编译时,把所有的JSX都改成React.createElement:class Home extends Component { render() { return ( <div onClick={() => console.log(‘hello’)}> <h1>Hello, world!</h1> <Blog title=“deepred” /> </div> ); }}编译后:class Home extends Component { render() { return React.createElement(“div”, { onClick: () => console.log(‘hello’) }, React.createElement(“h1”, null, “Hello, world!”), React.createElement(Blog, { title: “deepred” })); }}在开发中,有了JSX后我们基本不怎么需要用到createElement方法,但如果我们需要实现这样一个组件:// 根据传入的type属性,渲染成相应的html元素<Tag type=“h1” id=“hello” onClick={() => console.log(‘hello’)}>this is a h1</Tag><Tag type=“p”>this is a p</Tag>我们不太可能根据type的属性,一个个if else去判断对应的标签:function Tag(props) { const { type, …other } = props; if (type === ‘h1’) { return <h1 {…other}>{props.children}</h1> } if (type === ‘p’) { return <p {…other}>{props.children}</p> }}这时,就需要用到底层的api了:function Tag(props) { const { type, …other } = props; return React.createElement(type, other, props.children);}自己实现一个JSX渲染器虚拟dom本质就是一个js对象:const vnode = { tag: ‘div’, attrs: { className: ‘container’ }, children: [ { tag: ‘img’, attrs: { src: ‘1.png’ }, children: [] }, { tag: ‘h3’, attrs: {}, children: [‘hello’] } ]}可以通过在每个文件的上方添加/** @jsx h /来告诉@babel/preset-react用h方法名代替JSX(默认方法是React.createElement)/* @jsx h /const element = <h1 id=“container” className=“home”>Hello</h1>;/* @jsx h /const element = h(“h1”, { id: “container”, className: “home”}, “Hello”);现在让我们开始创建自己的h函数吧!function h(nodeName, attributes, …args) { // 使用concat是为了扁平化args,因为args数组里面的元素可能也是数组 // h(‘div’, {}, [1, 2, 3]) h(’d’, {}, 1, 2, 3) 都是合法的调用 const children = args.length ? [].concat(…args) : null; return { nodeName, attributes, children };}const vnode = h(“div”, { id: “urusai”}, “Hello!”);// 返回// {// “nodeName”: “div”,// “attributes”: {// “id”: “urusai”// },// “children”: [// “Hello!”// ]// }h的作用就是返回一个vnode,有了vnode,我们还需要把vnode转成真实的dom:function render(vnode) { if (typeof vnode === ‘string’) { // 生成文本节点 return document.createTextNode(vnode); } // 生成元素节点并设置属性 const node = document.createElement(vnode.nodeName); const attributes = vnode.attributes || {}; Object.keys(attributes).forEach(key => node.setAttribute(key, attributes[key])); if (vnode.children) { // 递归调用render生成子节点 vnode.children.forEach(child => node.appendChild(render(child))); } return node;}现在让我们使用这两个方法吧:/* @jsx h /const vnode = <div id=“urusai”>Hello!</div>;const node = render(vnode);document.body.appendChild(node);编译转码后:/* @jsx h /const vnode = h(“div”, { id: “urusai”}, “Hello!”);const node = render(vnode);document.body.appendChild(node);我们还可以遍历数组:/* @jsx h /const items = [‘baga’, ‘hentai’, ‘urusai’];const vnode = <ul>{items.map((item, index) => <li key={index}>{item}</li>)}</ul>;const list = render(vnode);document.body.appendChild(list);编译转码后:/* @jsx h */const items = [‘baga’, ‘hentai’, ‘urusai’];const vnode = h(“ul”, null, items.map((item, index) => h(“li”, { key: index}, item)));const list = render(vnode);document.body.appendChild(list);通过h render两个函数,我们就实现了一个很简单的JSX渲染器!!!参考WTF is JSXJSX In DepthReact Without JSX ...

March 20, 2019 · 2 min · jiezi

Nunjucks使用正则表达式示例

我在使用egg.js时,他用的模板引擎是Nunjucks,其中有个地方需要用到正则,可是官方文档基本上写了跟没写一样,官方的正则表达式。于是我便去找例子了。正则表达式在Nunjucks中使用正则表达式的示例:{% set regExp = r/^foo.*/g %}{% if regExp.test(‘foo’) %} Foo in the house!{% endif %}那么这个就会被正常显示。其他的表达式也是可以的。例如:<!– 有个后台存储的未验证的手机号码(mobile)在前端显示,如果格式正确则显示,不正确则显示“暂无” –>{% set regExp = r/^\d{11}$/g %}<span>号码:{{mobile if regExp.test(mobile) else ‘暂无’}}</span>这两个例子应该看得懂吧。正则这块我并没有看源码,因为搜索出来了,我这里参考的regex exmaple?后来发现其实很多方法文档并没有写出来,这时候可能真的需要看看源码了,有兴趣的话可以阅读下filter的源码https://github.com/mozilla/nu…

January 15, 2019 · 1 min · jiezi