除了可通过模板创建HTML之外,Vue还提供了渲染函数和JSX,前者的编码自由度很高,后者对于开发过React的人来说会很熟悉。注意,Vue的模板最终都会被编译成渲染函数。

一、渲染函数

  虽然在大部分场景中,都会选择直观而清晰的模板,但遇到一些复杂的场景时,就不得不使用渲染函数render()了。

1)render()

  假设有一个page组件,它会根据外部传入的type特性,有选择的渲染,其模板如下所示。

<script type="text/x-template" id="template">
<h1 v-if="type == 1">
<slot></slot>
</h1>
<h2 v-else-if="type == 2">
<slot></slot>
</h2>
<h3 v-else-if="type == 3">
<slot></slot>
</h3>
</script>
<script>
Vue.component("page", {
template: '#template',
props: ["type"]
});
</script>

  在模板中,充斥着冗余的<slot>元素,并且如果要增加分支,那么还得修改模板,即插入新的条件指令、标题元素和插槽。显然,在这个场景中不适合用模板,接下来替换成render()函数,代码不仅简洁而且更易维护,如下所示。

Vue.component("page", {
render: function (createElement) {
return createElement(
"h" + this.type,
this.$slots.default
);
},
props: ["type"]
});

  render()函数能接收一个createElement()方法,并返回一个VNode。Vue通过虚拟DOM来高性能的变更真实DOM,而VNode是虚拟节点(Virtual Node)的简写。实例属性$slots是一个对象,其键是插槽的名称,可访问分发给插槽的内容,代码中的default是指默认插槽。

  注意,若render()函数存在,那么Vue就不会编译template选项中的模板和从el选项所挂载的元素中提取出的模板,即不会将它们转换成渲染函数。

2)createElement()

  该方法可接收3个参数:标签名称、数据对象和虚拟子节点。除了标签名称必传之外,其余两个参数都是可选的,接下来会对这3个参数进行逐一讲解。

  标签名称既可以是一段字符串,也可以是一个返回字符串的函数。并且由于render()函数可以访问this,因此标签名称还可以是data选项的属性、计算属性等,如下所示。

Vue.component("btn", {
render: function (createElement) {
return createElement(
this.tag
);
},
data: function() {
return { tag: "button" }
}
});

  数据对象是一个配置信息集合,包含了组件所需的属性以及DOM元素的特性和属性,例如样式、插槽、ref、自定义指令、事件和props等,下面只列出了数据对象的部分字段。

Vue.component("btn", {
render: function(createElement) {
return createElement(this.tag, {
style: { color: "red" }, //与v-bind:style的功能相同
attrs: { id: "btn" }, //DOM元素特性
domProps: { innerHTML: "提交" }, //DOM元素属性
on: { click: this.handler } //事件监听器
});
},
methods: {
handler: function() {
console.log("click");
}
}
});

  Vue还为on选项中的事件提供了与.passive、.capture和.once三个修饰符相对应的前缀,如下所示。

on: {
"&click": this.handler, //.passive
"!click": this.handler, //.capture
"~click": this.handler //.once
}

  虚拟子节点既可以是字符串,也可以是数组,如下所示。注意,如果需要省略数据对象,那么可直接将虚拟子节点作为第二个参数传入。

Vue.component("c-article", {
render: function (createElement) {
return createElement(
"div",
["标题", createElement("h2", "副标题")]
);
}
});

  官方规定组件树中的所有VNode必须要唯一,虽然像下面这样重复引用同一个VNode是不合法的,但是在渲染时并不会报错,仍然能呈现内容。

Vue.component("c-article", {
render: function(createElement) {
var h1 = createElement("h1", "标题");
return createElement(
"div",
[h1, h1]
);
}
});

二、JSX

  如果要在Vue中使用JSX语法,那么需要先安装一个Babel插件,安装命令如下所示。

npm install @vue/babel-preset-jsx --save-dev

  在安装完之后,就可在配置文件babel.config.js中对其进行配置,如下所示。

module.exports = {
presets: ["@vue/babel-preset-jsx"]
};

  经过这一系列的操作后,就能以JSX语法来创建模板,如下所示,为按钮注册了点击事件。注意,render()函数的h参数是createElement的别名。

Vue.component("btn", {
render: function(h) {
return (<button vOn:click={this.handler}>ok</button>);
},
methods: {
handler: function() {
console.log("click");
}
}
});

  假设上面的代码保存在default.js文件中,并且当前处在该文件的目录中,执行下面这条编译命令,会将编译后的代码保存到当前目录的dist.js文件中。

npx babel default.js --out-file dist.js

  dist.js文件中的代码如下所示,那段JSX代码自动转换成了createElement()方法。

Vue.component("btn", {
render: function (h) {
return h("button", {
"on": {
"click": this.handler
}
}, ["ok"]);
},
methods: {
handler: function () {
console.log("click");
}
}
});

Vue躬行记(7)——渲染函数和JSX的更多相关文章

  1. Vue躬行记(1)——数据绑定

    Vue.js的核心是通过基于HTML的模板语法声明式地将数据绑定到DOM结构中,即通过模板将数据显示在页面上,如下所示. <div id="container">{{c ...

  2. Vue躬行记(3)——样式和表单

    Vue对DOM元素的class和style两个特性做了专门的增强,即对CSS类和内联样式做了一层封装,通过v-bind指令来处理它们,而接收的表达式既可以是简单的字符串.对象或数组,也可以是复杂的计算 ...

  3. Vue躬行记(2)——指令

    Vue不仅内置了各类指令,包括条件渲染.事件处理等,还能注册自定义指令. 一.条件渲染 条件渲染的指令包括v-if.v-else.v-else-if和v-show. 1)v-if 该指令的功能和条件语 ...

  4. Vue躬行记(4)——组件

    组件是可复用的Vue实例,拥有属于自己的数据.模板.脚本和样式,可避免繁重的重复性开发.由于组件都是独立的,因此其内部代码不会影响其它组件,但可以包含其它组件,并且相互之间还能通信. 一.注册 在使用 ...

  5. Vue躬行记(8)——Vue Router

    虽然Vue.js未提供路由功能,但是官方推出了Vue Router(即vue-router库),以插件的形式支持.它与Vue.js深度集成,可快速的创建单页应用(Single Page Applica ...

  6. Vue躬行记(5)——组件通信

    组件之间除了保持独立之外,还需要相互通信,本章将介绍几种通信的方式. 一.直接访问 Vue提供了三个实例属性,可直接访问父组件.子组件和根实例,如下所列. (1)$parent:父组件. (2)$ro ...

  7. Vue躬行记(6)——内容分发

    Vue提供了一种内容分发技术,可将父组件中的内容传递给子组件的模板,实现方式参照了Web组件规范草案. 一.插槽 Vue内置了一个<slot>元素,能作为插槽(slot)存在,而插槽内可包 ...

  8. Vue躬行记(9)——Vuex

    Vuex是一个专为Vue.js设计的状态管理库,适用于多组件共享状态的场景.Vuex能集中式的存储和维护所有组件的状态,并提供相关规则保证状态的独立性.正确性和可预测性,这不仅让调试变得可追踪,还让代 ...

  9. ES6躬行记(1)——let和const

    古语云:“纸上得来终觉浅,绝知此事要躬行”.的确,不管看了多少本书,如果自己不实践,那么就很难领会其中的精髓.自己研读过许多ES6相关的书籍和资料,平时工作中也会用到,但在用到时经常需要上搜索引擎中查 ...

随机推荐

  1. Unknown column 'user_id' in 'where clause'

    mapper位置报错Unknown column 'user_id' in 'where clause' 可能是数据库中的字段user_id包含空格

  2. Java 从入门到进阶之路(八)

    在之前的文章我们介绍了一下 Java 中的重载,接下来我们看一下 Java 中的构造方法. 我们之前说过,我们在定义一个变量的时候,java 会为我们提供一个默认的值,字符串为 null,数字为 0. ...

  3. Windows 10 删除C盘的用户,恢复技巧

    起因 入域不成功,然后强制删除了C盘 Users里面 账户 然后再进行入域的时候就入域不成功了,如果再进行登录就会提示 无法登录到你的账户 通常可以通过从你的账户注销,然后重新登录解决此问题 如果不立 ...

  4. CSS样式手册

    字体属性:(font) 大小 {font-size: x-large;}(特大) xx-small;(极小) 一般中文用不到,只要用数值就可以,单位:PX.PD 样式 {font-style: obl ...

  5. markdown公式转为知乎格式

        在知乎中写技术类文章,经常会用到markdown知乎文章可以导入markdown格式,但是不支持Latex公式.知乎大神提供了替代方案: https://zhuanlan.zhihu.com/ ...

  6. 古剑奇谭三已取消该页导航,B站版本无法登陆

    最近登陆古剑三突然出现这个问题 怎么重开也无法登陆 最后发现是Ie设置问题 解决方法 点中间这个圆形图标打开 小娜 搜索“ie” 点击打开ie之后点右上角的小齿轮 选择“internet选项” 连接- ...

  7. 算法学习之剑指offer(十二)

    一 题目描述 请设计一个函数,用来判断在一个矩阵中是否存在一条包含某字符串所有字符的路径.路径可以从矩阵中的任意一个格子开始,每一步可以在矩阵中向左,向右,向上,向下移动一个格子.如果一条路径经过了矩 ...

  8. cobalt strike批量发送钓鱼邮件

    0×01 利用Cobalt strike生成木马 这里我们生成木马可以用cs带的HTA.OFFICE宏.word宏来使目标上线cs,这里以word宏病毒为例子. 首先我们需要制作一个word宏病毒来进 ...

  9. Linux常用高级命令

    目录 linux命令是对Linux系统进行管理的命令.对于Linux系统来说,无论是中央处理器.内存.磁盘驱动器.键盘.鼠标,还是用户等都是文件,Linux系统管理的命令是它正常运行的核心,与之前的D ...

  10. [NOIp2011] luogu P1313 计算系数

    继续水博客,待会回去上术学. 题目描述 给定一个多项式 (by+ax)k(by+ax)^k(by+ax)k ,请求出多项式展开后 xn×ymx^n \times y^mxn×ym 项的系数. Solu ...