9.1 virtual DOM
Virtual DOM 并不是真正意义上的DOM,而是一个轻量级的JavaScript对象,在状态发生变化时,Virtual DOM会进行Diff运算,只需要更新被替换的DOM,而不会全部重绘
virtual DOM运行过程
Object---->Render(生成虚拟节点)----->createElement(h)(基于虚拟节点创建DOM节点)----->diff(状态更新后,进行对比,生成补丁对象)—>patch(遍历补丁对象,更新DOM节点)
vnode类型
- vnode
- EmptyVNode : 没有内容的注释节点
- TextVNode : 文本节点
- ElementVNode :普通元素节点
- CloneVNode : 克隆节点
- ComponentVNode : 组件节点
9.2 Render函数
9.3 createElement用法(Render函数通过createElement来创建virtual DOM)
createElement有三个参数
-
一个HTML标签,组件选项,或一个函数(必须return一个)
-
一个对应属性的数据对象(可选)
{ //和v-bind:class一样的API 'class': { foo:true, bar:false } //和v-bind:sytle一样的API style: { color:'red', fontSize:14px, } //正常的HTML特性 attrs:{ id:foo } //组件props props:{ myProp:'bar' } //DOM属性 domProps:{ innerHTML:'baz' } //自定义事件监听器on,不支持v-on:keyup.enter的修饰符 //需要手动配置keyCode on:{ click:this.clickHandler } }
-
子节点(可选)
9.3.2 Render函数约束
- 如果Vnode是组件或含有组件的slot,那么VNode必须唯一(现版本经测试,不唯一,也可以实现多次渲染)
-
VNode是组件:
var child = { render: function (createElement) { return createElement('p', 'text'); } } Vue.component('ele', { render: function (createElement) { var childNode = createElement(child); return createElement('div', [ childNode, childNode ] ); } });
-
VNode是含有组件的slot
<ele> <div> <child></child> </div> </ele> Vue.component('child', { render: function (createElement) { return createElement('p', 'text') } }); Vue.component('ele', { render: function (createElement) { return createElement('div', [ this.$slots.default, this.$slots.default ]); } })
-
正确方式
var child = { render: function (createElement) { return createElement('p', 'text'); } } Vue.component('ele', { render: function (createElement) { return createElement('div', Array.apply(null, { length: 5 }).map(function () { return createElement(child) }) ); } })
-
9.3.3 利用javascript代替模板功能
-
v-if和v-else
<div id="app"> <ele :show="show"></ele> <button @click="show = !show">切换</button> </div> Vue.component('ele', { render(createElement) { if (this.show) { return createElement('p', 'show的值为True') } else { return createElement('p', 'show的值为False') } }, props: { show: { type: Boolean, default: false } } }) var app = new Vue({ el: '#app', data: { show: false } })
-
v-for
<div id="app"> <my-list :list="list"></my-list> </div> Vue.component('my-list', { render(createElement) { var nodes = []; for (let i = 0; i < this.list.length; i++) { nodes.push(createElement('p', this.list[i])) } return createElement('div', nodes); }, props: { list: { type: Array } } }) var app = new Vue({ el: '#app', data: { list: [ '《Vue.js实战》', '《SpringBoot实战》', '《Git高手之路》' ] } })
-
v-model
Vue.component('ele', { render(createElement) { var _this = this; return createElement( 'div', [ createElement('input', { domProps: { value: _this.value }, on: { input: function (event) { _this.value = event.target.value } } }), createElement('p', 'value:' + this.value) ] ) }, data() { return { value: '' } }, }) var app = new Vue({ el: '#app', })