首页 > 编程笔记 > JavaScript笔记
Vue render渲染函数和JSX的用法
通常情况下,Vue.js 推荐使用 template 定义视图内容(html),然而有时使用渲染函数生成视图内容要方便得多。
用 template 定义一个子组件,用
在上面的案例中,createElement('h'+this.level,this.$slots.default)执行的结果,也是创建一个 h 的节点对象,只是这个对象不是原汁原味的 DOM 节点,而是 Vue.js 中的节点描述对象,包含所有描述信息,以便 Vue.js 将其渲染到页面。这种节点,通常称为虚拟节点(Virtual Node),简称为 VNode。虚拟 DOM 是在 Vue.js 里面对所有 Vue.js 组件数的总称。
关于第 2 个参数,经常又称为数据对象,里面包含的是组件属性对象对应的数据,代码如下:
特别要注意的是,在 Vue.js 组件树中,VNode 是唯一的。如下代码是不正确的,因为在渲染出来的对象里面有两个一样的 VNode 对象,代码如下:
用 template 定义一个子组件,用
h n
显示插槽里面的内容,代码如下:<!-- 定义 Vue.js 的视图 --> <div id="app"> <sub-component :level="1"> Hello </sub-component> <sub-component :level="2"> Hello </sub-component> <sub-component :level="4"> Hello </sub-component> </div> <script type="text/JavaScript"> const SubComponent = { // template定义视图 template: '<div> <h1 v-if="level === 1"><slot></slot></h1> <h2 v-else-if="level === 2"><slot></slot></h2> <h3 v-else><slot></slot></h3> </div>', props: { level: { type: Number, required: true } } }; // 创建 Vue.js 对象 const vm = new Vue({ el: "#app", components: { SubComponent } }); </script>在 template 里面,用 v-if 根据 level 的不同值,渲染不同的 h,如果代码量太大,则可改成渲染函数生成子组件的 html,代码如下:
<!-- 定义 Vue.js 的视图 --> <div id="app"> <sub-component :level="1"> Hello </sub-component> <sub-component :level="2"> Hello </sub-component> <sub-component :level="4"> Hello </sub-component> </div> <script type="text/JavaScript"> const SubComponent = { // 用render()函数渲染视图的HTML render: function(createElement) { return createElement( 'h' + this.level, this.$slots.default ) }, props: { level: { type: Number, required: true } } } // 创建Vue.js对象 const vm = new Vue({ el: "#app", components: { SubComponent } }) </script>这种情况下,渲染函数的使用要比 template 实现方便很多。
虚拟DOM
浏览器接收到 html 页面后,会先将页面内容解析成树形结构,保存在内存中,再显示到页面上。每个元素是一个独立的节点对象,文本也是。在上面的案例中,createElement('h'+this.level,this.$slots.default)执行的结果,也是创建一个 h 的节点对象,只是这个对象不是原汁原味的 DOM 节点,而是 Vue.js 中的节点描述对象,包含所有描述信息,以便 Vue.js 将其渲染到页面。这种节点,通常称为虚拟节点(Virtual Node),简称为 VNode。虚拟 DOM 是在 Vue.js 里面对所有 Vue.js 组件数的总称。
createElement参数
createElement 的语法是:createElement({String|Object|function},{Object},{String, Array})带 3 个参数:
- 第 1 个参数可以是 String|Object|Function 类型,必选,可以是 html 元素名称、组件选项对象或者分解成 String 或 Object 的任何一种异步函数。
- 第 2 个参数是 Object 类型,可选,同模板中的属性对象对应的数据对象。
- 第 3 个参数可以是 String|Array 类型,可选,可以是虚拟节点的子文本节点,或者其他子虚拟节点。
关于第 2 个参数,经常又称为数据对象,里面包含的是组件属性对象对应的数据,代码如下:
// 与 v-bind:class 的 API 相同 // 接收一个字符串、对象或字符串和对象组成的数组 'class': { foo: true, bar: false }, // 与 v-bind:style 的 API 相同 // 接收一个字符串、对象, 或对象组成的数组 style: { color: 'red', fontSize: '14px' }, // 普通的 HTML attribute attrs: { id: "foo" }, // 组件prop props: { myProp: 'bar' }, // DOM property domProps: { innerHTML: 'baz' }, // 事件监听器在 on 内, // 但不再支持如 v-on:keyup.enter 这样的修饰器 // 需要在处理函数中手动检查 keyCode on: { click: this.clickHandler }, // 仅用于组件,用于监听原生事件,而不是在组件内部使用 // vm.$emit 触发的事件 nativeOn: { click: this.nativeClickHandler }, // 自定义指令. 注意,无法对 binding 中的 oldValue 赋值 // 因为 Vue.js 已经自动进行了同步 directives: [ { name: 'my-custom-directive', value: '2', expression: '1 + 1', arg: "foo", modifiers: { bar: true } }], // 作用域插槽的格式为 // ( name: props => VNode [ Array<VNode> } scopedSlots: { default: props => createElement('span', props.text) }, // 如果组件是其他组件的子组件,则需为插槽指定名称 slot: 'name-of-slot' // 其他特殊顶层 property key: 'myKey', ref: 'myRef', // 如果在渲染函数中给多个元素应用了相同的 ref 名 // 则 $refs.myRef 会变成一个数组 refInFor: true }
特别要注意的是,在 Vue.js 组件树中,VNode 是唯一的。如下代码是不正确的,因为在渲染出来的对象里面有两个一样的 VNode 对象,代码如下:
render: function (createElement) { var myParagraphVNode = createElement('p', 'hi') return createElement('div', // 错误,重复的VNode myParagraphVNode, myParagraphVNode ) }