[toc]html
经过本文, 你能够学到一些vue
中jsx
的语法。
vue
更加推荐使用模板开发组件,可是在一些基础组件开发中,为了灵活实现,不可避免须要使用一些jsx
语法,而官方对这方面的文档特别少, 本文记录一些本人在开发过程当中使用jsx
的经验和思考。vue
总体上来看,因为vue
的createElement
跟react
的createElement
有区别,致使jsx
的写法也有区别.react
jsx本质上是createElement
的语法糖,最终会被编译器转为createElement
函数.当在jsx
的标签中使用{ ...obj }
时, obj将会编译为createElement
的第二个参数.git
vue
的createElement跟react的createElement函数第二个参数意义是不同的.在vue
中,第二个参数是 data对象, 而react
第二个参数是props
。因此本人将这种方式称为data写法
。github
如在vue
中须要设置动态属性时:编程
const props={ name: 'joyer', }, <my-button {...{ props:props, }}></my-button>
当不知道模板中某个vue
语法怎么用jsx
中实现时,能够先转换为createElement
的data
对象,而后使用{...data}
写在jsx
标签上(本文重点).api
如官方推荐原生dom
属性的jsx
写法:数组
<button domPropsType="submit"><button>
采用data
写法为:babel
<button { ...{ domProps: { type: 'submit', }, }}><button>
该方式不够优雅,若是官方有更加优雅的语法糖,推荐使用官方推荐。若是某个语法,官方没有案例,该方式就能够做为最终选择。 而且经过这种方式,createElement
中全部的特性均可以用于jsx
的开发了。dom
官网中v-model写法不可行。
模板中写法为:
<el-input v-model.trim="inputValue"/>
jsx
写法须要为:
<el-input vModel_trim={inputValue}/> // 或者使用 <el-input value={this.inputValue} on-input={val => this.inputValue = val.trim()}/>
模板中的写法:
<el-tag v-for="(item, index) in content" :key="index" type="success" > {{item.name}} </el-tag>
jsx
的写法:
{ this.content.map((item, index) = >{ return (<el-tag key={ index } type="success">{ item.name }</el-tag>); }) }
官方的写法
<input vOn:click_stop_prevent="newTodoText" />
一些编辑器会提示语法错误(由于react
的jsx
不容许这样写),推荐使用下面的写法
<input nativeOn-keyup={arg => arg.keyCode === 13 && this.fetch()} on-click={event => {event.stopPropagation();event.preventDefault();this.click()} }/>
修饰符须要本身在代码中实现。或者可使用修饰符简写,对照官网的语法, jsx
写法为:
<input {...{ on: { '!click': () => this.doThisInCapturingMode, '~keyup': () => this.doThisOnce, '~!mouseover': () => this.doThisOnceInCapturingMode } }} />
事件处理都采用了箭头函数, 跟react
同样, 须要处理this
绑定问题,可使用bind
绑定,
`on-click={this.click.bind(this, args) }`
不能直接赋值函数on-click={this.click}
。
v-on="$listeners"
和v-bind="$attrs"
在高阶组件中, 通常都会使用v-on="$listeners"
和v-bind="$attrs"
,但在官方文档没有说明jsx
如何实现,只有createElement
中说明了实现:
return createElement('div', { props: { ...$attrs, otherProp: value, }, on: { ...$listeners, click() { }, } },this.$slots.default])
参照data写法
, jsx
实现为:
const data = { props: { ...$attrs, otherProp: value, }, on: { ...$listeners, click() { }, } } <button { ...data }><button>
对于$attrs
和$listeners
能够有更加灵活的用法。如要实现elemet-ui
中一个能够快速布局el-form-item
高阶组件,将el-form-item
跟el-col
的结合:
render(h) { // 拆分出做用于col和form-item上的属性 const colAttrs = {}; const itemAtts = {}; this.$attrs.forEach((attrName) => { // 这里使用了lodash if (_.startsWith(attrName, `col-`)) { colAttrs[attrName.replace(`col-`, '')] = this.$attrs[attrName]; return; } itemAtts[attrName] = this.$attrs[attrName]; }); return (<el-col { ...{ props: this.inputAttrs, } }> </el-col>); }
该高阶组件能够传递两种类型的属性, 带col-
开头的属性,做用于el-col
上面, 其余属性做用于el-form-item
组件上。
若是须要标签属性透传,将当前组件的全部attrs
传递给内部组件(内部组件也用v-bind="$attrs"
),还需设置attrs
值。
如高阶组件my-button
:
<el-button v-bind="$attrs" type="primary"> <slot></slot> </el-button>
高阶组件high-button
:
render(h) { return (<my-button { ...{ props: this.attrs, attrs: this.$attrs, } }><my-button>); }
经过设置attrs
将high-button
接收到的全部标签设置传递给my-button
中。若是不这样作, 那么my-button
中将接收不到任何属性设置,由于只传递props
,在high-button
组件中对于没有匹配high-button
的props
声明的标签属性都会被丢弃。
默认插槽模板写法:
<button> <slot></slot> </button>
jsx
的写法:
<button> {this.$scopedSlots.default()} </button>
具名插槽模板写法:
<button> <slot name="before"></slot> <slot ></slot> </button>
jsx
写法:
let before = ''; if (this.$scopedSlots.before) { before = this.$scopedSlots.before(props => props.text); } return (<button> { before } {this.$scopedSlots.default()} </button>)
做用域插槽模板写法:
<slot :isAdvancedPanelShow="isAdvancedPanelShow"></slot>
jsx
写法:
{this.$scopedSlots.default({ isAdvancedPanelShow: this.isAdvancedPanelShow })}
还记得官网怎么介绍 createElement
获取js
的彻底编程能力吗? 举了一个根据不一样的等级使用不一样标题的案例:
Vue.component('anchored-heading', { render: function (createElement) { return createElement( 'h' + this.level, // 标签名称 this.$slots.default // 子节点数组 ) }, props: { level: { type: Number, required: true } } })
这个案例经过jsx
的写法为:
Vue.component('anchored-heading', { render: function (h) { const TagName = 'h' + this.level; return <TagName>{ this.$slots.default(this.props) }</TagName> }, props: { level: { type: Number, required: true } } })
要知道,vue
的createElement
函数的第一个参数能够是一个 HTML 标签名、组件选项对象,或者resolve
了上述任何一种的一个async
函数。
在实际开发中, 碰到一种场景, 有组件CompA
, CompB
, CompC
。若是是a
状况,须要在当前组件按照CompA
, CompB
, CompC
顺序展现, 若是是否是a
状况, 则经过CompC
, CompB
, CompA
来展现。jsx
写法为:
render(h) { // 假设组件A是须要特殊设置一些属性的 const compA = (<CompA name="joyer">hellow word</CompA>) const content = this.status === 'a' ? [compA, CompB, CompC] : [CompC, CompB, compA]; return (<div>{content}</div>) }
这里末尾也能够这样写:
return (<div>{...content}</div>)
但在有些编辑器会报错,由于在react
不容许这样写:
Spread children are not supported in React.
能够在babel官方提供的编辑器中jsx
尝试代码,不过须要记得在左边最下角添加babel=plugin-transform-vue-jsx
插件: