自定义指令
类似组件可以全局注册和局部注册,使用 derective 注册。
钩子函数
指令定义函数提供了几个钩子函数(可选):
- bind:只调用一次,指令第一次绑定到元素时调用,可以定义一个在绑定时执行一次的初始化动作;
- inserted:被绑定元素插入父节点时调用(父节点存在即可调用,不必存在于 document中);
- update:被绑定元素所在的模板更新时调用,而不论绑定值是否变化;通过比较更新前后的绑定值,可以忽略不必要的模板更新;
- componentUpdated:被绑定元素所在模板完成一次更新周期时调用;
- unbind:只调用一次, 指令与元素解绑时调用。
钩子函数有以下参数:
- el:指令所绑定的元素,可以用来直接操作 DOM 。
- binding:一个对象,包含以下属性:
- name:指令名,不包括 “v” 前缀;
- value:指令的绑定值,例如 ` vmydirective="1 + 1",value 的值是2;
- oldValue:指令绑定的前一个值,仅在 update 和 componentUpdated 钩子中可用,无论值是否改变都可用;
- expression:绑定值的字符串形式,例如
vmydirective="1 + 1"
,expression 的值是“1 + 1”; - arg:传给指令的参数。例如
vmydirective:foo
, arg 的值是 “foo”。 - modifiers:一个包含修饰符的对象, 例如
vmydirective.foo.bar
,修饰符对
象 modifiers 的值是{ foo: true, bar: true }
;
- vnode:Vue 编译生成的虚拟节点。
- oldVnode:上一个虚拟节点,仅在 update 和 componentUpdated 钩子中可用。
<div id="app">
<input type="text" v-focus>获取焦点
<br>
<input type="text">
<hr>
<div v-command:expression.a.b.c="value"></div>
</div>
<script>
// 自定义指令
Vue.directive('focus', {
inserted: function (el) { // inserted 选项:插入父节点时调用
el.focus()
}
})
Vue.directive('command', {
bind: function (el, binding, vnode) {
let keys = []
for (let key in vnode) {
keys.push(key)
}
console.log(keys)
el.innerHTML =
// '<div v-command:expression=.a.b.c="value"></div>' + "<br>" +
"name: " + binding.name + "<br>" +
"name: " + binding.value + "<br>" +
"expression: " + binding.expression + "<br>" +
"argument: " + binding.arg + "<br>" +
"modifiers: " + JSON.stringify(binding.modifiers) + "<br>" +
"vnode keys: " + keys.join(", ") + "<br>"
}
})
let app = new Vue({
el: "#app",
data: {
value: "自定义指令所绑定的值"
}
})
</script>
render函数
在 render 函数中使用 this.$slots
和 props
传递数据:
<div id="app">
<child :level="level">
标题
</child>
<button v-on:click="add1()">+1</button>
<button v-on:click="minus1()">-1</button>
</div>
<script>
Vue.component('child', {
// 如使用template则只允许有一个子节点
render: function (createElement) { // 注意,参数createElement不可修改
// createElement函数的使用:
return createElement(
// 第一个参数(必须,用于创建DOM元素,可以是String/ Object/ Function)
'h' + this.level, // String(HTML标签)
// {template: '<div>haha</div>>'}, // Object(含有数据选项的对象)
// function () { // Function(返回含有数据选项的对象)
// return {template: '<div>haha</div>>'}
// },
// 第二个参数(可选,数据对象,只能是Object)
this.$slots.default // 含有VNode的数组
// {
// class: {active: true}, // 创建的DOM元素的属性
// style: {color: red, fontSize: '16px'},
// attrs: {id: 1, src: ""},
// domProps: {innerHTML: '<span style="color: red">红色</span>'},
// on: {input: functiopn(){//...}}
// }
// 第三个参数(可选,动态的VNode虚拟节点,可以是String或Array)
// [createElement("h1", "标题"), createElement("h2", "二级标题")]
);
},
props: ['level'] // 使用 props 在 render 函数中传递数据
})
let app = new Vue({
el: "#app",
data: {
level: 1
},
methods: {
add1: function () {
if (this.level < 6)
this.level += 1;
},
minus1: function () {
if (this.level > 1)
this.level -= 1;
}
}
})
</script>
在render函数中使用v-model
:
<div id="app">
<!-- 方法1:子组件使用$emit向父组件传递事件 -->
<!--<my-component :name="name" @input="showName"></my-component>-->
<!-- 方法2:使用v-model绑定属性,且自动接收input事件从子组件传递给父组件的值 -->
<my-component :name="name" v-model="name"></my-component>
<br> {{name}}
</div>
<script>
Vue.component("my-component", {
render: function (createElement) {
let self = this // 临时保存this,此处的this为当前Vue实例
return createElement("input", {
domProps: {
value: self.name
},
on: {
input: function (event) {
console.log(this) // 此处的this为window
self.$emit("input", event.target.value) // 输入内容传递给父组件
}
}
})
}
})
let app = new Vue({
el: "#app",
data: {
name: "ywh"
},
// methods: {
// showName: function(value) {
// this.name = value
// }
//
// }
})
</script>
在 render 函数中使用作用域插槽:
<div id="app">
<my-component>
<!-- 作用域插槽写在template中 -->
<template scope="prop"> <!-- prop获取传递过来的数据 -->
{{prop.text}}
</template>
</my-component>
</div>
<script>
Vue.component('my-component', {
render: function (createElement) {
// 相当于在template中创建一个<div><slot :text="text"></slot></div>
return createElement(
'div',
this.$scopedSlots.default({ // 使用作用域插槽
text: '子组件传递过来的数据',
})
)
}
})
let app = new Vue({
el: "#app"
})
</script>
函数化组件
<div id="app">
<my-component value="子组件信息"></my-component>
</div>
<script>
Vue.component('my-component', {
functional: true, // 表示当前Vue实例无状态,无实例(没有this)
render: function(createElement, context) {
// context中存放父组件、子组件中的内容
// this.text === context.props.text
// this.$slots.default === context.children
return createElement("button", {
on: {
click: function() {
console.log(context)
console.log(context.parent) // 表示父组件
alert(context.parent.parentMsg) // 父组件内容(msg)
console.log(context.props.value) // 子组件内容
}
}
}, "click")
},
prope: ["value"]
})
let app = new Vue({
el: "#app",
data: {
parentMsg: "父组件信息"
}
})
</script>