render (h) {
return (
<div
// Component props
propsMsg="hi"
// Normal attributes or component props.
id="foo"
// DOM properties are prefixed with `domProps`
domPropsInnerHTML="bar"
// event listeners are prefixed with `on` or `nativeOn`
onClick={this.clickHandler}
nativeOnClick={this.nativeClickHandler}
// other special top-level properties
class={{ foo: true, bar: false }}
style={{ color: 'red', fontSize: '14px' }}
key="key"
ref="ref"
// assign the `ref` is used on elements/components with v-for
refInFor
slot="slot">
</div>
)
}
以上jsx语法糖等同于如何h函数生成VNode:
render (h) {
return h('div', {
// Component props
props: {
msg: 'hi'
},
// Normal HTML attributes
attrs: {
id: 'foo'
},
// DOM props
domProps: {
innerHTML: 'bar'
},
// Event handlers are nested under "on", though
// modifiers such as in v-on:keyup.enter are not
// supported. You'll have to manually check the
// keyCode in the handler instead.
on: {
click: this.clickHandler
},
// For components only. Allows you to listen to
// native events, rather than events emitted from
// the component using vm.$emit.
nativeOn: {
click: this.nativeClickHandler
},
// Class is a special module, same API as `v-bind:class`
class: {
foo: true,
bar: false
},
// Style is also same as `v-bind:style`
style: {
color: 'red',
fontSize: '14px'
},
// Other special top-level properties
key: 'key',
ref: 'ref',
// Assign the `ref` is used on elements/components with v-for
refInFor: true,
slot: 'slot'
})
}
Vue JSX插件依赖及语法实践
文章内容主要分两块。
第一块是了解jsx运行环境,因为jsx只是语法糖,最终都是需要babel来转译语法,所以需要配置相关babel插件。vue-cli3脚手架工具生成的应用工程默认支持jsx/tsx,省去了自己配置的繁琐,但了解相关babel插件对理解和书写jsx非常有帮助。
第二块是实践jsx在vue中的语法以及相关案例。了解jsx是如何生成最终的VNode。tsx应用Demo代码放在github vue-tsx-demo
1. 环境基础babel
vue-cli3自动生成的app项目中,babel.config.js预设了 presets: ["@vue/app"],该插件为babel-preset-app
里面包含插件,主要是babel解析,以支持许多扩展语法。比如
jsx、es6语法
等:里面重点插件有:
1.1 Babel JSX插件集合
1.2 Babel预设插件集合
直接支持ES6模块语法,浏览器能自己解析import语法
,可显著减少包体积)。注意:指定esmodules目标时,浏览器目标将被忽略启用将ES6模块语法转换为其他模块类型的功能
。"amd" | "umd" | "systemjs" | "commonjs" | "cjs" | "auto" | false,默认为"auto"。设置为false不会转换模块
1.3 其他
2. JSX在Vue中语法
react和vue底层vnode diff对比不是使用相同的数据结构,所以导致两者jsx书写方式有些许不同。目前两者大部分jsx语法一致,是因为有各种babel插件辅助做了这部分事。但对于动态属性这样自由化较高的地方,需要我们知道两者本质区别(即不同的VNode数据结构)。
vue template模板本质上最终生成render函数,而render函数本质上是生成VNode,所以有必要了解这个VNode数据结构。Vue2.x VNode diff核心算法借鉴的是snabbdom库,所以数据结构也有snabbdom数据结构的影子,比如事件需要放置在on属性上,方便最终patch时挂载到真实dom元素上(react则自定义模拟事件系统,所有事件都冒泡到顶层document处理)。更多VNode信息可查看Vue官方文档 - 深入数据对象。
以下查看jsx转译为h函数:
以上jsx语法糖等同于如何h函数生成VNode:
使用jsx代替vue需要解决的系列问题:
2.1 基础语法
bable jsx插件会通过正则匹配的方式在编译阶段将书写在组件上属性进行“分类”。 onXXX的均被认为是事件,nativeOnXXX是原生事件,domPropsXXX是Dom属性。
class,staticClass,style,key,ref,refInFor,slot,scopedSlots这些被认为是顶级属性,至于我们属性声明的props,以及html属性attrs,不需要加前缀,插件会将其统一分类到attrs属性下,然后在运行阶段根据是否在props声明来决定属性归属(即属于props还是attrs)。
2.2 动态属性
在React中所有属性都是顶级属性,直接使用{...props}就可以了,但是在Vue中,你需要明确该属性所属的分类,如一个动态属性value和事件change,你可以使用如下方式(延展属性)传递:
尽量使用明确分类的方式传递属性,而不是要babel插件帮你分类及合并属性。
2.3 指令
常用的v-if和v-for,使用js语法中的if/for语句就能实现了。v-model属于prop + input事件语法糖,也可以使用babel插件自动实现。
2.4 slot插槽
slot直接通过
this.$slots
对象拿到,scopedSlot通过this.$scopedSlots
对象拿到($scopedSlots每项是待调用函数)。2.5 组件
不需要注册,直接使用
2.6 functional函数
2.7 v-model
安装
@vue/babel-sugar-v-model
babel插件后即可自动解析v-model,官方更推荐使用vModel
或者value + onInput事件
。参考文章