Vue中除框架默认自带的 v-model v-show 等指令外,也允许自定义指令。需要注意的是代码的抽象和复用主要形式是"组件",确实需要对DOM元素底层进行操作时,才推荐使用指令。
Vue中存在两种指令形式:全局指令、局部指令。
直接将指令定义在 Vue 实例上
Vue.directive('focus', function(el, binding) {
el.focus();
})
在项目中大部分情况下不会使用这种情况的全局指令,而是通过将指令单独提出来,再统一注册的方式创建全局指令。
在 vue-cli 中,创建文件夹 directive,创建 index.js 文件
// directive > index.js
import Vue from "vue";
import focus from "./focus";
import color from "./color";
const direvtives = {
focus,
color,
}
Object.keys(direvtives).forEach(item => {
Vue.directive(key, direvtives[key]);
})
在main.js中引入并调用
// main.js
import directive from "@/directive";
Vue.use(directive);
局部指令是指注册在组件内部,由此组件独占的指令。不推荐使用此种方案,需要用到组件的场景大部分都是需要全局注册的。
<div v-color>div>
export default {
name: 'a-color',
directive: {
focus: {
inserted(el) {
el.focus();
}
}
},
}
指令中存在一系列的钩子函数:
directive: {
dire: {
focus: {
/**
* 指令第一次绑定到元素时调用,只调用一次,一般用于初始化设置
* */
bind(el, binding, vNode) {
console.log(el); // 指令绑定的元素
console.log(binding.name); // 指令名 focus
console.log(binding.value); // 指令绑定值 2
console.log(binding.expression); // 指令表达式 1 + 1
console.log(binding.arg); // 传给指令的参数 foo
console.log(binding.modifiers); // 包含修饰符的对象 {bar: true}
console.log(vNode); // 虚拟DOM节点 vNode {tag: 'input'...}
},
/**
* 被绑定元素插入父节点时调用
* */
inserted(el, binding, vNode) {},
/**
* 所在组件虚拟DOM节点更新时调用,但是可能发生在其子vNode更新之前。
* */
update(el, binding, vNode, oldVnode){
console.log(binding.oldValue); // 指令绑定的前一个值
console.log(oldVnode); // 上一个虚拟DOM节点
},
/**
* 指令所在组件的VNode及子VNode全部更新后调用
* */
componentUpdated(el, binding, vNode, oldVnode) {},
/**
* 指令与元素解绑时调用
* */
unbind(){}
}
}
一般而言,大部分的指令操作都在 inserted 方法中进行。另外如果想在 bind 和 update 中触发相同的行为,可以直接省略钩子函数调用,采用简写的方式。
directive: {
focus(el, binding) {
el.style.color = binding.value;
}
}
vue允许指令的参数是动态的, v-color:[args]=“value”
<div v-color[foo]="red">div>
<textarea v-model="copyText">textarea>
<button v-copy="copyText">复制button>
directives: {
copy: {
bind(el, { value }) {
el.$value = value
el.handler = () => {
if (!el.$value) {
alert('无复制内容')
return
}
// 动态创建 textarea 标签
const textarea = document.createElement('textarea')
// 将该 textarea 设为 readonly 防止 iOS 下自动唤起键盘,同时将 textarea 移出可视区域
textarea.readOnly = 'readonly'
textarea.style.position = 'absolute'
textarea.style.left = '-9999px'
// 将要 copy 的值赋给 textarea 标签的 value 属性
textarea.value = el.$value
// 将 textarea 插入到 body 中
document.body.appendChild(textarea)
// 选中值并复制
textarea.select()
const result = document.execCommand('Copy')
if (result) {
alert('复制成功') // 可根据项目UI仔细设计
}
document.body.removeChild(textarea)
}
// 绑定点击事件,就是所谓的一键 copy 啦
el.addEventListener('click', el.handler)
},
// 当传进来的值更新的时候触发
componentUpdated(el, { value }) {
el.$value = value
},
// 指令与元素解绑的时候,移除事件绑定
unbind(el) {
el.removeEventListener('click', el.handler)
},
}
}