你有没有用过Vue.js的渲染函数和JSX?

前言

真的,一定会有一些小伙伴直到完整了几个项目都做完了,却从未用过渲染函数和JSX,所以一旦遇到需要复杂处理的模板元素,其中就会夹杂大量的v-ifv-elsev-else-if……以及各种三元操作符。是时候了解一下渲染函数和JSX了,即便Vue 3在几个月后就要问世,学习一下JSX绝对没有坏处,也不会过时,JSX是React一直推崇的描述模板的方法,算是业界通用的一项技术。

官网

https://cn.vuejs.org/v2/guide/render-function.html

为什么有官网介绍,还要来个教程

官网教程是基于运行时版本的Vue.js,按照全局组件的模式为例,而我们通常是使用完整版的Vue.js,且使用单文件组件,所以本文以单文件组件为例说明。

渲染函数和JSX适用场景

当你模板中存在大量条件判断时,就适用渲染函数和JSX。比如在class中、style中、文本中、属性中存在条件判断时,会将模板搞得很冗长,而且不容易阅读,这时候适用渲染函数和JSX会让代码变得很清晰。

Hello World

  1. 在components文件夹创建HelloWorld.vue,内容是:
export default {
  props: {
    msg: {
      type: String,
      default: ""
    },
    type: {
      type: String,
      default: ""
    }
  },
  render(createElement) {
    return createElement("button", {
      class: {
        btn: true,
        success: this.type === "success",
        danger: this.type === "danger"
      },
      domProps: {
        innerText: this.msg || "默认"
      },
      on: {
        click: this.handleClick
      }
    });
  },
  methods: {
    handleClick() {
      console.log(11);
    }
  }
};
<style scoped lang="scss">
.success {
  color: green;
}
.danger {
  color: red;
}
</style>
  1. 父组件按照常规的子组件调用方法调用即可:
<hello-world type="success" msg="abc">xyz</hello-world>

JS代码从略。

  1. 效果是渲染出一段DOM:<button data-v-469af010="" class="btn success">abc</button>

  2. 讲一下HelloWorld.vue。其中props和methods不解释,只说render。render负责渲染一段DOM,前提是要给它传入VDOM,而createElement就是负责构建VDOM,我们只需要关心createElement的参数就行了。这里官网都有介绍,简单说:

    第一个参数负责声明顶级元素的标签名,也就是说,标签名到底是button还是div还是h2还是span还是其他什么。

    第二个参数就是对顶级元素的所有修饰,官网都有解释,这里只列一下:

    • class
    • style
    • attrs
    • props
    • domProps
    • on
    • nativeOn
    • directives
    • scopedSlots
    • slot
    • key
    • ref
    • refInFor

    第三个参数是可选的,是一个数组,每一个数组元素也就是一个子元素,如果是文本,直接写字符串,如果是元素,就要继续写create('标签名', {修饰对象}),这样一层一层写下去。从实践说,如果层数太多,反而不如单文件的<template>标签直观,所以尽量保持2层即可。

循环创建元素

使用v-for可以在模板中循环创建元素,在createElement里当然也可以。

官方举了一个例子,但实践中一般用不到,因为实践中往往将一个数组映射成一系列元素:

官网例子:

render: function (createElement) {
  return createElement('div',
    Array.apply(null, { length: 20 }).map(function () {
      return createElement('p', 'hi')
    })
  )
}

更贴近实践的例子,dataList靠父组件传入,然后利用map返回一系列相似的子元素:

render: function (createElement) {
  return createElement('div',
    this.dataList.map(function () {
      return createElement('p', {
        // ...
      })
    })
  )
}

如何对应<template>里的v-for/v-model/v-if/v-else指令

如何对应v-for上面已经说了,就用map就可以了。

如何对应v-model略复杂,官网有专门介绍,不说了。

v-if这类条件指令,用JS的原生if...else...即可。这里不介绍用法,但是强调一点,这就是渲染函数最有优势的地方。比如,一套条件语句如下所示,想象一下,如果将这套判断逻辑实现到<template>标签里,会是多么的恐怖,多么难以理解,某个else是哪个if的else?看的眼花。而在JS中,if...else...就会直观得多。

if () {
  if () {
    if () {
    }
  } else {
  }
} else {
}

事件和插槽

很容易,阅读官网即可。

JSX

终于到JSX了,官网的介绍比较简单。JSX说白了就是将<template>里的标签直接写到JS里,这本身在JS里是行不通的,只能依靠插件来编译。比如官方的示例:

  render: function (h) {
    return (
      <AnchoredHeading level={1}>
        <span>Hello</span> world!
      </AnchoredHeading>
    )
  }

在JS里用括号包裹一段像DOM的东西,而且还不是字符串,这在JS里是绝对行不通的,因此想用JSX就必须用插件编译成正常的模板,https://github.com/vuejs/jsx有介绍。

注意几点:

  1. JSX的一个原则是从简、小片段原则,所以不要将计算过程写入JSX中,如果写入的话,又跟<template>一样了,比如你要计算class的值,你需要在return之前,先声明一个变量比如叫classVal,然后通过一系列的JS运算算出classVal的值,然后JSX里面只能写上像上文那样比较简单的内容,比如<button class={classVal}></button>

  2. JSX默认不支持v-if等v-*指令,只支持非常少的几个指令,需要再额外装插件来弥补。

  3. JSX支持三元操作符,在{}里使用即可。

总之,vue没有主打JSX,而且JSX本身也比较弱,至少在Vue 2.0里,不是良药。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容

  • Android 自定义View的各种姿势1 Activity的显示之ViewRootImpl详解 Activity...
    passiontim阅读 173,161评论 25 708
  • 遇到南墙有的人迷途知返,有的人却固步自封不知悔改,不是所有人都有义务施舍给你同情,该自己走的路还是得自己走。解铃还...
    SEVEN_24阅读 435评论 0 2
  • 从我受教育以来,我的角色一直是不温不火,态度认真,资质平庸,学业中上的学生。我从来没有质疑过我所受的教育,也没有质...
    活动策划女青年阅读 600评论 0 6
  • 如何获得新时代的幸福? 所谓新幸福,就是摆脱金钱、时间、场所等外物的束缚,让我们重新拥有自由。 1.从“厉行节约”...
    牛奶tiger阅读 178评论 0 0
  • 毕业答辩的deadline临近,大家的答辩幻灯片做的怎样了? 相信大家制作幻灯片的第一步是找到一个自己喜欢的模版,...
    曹奇_edfa阅读 938评论 0 1