目录
4.补充:Vue组件中使用 render 代替 templete
1.JS 的 width 语法
- 改变 { } 内自由变量的查找规则,当做 obj 属性来查找
- 如果找不到匹配的 obj 属性,就会报错
- with 要慎用,它打破了作用域规则,易读性变差
const obj = {a: 100, b: 200}
console.log(obj.a) // 100
console.log(obj.b) // 200
console.log(obj.c) // undefined
// 使用 with,能改变{}内自由变量的查找方式
// 将 {} 内自由变量,当做 obj 的属性来查找 a => obj.a
with(obj) {
console.log(a) // 100
console.log(b) // 200
console.log(c) // Uncaught ReferenceError: c is not defined
}
2.模板编译成 js 代码(使用with)
// 从 vue 源码中找到缩写函数的含义
function installRenderHelpers (target) {
target._o = markOnce;
target._n = toNumber;
target._s = toString;
target._l = renderList;
target._t = renderSlot;
target._q = looseEqual;
target._i = looseIndexOf;
target._m = renderStatic;
target._f = resolveFilter;
target._k = checkKeyCodes;
target._b = bindObjectProps;
target._v = createTextVNode;
target._e = createEmptyVNode;
target._u = resolveScopedSlots;
target._g = bindObjectListeners;
target._d = bindDynamicKeys;
target._p = prependModifier;
}
_c = createTextVNode
// 1.插值
const template = `<p>{{message}}</p>`
// 编译后
with(this){
return createElement('p',[createTextVNode(toString(message))])
}
// 2.表达式
const template = `<p>{{flag ? message : 'no message found'}}</p>`
// 编译后
with(this){
return _c('p',[_v(_s(flag ? message : 'no message found'))])
}
// 3.属性和动态属性
const template = `
<div id="div1" class="container">
<img :src="imgUrl"/>
</div>
`
// 编译后
with(this){
return _c('div',
{staticClass:"container",attrs:{"id":"div1"}},
[
_c('img',{attrs:{"src":imgUrl}})
]
)
}
// 4.条件
const template = `
<div>
<p v-if="flag === 'a'">A</p>
<p v-else>B</p>
</div>
`
// 编译后
with(this){
return _c('div',[(flag === 'a')?_c('p',[_v("A")]):_c('p',[_v("B")])])
}
// 5.循环
const template = `
<ul>
<li v-for="item in list" :key="item.id">{{item.title}}</li>
</ul>
`
// 编译后
with(this){
return _c('ul',_l((list),
function(item){
return _c('li',{key:item.id},[_v(_s(item.title))])
}
),0)
}
// 6.事件
const template = `
<button @click="clickHandler">submit</button>
`
with(this){
return _c('button',{on:{"click":clickHandler}},[_v("submit")])
}
// 7.v-model
const template = `<input type="text" v-model="name">`
with(this){
return _c('input',{directives:[
{
name:"model",
rawName:"v-model",
value:(name),
expression:"name"}],
attrs:{"type":"text"},
domProps:{"value":(name)},
on:{"input":function($event){
if($event.target.composing)return;
name=$event.target.value}
}
})
}
// render 函数
// 返回 vnode
// patch
// 编译
const res = compiler.compile(template)
console.log(res.render)
3.编译模板总结
- 模板编译为 render 函数,执行 render 函数返回 vnode
- 基于 vnode 再执行 patch 和 diff
- 使用 webpack vue-loader,会在开发环境下编译模板,打包后显示编译后的js代码
4.补充:Vue组件中使用 render 代替 templete
Vue.component('heading', {
// templete: '<h1><a name="headerId" href="#headerId">this is a tag</a></h1>'
render: function (createElement) {
return createElement(
'h' + this.level,
[
createElement('a',{
attrs: {
name: 'headerId',
href: '#' + 'headerId'
}
}, 'this is a tag')
]
)
}
})
5.总结
- width 语法
- 模板到 render 函数,再到 vnode,再到渲染和更新
- vue 组件可以用 render 代替 template