文章目录
一、vue中自定义指令
1. 什么是自定义指令?
除了使用 Vue 提供的内置指令之外,我们可以自定义一些自己的指令,来实现业务操作。
2. 什么时候需要自定义指令?
当你需要不可避免的操作 DOM 的时候,使用自定义指令来解决
3. 如何注册和使用自定义指令?
1. 注册
- 全局注册,在任何组件中都可以使用全局注册自定义指令
- 局部注册,只能在当前组件使用该指令
如果需要在多个不同的组件中使用该指令,则把它定义为全局的
非通用的,不需要多次使用的指令我们定义到局部
2. 使用
例:注册一个自定义指令focus
// 注册一个全局自定义指令 `v-focus`
Vue.directive('focus', {
// 当被绑定的元素插入到 DOM 中时……
inserted: function (el) {
// 聚焦元素
el.focus()
}
})
注册一个全局自定义指令 v-focus
使用 声明Vue.directive()
参一是指令的名字
- 指令的名字随便起,但是在使用的时候务必加上 v- 前缀,所以我们在其名字的时候就不要加 v- 前缀
- 如果是驼峰命名法的名称,则在使用的时候需要把驼峰转为小写使用 - 连接起来(例:myFocus 为 v-my-focus)
参二是钩子函数
下面我们将简单介绍钩子函数
二、钩子函数
1. 简介钩子函数
vue中提供了5个钩子函数
- bind:只调用一次,指令第一次绑定到元素时调用。在这里可以进行一次性的初始化设置。(bind 中拿不到父元素)
- inserted:被绑定元素插入父节点时调用 (仅保证父节点存在,但不一定已被插入文档中)。如果你需要操作作用指令的父元素,则最起码写到这个 inserted 中
- update:所在组件的 VNode 更新时调用,但是可能发生在其子 VNode 更新之前。指令的值可能发生了改变,也可能没有。但是你可以通过比较更新前后的值来忽略不必要的模板更新 (详细的钩子函数参数见下)。
- componentUpdated:指令所在组件的 VNode 及其子 VNode 全部更新后调用。
- unbind:只调用一次,指令与元素解绑时调用。
每个钩子函数都可以接收两个参数:
- el 作用该指令的 DOM 对象
- binding 一个对象,可以获取指令的值等信息
注意:
- bind 和 inserted 的相同之处是一上来都执行一次,以后再也不会执行,异同之处在于,bind 拿不到父元素,inserted 可以拿到父元素
- update 和 componentUpdated 只有在指令的绑定的值发生更新的时候才会触发调用
- update 和 componentUpdated 的区别是:
update 中获取的是更新的之前的指令所在的 DOM 内容
componentUpdated 获取的是更新之后的最新 DOM 内容
update 拿到的是数据改变视图之前的视图内容
componentUpdated 拿到的是数据改变视图之后的视图内容
也就是说如果你需要获取数据改变视图之前的内容,则把代码写到 update 中
如果需要获取数据改变视图之后的内容,则把代码写到 componentUpdated 里面
例: 模拟v-show实现
<div id="app">
<!-- <input type="text" v-focus> -->
<div class="box" v-my-show="seen">{{ seen }}</div>
</div>
Vue.directive('my-show', {
bind (el, binding) {
inserted (el, binding) {
console.log('my-show inserted')
if (binding.value) {
el.style.display = 'block'
} else {
el.style.display = 'none'
}
},
update (el, binding) {
// console.log('my-show update', el, binding)
console.log('my-show update', el.innerHTML)
if (binding.value) {
el.style.display = 'block'
} else {
el.style.display = 'none'
}
},
componentUpdated (el, binding) {
console.log('my-show componentUpdated', el.innerHTML)
},
unbind () {
console.log('my-show unbind')
}
})
2. 函数简写
在很多时候,你可能想在 bind 和 update 时触发相同行为,而不关心其它的钩子。比如这样写:
Vue.directive('color-swatch', function (el, binding) {
el.style.backgroundColor = binding.value
})
我只关心 bind 和 inserted,所以可以这样简写
Vue.directive('my-show', function (el, binding) {
// console.log('my-show update', el, binding)
// console.log('my-show update', el.innerHTML)
if (binding.value) {
el.style.display = 'block'
} else {
el.style.display = 'none'
}
})
模拟v-bind动态绑定属性值
<body>
<div id="app">
<h1 v-my-bind:title="message" v-my-bind:foo="message">{{ message }}</h1>
<input type="text" v-model="message">
</div>
<script src="node_modules/vue/dist/vue.js"></script>
<script>
// v-bind 作用
// 动态绑定属性值
// Vue.directive('my-bind', {
// bind (el, binding) {
// console.log(binding.value)
// el.setAttribute(binding.arg, binding.value)
// },
// update (el, binding) {
// el.setAttribute(binding.arg, binding.value)
// }
// })
// 很多时候,我们都会在 bind 和 update 中执行相同的代码
// 所我们可以使用简写的方式,.直接给一个函数,该函数会被作为 bind 和 update 的时候执行的函数
Vue.directive('my-bind', function (el, binding) {
el.setAttribute(binding.arg, binding.value)
})
const app = new Vue({
data: {
message: 'Hello Vue.js!'
},
methods: {}
}).$mount('#app')
</script>
</body>
模拟v-bind绑定class
<style>
.box {
background-color: pink;
}
.box2 {
color: red;
}
</style>
</head>
<body>
<div id="app">
<h1 v-my-bind:title="123">{{ message }}</h1>
<input type="text" v-model="message">
<input type="checkbox" v-model="toggleBox"> toggleBox
<input type="checkbox" v-model="toggleBox2"> toggleBox2
<div v-my-bind:class="{box: toggleBox, box2: toggleBox2}">
hello vue
</div>
</div>
<script src="node_modules/vue/dist/vue.js"></script>
<script>
// v-bind:class = "{}"
// v-bind:class = "xxx"
Vue.directive('my-bind', function (el, binding) {
console.log('所在模板更新了')
if (binding.arg === 'class') {
for (let key in binding.value) {
if (binding.value[key]) {
// 作用类名
el.classList.add(key)
} else {
el.classList.remove(key)
}
}
} else {
el.setAttribute(binding.arg, binding.value)
}
})
const app = new Vue({
data: {
message: 'Hello Vue.js!',
toggleBox: true,
toggleBox2: true
},
methods: {}
}).$mount('#app')
</script>
</body>