vue自定义指令

273 阅读3分钟

这是我参与8月更文挑战的第9天,活动详情查看:8月更文挑战

自定义指令

  • 有些情况下,你可能需要对普通 DOM 元素进行底层操作,这时候就会用到自定义指令。也就是说,自定义指令是操作底层DOM元素的。

比方说:打开页面的时候自动聚焦到某个input框,通常的做法是 定义ref,并在mounted中调用该input框的focus方法。当然,我们也可以用自定义指令:

// 注册一个全局自定义指令 `v-focus` 
Vue.directive('focus', { 
    // 当被绑定的元素插入到 DOM 中时…… 
    inserted: function (el) { 
        // 聚焦元素 el.focus() 
    } 
})

// 定义一个局部的指令,可以在组件内部的directives选项下定义
directives: { 
    focus: { 
        // 指令的定义 
        inserted: function (el) { 
            el.focus() 
        } 
    } 
}

// 使用
<input v-focus>

自定义指令的钩子函数

  • bind只调用一次,指令第一次 绑定 到元素时调用。在这里可以进行一次性的初始化设置。
  • inserted:被绑定元素插入父节点时调用 (仅保证父节点存在,但不一定已被插入文档中)。
  • update:所在组件的 VNode 更新时调用,但是可能发生在其子 VNode 更新之前。指令的值可能发生了改变,也可能没有。
  • componentUpdated:指令所在组件的 VNode 及其子 VNode 全部更新后调用。
  • unbind:只调用一次,指令与元素解绑时调用。

指令钩子函数会被传入的参数

  • el:指令所绑定的元素,可以用来直接操作 DOM。
  • binding:是一个对象,包含以下属性:
    • name:指令名,不包括 v- 前缀。
    • value:指令的绑定值,例如:v-my-directive="1 + 1" 中,绑定值为 2
    • oldValue:指令绑定的前一个值,仅在 update 和 componentUpdated 钩子中可用。无论值是否改变都可用。
    • expression:字符串形式的指令表达式。例如 v-my-directive="1 + 1" 中,表达式为 "1 + 1"
    • arg:传给指令的参数,可选。例如 v-my-directive:foo 中,参数为 "foo"
    • modifiers:一个包含修饰符的对象。例如:v-my-directive.foo.bar 中,修饰符对象为 { foo: true, bar: true }
  • vnode:Vue 编译生成的虚拟节点。
  • oldVnode:上一个虚拟节点,仅在 update 和 componentUpdated 钩子中可用。 注意: 除了el之外,其它参数都应该是只读的,切勿进行修改

动态的指令参数

  • 指令的参数可以是动态的。例如,在 v-mydirective:[argument]="value" 中,argument 参数可以根据组件实例数据进行更新!

实现一个vue的列表滚动加载 自定义指令

都知道,在开发过程中会涉及到很多的列表页面,而大部分列表页是需要分页加载的,那么这时候我们在PC段通常是采用paganation组件,进行分页处理。在移动端则更多的是采用滚动加载。下面我们就来实现以下滚动加载吧。

  1. 在单文件组件的directives选项下,创建loadMore指令;
// 注意:但文件组件的vue格式有很多种写法,此处是其中一种
export default Vue.extend({
    directives: {
        loadmore: {}
    }
})
  1. 接下来我们将 指令 绑定到 我们需要的元素上;
loadmore: {
    // 指令第一次 绑定 到元素时,调用bind钩子,
    bind(el, binding) {
        
    },
}
  1. 在指令第一次绑定到元素上时,我们对需要滚动加载的元素添加滚动事件;
loadmore: {
    // 指令第一次 绑定 到元素时,调用bind钩子,
    bind(el, binding) {
        let dom = el.querySelector('.bg');
        dom &&
          dom.addEventListener('scroll', function () {
            const condition = this.scrollHeight - this.scrollTop <= this.clientHeight;
            if (condition) {
              // 因为我们指令绑定的是一个加载更多的方法,所以此处调用绑定的方法
              binding.value();
            }
          });
    },
    unbind(el, binding) {
        let dom = el.querySelector('.bg');
        dom && dom.removeEventListener('scroll')
    },
}
  1. 我们将定义好的自定义指令绑定到元素上;
<template>
    <div class="page" v-loadmore="loadMoreData">
        <div class="bg"></div>
    </div>
</template>
<script>
    export default Vue.extend({
        methods: {
            // 加载更多的方法
            loadMoreData() {
              // 拿到此时页面中的数据总数
              let datalength = this.pagingResult.pageNo * this.pagingResult.pageSize;
              // 接口返回的实际数据总数
              let rowTotal = this.pagingResult.total;
              // 如果接口的实际总数大于 页面已拿到的数据总数,则去加载更多数据
              if (rowTotal > datalength) {
                this.pagingResult.pageNo += 1;
                // 调用函数 获取数据
                this.getList();
              }
            },
        }
    })
</script>
  1. 至此,我们的一个简单的自定义指令已经开发完成了。

写在最后

如果写的有的不对的,或者能够改进的地方,欢迎大佬们评论区指出。感谢🙏🙏🙏