vue的jsx写法记录

[toc]html

经过本文, 你能够学到一些 vuejsx的语法。

vue更加推荐使用模板开发组件,可是在一些基础组件开发中,为了灵活实现,不可避免须要使用一些jsx语法,而官方对这方面的文档特别少, 本文记录一些本人在开发过程当中使用jsx的经验和思考。vue

总体上来看,因为vuecreateElementreactcreateElement有区别,致使jsx的写法也有区别.react

data写法

jsx本质上是createElement的语法糖,最终会被编译器转为createElement函数.当在jsx的标签中使用{ ...obj }时, obj将会编译为createElement的第二个参数.git

vuecreateElement跟react的createElement函数第二个参数意义是不同的.在vue中,第二个参数是 data对象, 而react第二个参数是props。因此本人将这种方式称为data写法github

如在vue中须要设置动态属性时:编程

const props={
  name: 'joyer',
},

<my-button {...{
  props:props,
}}></my-button>

当不知道模板中某个vue语法怎么用jsx中实现时,能够先转换为createElementdata对象,而后使用{...data}写在jsx标签上(本文重点).api

如官方推荐原生dom属性的jsx写法:数组

<button domPropsType="submit"><button>

采用data写法为:babel

<button { ...{
  domProps: {
    type: 'submit',
  }, 
}}><button>

该方式不够优雅,若是官方有更加优雅的语法糖,推荐使用官方推荐。若是某个语法,官方没有案例,该方式就能够做为最终选择。 而且经过这种方式,createElement中全部的特性均可以用于jsx的开发了。dom

v-model的写法

官网中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()}/>

v-for

模板中的写法:

<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" />

一些编辑器会提示语法错误(由于reactjsx不容许这样写),推荐使用下面的写法

<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-itemel-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>);
}

经过设置attrshigh-button接收到的全部标签设置传递给my-button中。若是不这样作, 那么my-button中将接收不到任何属性设置,由于只传递props,在high-button组件中对于没有匹配high-buttonprops声明的标签属性都会被丢弃。

slot写法

默认插槽模板写法:

<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
    }
  }
})

要知道,vuecreateElement函数的第一个参数能够是一个 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官方编辑器中尝试

能够在babel官方提供的编辑器jsx尝试代码,不过须要记得在左边最下角添加babel=plugin-transform-vue-jsx插件:

添加vue-jsx插件

相关文章
相关标签/搜索