Skip to content

jsx 语法

jsx 与 渲染函数

https://github.com/vuejs/babel-plugin-transform-vue-jsx

jsx 就是一种语法糖,通过 babel 编译后就是渲染函数,以下两段代码等价。

jsx 写法

jsx
render (h) {
  return (
    <div
      id="foo"
      propsOnCustomEvent={this.customEventHandler}
      domPropsInnerHTML="bar"
      onClick={this.clickHandler}
      nativeOnClick={this.nativeClickHandler}
      class={{ foo: true, bar: false }}
      style={{ color: 'red', fontSize: '14px' }}
      key="key"
      ref="ref"
      refInFor
      slot="slot">
    </div>
  )
}

渲染函数写法

js
render (h) {
  return h('div', {
    props: { onCustomEvent: this.customEventHandler },
    attrs: { id: 'foo' },
    domProps: { innerHTML: 'bar' },
    on: { click: this.clickHandler },
    nativeOn: { click: this.nativeClickHandler },
    class: { foo: true, bar: false },
    style: { color: 'red', fontSize: '14px' },
    key: 'key',
    ref: 'ref',
    refInFor: true,
    slot: 'slot'
  })
}

jsx 相较于渲染函数对 props、domProps、on、native 配置项做平铺处理,使用对应前缀+属性名作为属性传入。

指令

v-show 是唯一在 jsx 中写法支持的指令(babel6 以下)

jsx
<div v-show={true}>babel6 以下 jsx 唯一支持的指令</div>

v-if 使用三元运算符实现

往往认为 v-ifv-else 成对出现,所以使用三元运算符。

jsx
<div>{true ? <span>三元运算符</span> : <span>不展示</span>}</div>

v-for 使用数组 + map 方法实现

jsx
<div>
  {[1, 2, 3].map(item => (
    <div>{item}</div>
  ))}
</div>

自定义指令

用 jsx 写自定义指令确实有些麻烦,完全就是渲染函数的写法。

jsx
const directives = [{ name: 'demo', value: 123, modifiers: { abc: true } }]
return <div {...{ directives }}></div>

// 为什么这样就不行
return <div directives={directives}></div>

以上两段端绑定指令代码应该是一致的,结果却第二种绑定方式不行。其原因就是 directives 被解析到 attrs 属性中了,而其它的渲染函数选项(props,on 等)会正常解析,或许这算是一种 bug?

js
{
  attrs: {
    directives: [{ name: 'demo', value: 123, modifiers: { abc: true } }]
  }
}

babel7+ 新增

https://github.com/vuejs/jsx-vue2

新增对渲染函数参数支持

函数式组件 - 渲染函数

js
render(h, ctx) {
  return h('div', ctx.data, ctx.children)
}

重点关注 ctx.data,该对象有两个重要属性 attrs 和 on,分别代表传入属性与事件。 jsx 支持渲染函数传参方式后,可以写成下面这种形式,并且两种写法等价。

jsx
render(h, ctx) {
  return <div {...ctx.data}></div>
}

render(h, { data }) {
  return <div attrs={data.attrs} on={data.on}></div>
}

jsx 函数式组件可直接写成函数

jsx
// 默认导出
export default ({ props }) => <p>hello {props.message}</p>

// 变量 - 一定使用大驼峰
const HelloWorld = ({ props }) => <p>hello {props.message}</p>

v-model 指令

jsx
<input vModel={this.value}></input>

v-on 指令

jsx
<input vOn:click={this.newTodoText} />
<input vOn:click={[this.newTodoText]} /> // 事件数组,逐个执行

指令修饰符使用下划线连接。

jsx
<input vModel_trim={this.value}></input>
<input vOn:click_stop_prevent={this.newTodoText} />

<input vOn:click_stop_prevent={[this.newTodoText]} /> 

注意

事件使用修饰符后,绑定值不可事件数组。

v-html 指令

实质就是 DOM 属性 innerHTML 赋值。

jsx
<p domPropsInnerHTML={html} />

其它

组件

使用组件引入即可,不用注册。

jsx
import MyComponent from './my-component'

export default {
  render() {
    return <MyComponent>hello</MyComponent>
  }
}

插槽

jsx
<MyComponent>
  <header slot="header">header</header>
  <footer slot="footer">footer</footer>
</MyComponent>

作用域插槽

jsx
const scopedSlots = {
  header: () => <header>header</header>,
  footer: () => <footer>footer</footer>
}

<MyComponent scopedSlots={scopedSlots} />

注意

当使用了作用域插槽时,默认内容应该作为默认作用域插槽使用,否则有意想不到的 bug。

jsx
const scopedSlots = {
  default: () => 默认文字,
  header: () => <header>header</header>,
  footer: () => <footer>footer</footer>
}

<MyComponent scopedSlots={scopedSlots}></MyComponent>