通过一个例子来讲解函数式自定义指令
按按钮n加1,同时显示放大十倍后的n。
<body> <div id="root"> <h2>我是:<span v-text="n"></span></h2> <h2 >我是十倍的:<span v-big="n"></span></h2> <button @click="n++">点我+1</button> </div> </body> <script> Vue.config.productionTip = false new Vue({ el:"#root", data:{ n:1 }, directives:{ big(element,binding){ element.innerText = binding.value * 10 } } }) </script>
通过在directives中创建函数来实现函数式自定义指令,传入的参数第一个是当前的节点,第二个是绑定的值。
在两种地方这里的指令中的函数会被调用
指令与元素成功绑定时(一上来)。
指令所在的模板被重新解析时。
对象式的自定义指令是对函数式的一种补充,因为函数式有缺陷。
需求:
每次点击按钮,input输入框中的数据为n的十倍,同时获取焦点
<body> <div id="root"> <h2>{{n}}</h2> <button @click="n++">点我+1</button> <input type="text" v-fbind="n"> </div> </body> <script> Vue.config.productionTip = false new Vue({ el:"#root", data:{ n:1 }, directives:{ fbind(element,binding) { element.value = binding.value element.focus() } } }) </script>
每次点击都会显示n的十倍,但是初始的焦点不在输入框中。
从原始的js来解释这个问题
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> <style> .demo{ background-color: orange; } </style> </head> <body> <button id="btn">点我创建输入框</button> <script> const btn = document.getElementById('btn') btn.onclick = () => { const input = document.createElement("input") input.className = "demo" input.value = 100 console.log(input.parentElement) document.body.appendChild(input) // 放入父节点之后才能生效 input.focus() console.log(input.parentElement) } </script> </body> </html>
可以从代码中看到,有些操作放在父节点之后才能生效,例如获取焦点、改变父节点属性等需要对父节点DOM的操作需要在子节点放入父节点之后操作。
而我们的函数式自定义指令只有在绑定和重新解析的时候执行,在第一次绑定的时候,节点还没有放入DOM中,因此第一次焦点不在输入框。
而对象式可以解决这类问题
<body> <div id="root"> <h2>{{n}}</h2> <button @click="n++">点我+1</button> <input type="text" v-fbind="n"> </div> </body> <script> Vue.config.productionTip = false new Vue({ el:"#root", data:{ n:1 }, directives:{ fbind:{ bind(element,binding){ console.log("bind") element.value = binding.value * 10 }, inserted(element,binding){ console.log("inserted") element.focus() }, update(element,binding){ console.log("update") element.value = binding.value * 10 element.focus() } } } }) </script>
对象式有三个函数分别是bind、inserted、update。
因此通过在inserted之后获取焦点可以实现第一次进入获取焦点。
函数式相当于简化的对象式,函数式中的函数其实代表了bind和update。
上面讲的都是局部自定义指令,可以写成全局自定义指令
<script> VUE.directive('fbind',{ bind(element,binding){ console.log("bind") element.value = binding.value * 10 }, inserted(element,binding){ console.log("inserted") element.focus() }, update(element,binding){ console.log("update") element.value = binding.value * 10 element.focus() } }) VUE.directive('fbind2',function(element, binding){ element.value = binding.value * 10 element.focus() }) </script>
不能写成bigName这种形式,因为VUE指令无法识别大小写
<body> <div id="root"> <h2>我是:<span v-text="n"></span></h2> <h2 >我是十倍的:<span v-bigNumber="n"></span></h2> <button @click="n++">点我+1</button> </div> </body> <script> Vue.config.productionTip = false new Vue({ el:"#root", data:{ n:1 }, directives:{ bigNumber(element,binding){ element.innerText = binding.value * 10 } } }) </script>
这样写会报错
可以统一改成小写但是不符合命名规范,因此采用kebab-case命名方式,也就是用-来分割单词big-number,而不能采用驼峰命名法,如果采用big-number命名,不能用简写形式,必须要在指令名上加引号。
'bigNumber':function(element,binding){ element.innerText = binding.value * 10 } 'fbind':{ bind(element,binding){ element.value = binding.value * 10 element.focus() }, inserted(element,binding){ }, update(element,binding){ element.value = binding.value * 10 element.focus() } }
局部指令
//对象式 new Vue({ directives:{指令名:配置对象} }) // 函数式 new Vue({ directives{指令名:回调函数} })
全局指令