vue有两种构建方式(独立构建,运行时构建),独立构建包括了编译器部分,运行时构建不包括编译器
template,el,render的区别
template,el,render都可以指定具体渲染的内容,当实例参数中同时存在这三个参数时,其优先级为render>template>el,具体参考如下:
<!DOCTYPE html>
<html>
<head>
<title>demo</title>
<script src="https://cdn.jsdelivr.net/npm/vue@2.5.16/dist/vue.js"></script>
</head>
<body>
<div class="vapp-1"></div>
<div class="vapp-2"></div>
<div class="vapp-3"></div>
</body>
<script type="text/javascript">
new Vue({
el: '.vapp-1', //此时el只是指定了渲染后的挂载点
data: {
info: '这是通过el属性获取挂载元素的outerHTML方式渲染。'
},
template: '<p>这是template属性模板渲染。</p>',
render: function(h) {
return h('p', {}, '这是render属性方式渲染。')
}
})
new Vue({
el: '.vapp-2', //此时el只是指定了渲染后的挂载点
data: {
info: '这是通过el属性获取挂载元素的outerHTML方式渲染。'
},
template: '<p>这是template属性模板渲染。</p>'
})
new Vue({
el: '.vapp-3', //此时el.outerHTML为待编译的模板
data: {
info: '这是通过el属性获取挂载元素的outerHTML方式渲染。'
}
})
</script>
</html>
结果:
其实这三种编译模式本质都一样,template和el模板都将被编译成render函数,vue渲染是最终都是执行render函数来进行dom的挂载。
如果构建vue实例时没有指定render函数,则必须使用独立构建的vue库文件(vue.js属于独立构建的库文件),如果将上例代码中的vue.js换成vue.runtime.js(运行时库文件),则将报错。
<!DOCTYPE html>
<html>
<head>
<title>demo</title>
<script src="https://cdn.jsdelivr.net/npm/vue@2.5.16/dist/vue.runtime.js"></script>
</head>
<body>
<div class="vapp-1"></div>
<div class="vapp-2"></div>
<div class="vapp-3"></div>
</body>
<script type="text/javascript">
new Vue({
el: '.vapp-1',
data: {
info: '这是通过el属性获取挂载元素的outerHTML方式渲染。'
},
template: '<p>这是template属性模板渲染。</p>',
render: function(h) {
return h('p', {}, '这是render属性方式渲染。')
}
})
new Vue({
el: '.vapp-2',
data: {
info: '这是通过el属性获取挂载元素的outerHTML方式渲染。'
},
template: '<p>这是template属性模板渲染。</p>'
})
new Vue({
el: '.vapp-3',
data: {
info: '这是通过el属性获取挂载元素的outerHTML方式渲染。'
}
})
</script>
</html>
结果:
webpack打包vue项目时默认使用的是运行时库,如果需要使用独立构建的库,可以配置别名
resolve: {
alias: {
'vue$': 'vue/dist/vue.common.js', //针对CommonJS模式
//'vue$': 'vue/dist/vue.esm.js', //针对ES Module模式
//'vue$': 'vue/dist/vue.js', //针对UMD模式
}
}
render函数
render函数没有template里面v-if,v-for等功能,要想实现,需要我们自己手动模拟相关功能。
render模拟v-if
<!DOCTYPE html>
<html>
<head>
<title>demo</title>
<script src="https://cdn.jsdelivr.net/npm/vue@2.5.16/dist/vue.min.js"></script>
</head>
<body>
<div id="app1">
<div v-if="level==1">这是level1</div><div v-if="level==2">这是level2</div>
</div>
<div id="app2">
</div>
</body>
<script type="text/javascript">
new Vue({
el: '#app1',
data: {
level: 1
}
})
new Vue({
data: {
level: 2
},
render: function(createElement){
if(this.level == 1){
var dom = createElement('div',{},'这是level1');
}else{
var dom = createElement('div',{},'这是level2');
}
return dom;
}
}).$mount('#app2')
</script>
</html>
结果:
render函数模拟v-model
<!DOCTYPE html>
<html>
<head>
<title>demo</title>
<script src="https://cdn.jsdelivr.net/npm/vue@2.5.16/dist/vue.min.js"></script>
</head>
<body>
<div id="app">
<my-component ref="input" @input="input"></my-component>
</div>
</body>
<script type="text/javascript">
Vue.component('my-component',{
data: {
value: ''
},
render: function(createElement) {
var self = this;
var dom = createElement('input', {
domProps: {
value: 'default',
},
on: {
input: function(event) {
self.value = event.target.value;
self.$emit('input',self.value);
}
}
});
return dom;
}
})
new Vue({
el: '#app',
methods: {
input: function(value) {
console.log(value,this.$refs.input.value);
}
}
})
</script>
</html>
render函数之$slots
render函数里的$slots只能在组件里使用,vue全局实例里的render函数没有$slots的概念
<!DOCTYPE html>
<html>
<head>
<title>demo</title>
<script src="https://cdn.jsdelivr.net/npm/vue@2.5.16/dist/vue.min.js"></script>
</head>
<body>
<div id="app">
<my-component><span>lisong</span></my-component>
</div>
</body>
<script type="text/javascript">
Vue.component('my-component',{
render: function(createElement) {
var self = this;
var dom = createElement('div', 'hello '+this.$slots.default[0].children[0].text); //hello lisong
console.log(this.$slots);
return dom;
}
})
new Vue({
el: '#app'
})
</script>
</html>
createElement
createElement详细参数
{
// 和`v-bind:class`一样的 API
'class': {
foo: true,
bar: false
},
// 和`v-bind:style`一样的 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
},
// 仅对于组件,用于监听原生事件,而不是组件内部使用
// `vm.$emit` 触发的事件。
nativeOn: {
click: this.nativeClickHandler
},
// 自定义指令。注意,你无法对 `binding` 中的 `oldValue`
// 赋值,因为 Vue 已经自动为你进行了同步。
directives: [
{
name: 'my-custom-directive',
value: '2',
expression: '1 + 1',
arg: 'foo',
modifiers: {
bar: true
}
}
],
// Scoped slots in the form of
// { name: props => VNode | Array<VNode> }
scopedSlots: {
default: props => createElement('span', props.text)
},
// 如果组件是其他组件的子组件,需为插槽指定名称
slot: 'name-of-slot',
// 其他特殊顶层属性
key: 'myKey',
ref: 'myRef'
}