自定义指令
❝directive
❞
注册
全局注册
<div id="app">
<input type="text" v-focus>
</div>
<script>
//注册一个自定义指令
Vue.directive('focus',{
//将被绑定的元素插入到DOM中
inserted: function(el){
el.focus()
}
})
var app = new Vue({
el: '#app',
})
</script>
局部注册
var app = new Vue({
el: '#app',
directives: {
focus: {
inserted: function(el){
el.focus()
}
}
}
})
钩子函数
- inserted: 被绑定元素插入父节点
- bind:
- update:
- componentUpdate:
- unbind:
钩子函数参数
- el:指令所绑定元素。
- binding: 一个对象
- name:指令名
- value: 指令绑定的值
- oldValue: 指令绑定的前一个值
- expression: 字符串形式的指令表达式
- arg:传给指令的参数
- modifiers: 一个包含修饰符的对象
- vnode:vue编译的虚拟节点
<div id="app" v-demo:foo.a.b='message'>
</div>
<script>
Vue.directive('demo',{
bind: function(el,binding,vnode){
var s = JSON.stringify
el.innerHTML =
'name: '+ s(binding.name) + '<br>' +
'value: ' + s(binding.value) + '<br>' +
'expression: ' + s(binding.expression) + '<br>' +
'arg: ' + s(binding.arg) + '<br>' +
'modifiers: ' + s(binding.modifiers)
}
})
var app = new Vue({
el: '#app',
data:{
message: 'hello'
}
})
</script>
结果:
name: "demo"
value: "hello"
expression: "message"
arg: "foo"
modifiers: {"a":true,"b":true}
render函数
❝不使用模板,使用render函数可以用js来构建DOM
❞
「default包括了所有没有在具名插槽中的节点或v-slot:default中的内容,向组件传递不带v-slot指令的子节点时,这些子节点被存储在组件实例中的$slots.default中」
「vm.$slots用来被访问插槽分发的内容,每个具名插槽有其相应的property」
Vue通过建立一个虚拟DOM对真实DOM发生变化保存追踪,createElement包含的信息会告诉Vue页面上需要渲染什么样的节点,包括以及其子节点的信息。这样的节点即虚拟节点
<div id="app">
<h1>
<a href="">
hello world
</a>
</h1>
<my-component :level='level'>
hello Vue
</my-component>
</div>
<script>
Vue.component('my-component',{
render: function(createElement){
//createElement不是一个实际的DOM,
//其包含的信息告诉vue页面上需要渲染什么样的节点,包括其子节点的描述信息,
//它就是虚拟节点
return createElement(
'h'+this.level,
this.$slots.default
//通过$slots.default访问不带v-slot的子节点hello vue
)
},
props: {
level: {
type: Number,
required: true
}
}
})
var app = new Vue({
el: '#app',
data: {
level: 2
}
})
</script>
render函数第一个参数
❝createElement参数的类型必选 String | Object | Function
❞
<div id="app">
<child></child>
</div>
<script>
Vue.component('child',{
render: function(createElement){
// return createElement('h1','hello')
// return createElement({
// template: '<div>hello vue</div>'
// })
var domFun = function(){
alert(typeof createElement)
return {
template: '<div>hello world</div>'
}
}
return createElement(domFun())
}
})
var app = new Vue({
el: '#app'
})
</script>
render函数的第二个参数
第二个参数是数据对象,只能是Object,常用属性 class|style|domProps|attrs|on
<div id="app">
<child></child>
</div>
<script>
Vue.component('child',{
render: function(createElement){
return createElement({
template: '<a>hello world</a>'
},{
style: {
color: 'red',
fontSize: '20px',
height: '30px',
backgroundColor: 'yellow'
},
attrs: {
id: 'foo',
href: 'http://baidu.com'
},
class: {
foo: true,
baz: false
},
//domProps用来写原生DOM属性
domProps: {
innerHTML: '<span style="color: blue;">hello vue</span>'
}
})
}
})
var app = new Vue({
el: '#app'
})
</script>
render函数的第三个参数
第三个参数 String | Array构建子节点
<div id="app">
<child></child>
</div>
<script>
Vue.component('child',{
render: function(createElement){
return createElement('div',[
//这里是数组,是第三个参数
createElement('h1','hello'),
createElement('h5','world')
])
}
})
var app = new Vue({
el: '#app'
})
</script>
this.slots在render函数中的应用
第三个参数存的就是VNODE createElement('header',header),返回的就是VNODE var header = this.$slots.header
<div id="app">
<child>
<p slot="header">hello</p>
<p slot='footer'>world</p>
</child>
</div>
<script>
Vue.component('child',{
render: function(createElement){
var header = this.$slots.header
var footer = this.$slots.footer
return createElement('div',[
createElement('header',header),
createElement('footer',footer)
])
}
})
var app = new Vue({
el: '#app'
})
</script>
通过props在render函数中传递数据
<div id="app">
<child :show='show'></child>
<br>
<button @click='click'>点击我</button>
</div>
<script>
Vue.component('child',{
props: ['show'],
render: function(createElement){
var imgsrc;
if(this.show){
imgsrc = "https://lh3.googleusercontent.com/proxy/DwkPRPpr6gfUGGTEN6_alb8l9m0F0FLjG3BJUfKyF3Pt-MgD_fASJzayTPjbH4bDHVrK_pwtqWbFLCkYSHyeQyxbwjo7zU_-v5N6kZa_BpJVDNwbYV3zMWBFaBE7jMOivxBWaj46NKUjT0sk0-rpg4nt0z0U0Pb7XS3bzGUQqg4mKrBpuw"
}else {
imgsrc ='https://static.runoob.com/images/demo/demo2.jpg'
}
return createElement('img',{
attrs: {
src: imgsrc
},
style: {
width: '100px',
height: '100px'
}
})
}
})
var app = new Vue({
el: '#app',
data: {
show: true
},
methods: {
click: function(){
this.show = !this.show
}
}
})
</script>
v-model在render函数中使用
渲染函数中没有与 v-model 的直接对应——你必须自己实现相应的逻辑
<div id="app">
<my-component v-model='name'></my-component>
{{name}}
</div>
<script>
Vue.component('my-component',{
render: function(createElement){
var self = this
return createElement('input',{
domProps: {
value: this.name
},
on: {
input: function(event){
// 这里的this指向的是window
// self指向的是vue实例
self.$emit('input',event.target.value)
}
}
})
},
props: ['name']
})
var app = new Vue({
el: '#app',
data: {
name: 'Jane'
}
})
</script>
作用域插槽在render函数中的作用
<div id="app">
<my-component>
<template v-slot='prop'>
{{prop.text}}
</template>
</my-component>
</div>
<script>
Vue.component('my-component',{
render: function(createElement){
return createElement('div',this.$scopedSlots.default({
text: 'hello world'
}))
}
})
var app = new Vue({
el: '#app',
data:{
}
})
</script>
vm.$scopedSlots
用来访问作用域插槽
this.$scopedSlots.default
render函数组件化
<div id="app">
<my-component value='haha' :msg='msg'>
<template>
<slot>hello</slot>
</template>
</my-component>
</div>
<script>
Vue.component('my-component',{
functional: true,
//表示当前的实例无状态,没有this和data
//context为上下文对象,通过它可以拿到数据
render: function(createElement,context){
return createElement('button',{
on: {
click: function(){
console.log(context)
// this.text= context.props.text
console.log(context.parent)
console.log(context.props.value)
console.log(context.props.msg)
// this.$slots.default = context.children
console.log(context.children)
console.log(this.value)
//undefined ,functional:true后无法拿到外界的数据
}
}
},'click')
},
props: ['value','msg']
})
var app = new Vue({
el: '#app',
data:{
name: 'hello',
msg: 'world'
}
})
</script>