使用 Vue Directive 封装 DOM 操作

11,781 阅读4分钟
原文链接: elegenthus.github.io

这篇文章是关于Vue Directive的介绍,后面会介绍一个使用的小例子。


1.Vue Directive的简介

directive在Vue中十分常见,Vue提供的许多指令如 v-onv-show 使得Vue的功能更加强大,可是仍然有一些操作指令是Vue没有提供的,不过Vue提供了自定义directive的属性方法来满足这一需求。其实,Vue Directive就是一种特殊的HTML元素属性。
Vue提供了两中注册方法,一种是全局注册,在Vue.directive中定义组件的名字和相关指令操作

    Vue.directive('指令的名字', {
        //一些option,提供许多hook function 定义directive的具体操作,如inserted、bind...
        inserted: function (el) {
            //指令插入元素后的操作
        }
    })

另一种是局部注册,在对应组件的directives属性里注册组件名,传入指令的option对象

directives: {
  name: {  //指令的名字
    // 指令的定义
  }
}

在定义时,Vue提供了许多hook function,例如 insertedbind等,bind是只会在绑定的对象节点被插入父节点时调用一次的函数,与unbind相对应,unbind将也只会在元素被解除绑定时调用。

Vue.directive('指令的名字', {
    bind: function(el, binding, vnode,oldVnode) {
        //绑定指令时调用
    },
    unbind: function() {
        //指令解除绑定时调用
    }
})

bind函数中的binding,是一个包含了众多属性的对象,关于它的所有的性质的介绍可以自行查看官方文档 ,比较常用的一个属性binding.value,与其对应的是在指令中传入的字符串,Vue会自动解析这个值并执行。与此相对应的另一个属性binding.expression里的值则就是原始值。

2.为什么要使用VueDirective

有同学可能会问,我在Vue实例的方法中写DOM操作不可以吗?那为什么使用Vue Directive来封装DOM操作呢?
这是因为,为了实现View和ViewModel的分离,我们必须封装DOM操作,View层负责页面上的显示,ViewModel层负责改变操作数据,由于Vue是数据驱动的,属于ViewModel层,那么其中就不应该出现View层上的DOM操作,而且,使用Vue Directive是和DOM元素的创建、销毁绑定的。Vue Directive的生命周期方法能让我们更优雅的去在合适的时机进行DOM的操作。而在ViewModel里则没有和DOM元素对应的方法。因为Vue Directive是属于View层面的,所以DOM操作应该被封装在Vue Directive里而不是出现在Vue实例中。

3. Demo:自制scroll指令

接下来看一个具体使用Vue Directive封装DOM操作的scroll事件的例子,在这个例子中需求是在用户滑动到页面的底端时请求更多数据。

3.1 首先将DOM操作封装到指令的option中

let scrollCallback = function(callback) {
    if (document.body.scrollHeight < 1000) {
        return
    }
    if (document.body.scrollHeight - window.scrollY - 100  document.body.clientHeight) {
        callback()
    }
}
let callBackWarpped // 新变量 保存引用
export default {
    bind: function(el, binding, vnode) {
        callBackWarpped =  scrollCallback.bind({}, binding.value)
        window.addEventListener("scroll", callBackWarpped)
    },
    unbind: function() {
        window.removeEventListener("scroll", callBackWarpped)
    }
}

首先需要监听页面的滚动,如果触发了scroll事件那么就要执行回调函数,由于在解除绑定的时候也要将监听事件从window上移除,所以必须给回调函数取一个名字,例如本例中的scrollCallback,并在unbind函数中将监听移除,因此scrollCallBack的具体定义应在对象外执行。
并且回调函数应该在页面滑动到底端时才执行,也就是说不能马上执行 binding.value,怎样实现这一点呢?可以将bind.value作为函数的参数传进scrollCallback,先判断,然后在满足条件时调用binding.value

3.2 在组件里import一个directive

import scrollDirective from '../../directives/scroll'
//import 指令的option的名字 from '指令option的位置'

使用import将directive引入组件。

3.3 在组件的directives属性中注册这个指令,值为scroll

directives: {
    scroll: scrollDirective
    //指令的名字:指令的option的名字
},

将引入的组件注册到scroll上。

3.4 在相应元素上加上directive指令

v-scroll = "onScroll"
//v-'指令的名字' = "回调函数"

用注册好的名字在相对应的元素上加入指令 。

3.5 编写directive指令中的函数

最后在method中编写onScroll函数,也就是上文中对应的binding.value,在这个函数中我们将会请求更多数据,而Vue就会执行相应v-scroll中的值。


具体的Demo请戳这里