Vue自定义指令

Vue自定义指令

1、Vue自定义指令

本文主要讲述的是Vue自定义指令内容,为后续实现级联组件做铺垫。vue

① 指令简介

首先以经常使用的v-model指令的使用为例:node

<input type="text" v-model.lazy="age"/>{{age}}
Vue指令主要用于 须要进行一些DOM操做的时候,经过Vue指令 将DOM操做进行封装
使用指令的时候分为 左右两部分,等号左边是 指令名(v-model)修饰符(.lazy),等号右边是 指令表达式(age),指令表达式虽然是一个单纯的字符串,可是指令表达式的值倒是 当前组件上的同名属性对应的值,上面input输入框中显示的将是 this.age的值

这里补充一下v-model指令的三个修饰符的用法:express

  • .lazy修饰符,v-model指令默认监听的是input事件,即随用户的输入实时更新的,可是使用.lazy修饰符后,监听的事件则变成了change事件,也就是说触发条件变成了用户输入完成后输入框失去焦点或者用户按了Enter键以后值才会发生改变。
  • .number修饰符,当input输入框的类型为text的时候,其做用不是限制用户只能输入数字,而是将用户的输入尝试转换为数字类型以后再绑定到Vue实例上,即,能转换为数字就转换为数字,不能转换为数字的则仍然使用字符串的形式,好比:
<input type="text" v-model.number="age"/>{{age}}
当用户在输入框中输入"18a"后,最右侧显示的age的值 仍然为18,由于其会将"18a"先转换为数字类型,因此值仍然为 数字18;当用户输入"a18"后,最右侧显示的age值就会变为"a18",由于"a18"没法转换为数字,因此仍然显示 字符串"a18"
  • .trim修饰符,会将用户的输入去除左右两边空格后再绑定到Vue实例上

② 自定义指令的建立与使用

指令 实际上是一个对象。若是想在Vue组件中建立自定义的指令,那么能够在组件上添加 directives属性,其 属性值为一个对象,而后将自定义指令注册到directives属性值上,对象的 属性名指令名称,对象的 属性值自定义指令对象。须要注意的是,指令名称采用的驼峰命名法, 不包括v-部分,使用的时候 驼峰命名大写部分转换为小写并用-隔开,如:

// 某个组件ide

export default {
    directives: { // 在当前组件上注册一个指令
        clickOutside: { // 指令名称为clickOutside,使用的时候使用v-click-outside
            // 指令对象
        }
    }
}
<!--使用指令-->
 <div v-click-outside:bar.foo="close"></div>
指令对象内部主要是一些钩子函数,如: bindinsertedupdatecomponentUpdatedunbind,比较经常使用的是inserted, 在使用了该指令的元素被插入到父元素内时候执行,固然最重要的就是传递给钩子函数处理的参数,由于指令最重要的做用就是 操做DOM,因此其

① 第一个参数就是el,是绑定了指令的DOM元素对象,若是绑定指令的是一个组件,也就是说指令用在了组件上,那么el就表明这个组件渲染后的整个DOM元素对象。函数

② 第二个参数就是binding,是一个对象,包含了当前指令的一些属性,好比: binding.name值为click-outside,不包含v-部分,binding.expression值为close,binding.value值就是this.close的值,即当前组件上close属性对应的值,能够是一个单纯的数据,也能够是一个方法名,这里close就是一个组件上的close()方法,binding. modifiers值为{foo:true}就是当前指令的修饰符,是一个对象,若是没有修饰符则是一个空的对象{},binding.arg值为bar,是传递给指令的参数,即冒号修饰的部分this

注意: 指令的参数必须写在修饰符的前面,即冒号必须在点号前双向绑定

③第三个参数为vnode,即Vue编译生成的虚拟节点,这个参数很是有用,能够获取到很是多Vue实例相关的东西,vnode.context能够获取到当前vue组件实例,vnode.componentInstance,若是指令是用在某个组件上,那么componentInstance获取的就是使用了该指令的那个Vue组件实例code

export default {
    directives: { // 在当前组件上注册一个指令
        clickOutside: { // 指令名称为clickOutside,使用的时候使用v-click-outside
            inserted(el, binding) {
                document.addEventListener("click", (e) => { // 给整个document添加click事件
                    if (e.target === el || el.contains(e.target)) { // 若是点击的区域是使用了该指令的DOM元素的内部,那么不作任何处理
                        return;
                    }
                    binding.value(); // 即调用close()方法
                });
            }
        }
    }
}
该指令实现的是点击了 绑定指令的元素的外面后,执行指令绑定的方法

2、模拟实现v-model指令

实现一个 v-my-model指令,具备v-model的大部分功能,如下指令代码并非源码的实现,仅仅是简单模拟一下v-model指令的功能,包括v-model的双向绑定功能、lazy修饰符、number修饰符、trim修饰符。
export default {
    directives: { // 注册v-my-model到组件上
         myModel: { // 指令名称采用驼峰命名法
             inserted(el, binding, vnode) { // 在绑定元素插入父元素后执行
               el.value = binding.value; // 获取指令表达式的值做为input元素的value值
               const eventName = binding.modifiers.lazy ? "change": "input"; // 处理lazy修饰符,若是有lazy属性则换成change事件
               el.addEventListener(eventName, (e) => { // input元素监听input或者change事件
                   let result = e.target.value; // 获取用户输入
                   if (binding.modifiers.number && !Number.isNaN(parseInt(e.target.value))) { // 若是指令带有number修饰符,而且用户的输入可以转换为number
                       result = parseInt(e.target.value); // 将用户的输入转换为对应的数字
                   }
                   if (binding.modifiers.trim) { // 若是指令带有trim修饰符
                       result = result.trim(); // 去除用户输入的首尾空格
                   }
                   vnode.context[binding.expression] = result; // 将最终的结果保存到当前组件实例上即view --> model中
               });
               
               vnode.context.$watch(binding.expression, (newValue, oldValue) => { // 获取组件实例并监听其中的绑定的值变化
                   el.value = newValue; // 若是组件实例上数据发生变化,那么更新view数据
               });
             }
         }   
    }
}
v-my-model指令主要就是监听 input或者 change事件,同时经过 监听组件实例中指定数据的变化实现数据的 双向绑定。大致上实现了v-model指令的功能。
相关文章
相关标签/搜索