Vue学习—自定义指令

1. Vue内置指令

 

2. 自定义指令directives

参考官方文档: https://cn.vuejs.org/v2/guide/custom-directive.html

2.1 全局注册

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

2.2 局部注册

如果想注册局部指令,组件中也接受一个 directives 的选项:

directives: {
  focus: {
    // 指令的定义
    inserted: function (el) {
      el.focus()
    }
  }
}

然后你可以在模板中任何元素上使用新的 v-focus property,如下:

<input v-focus>

2.3 钩子函数

一个指令定义对象可以提供如下几个钩子函数 (均为可选):

  • bind:只调用一次,指令第一次绑定到元素时调用。在这里可以进行一次性的初始化设置。

  • inserted:被绑定元素插入父节点时调用 (仅保证父节点存在,但不一定已被插入文档中)。

  • update:所在组件的 VNode 更新时调用,但是可能发生在其子 VNode 更新之前。指令的值可能发生了改变,也可能没有。但是你可以通过比较更新前后的值来忽略不必要的模板更新 (详细的钩子函数参数见下)。

  • componentUpdated:指令所在组件的 VNode 及其子 VNode 全部更新后调用。

  • unbind:只调用一次,指令与元素解绑时调用。

接下来我们来看一下钩子函数的参数 (即 elbindingvnode 和 oldVnode)。

2.4 钩子函数参数

指令钩子函数会被传入以下参数:

  • el:指令所绑定的元素,可以用来直接操作 DOM。
  • binding:一个对象,包含以下 property:
    • 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 编译生成的虚拟节点。移步 VNode API 来了解更多详情。
  • oldVnode:上一个虚拟节点,仅在 update 和 componentUpdated 钩子中可用。

除了 el 之外,其它参数都应该是只读的,切勿进行修改。如果需要在钩子之间共享数据,建议通过元素的 dataset 来进行。

 

案例: 定义拖拽指令

参考: https://blog.csdn.net/weixin_37989623/article/details/105458244

定义成去全局指令:

在drag.js 中定义全局指令

import Vue from "vue";
// 使用Vue.directive()定义一个全局指令
// 1.参数一:指令的名称,定义时指令前面不需要写v-
// 2.参数二:是一个对象,该对象中有相关的操作函数
// 3.在调用的时候必须写v-
// 全局自定义拖拽组件
let drag = Vue.directive('drag', {
  //1.指令绑定到元素上回立刻执行bind函数,只执行一次
  //2.每个函数中第一个参数永远是el,表示绑定指令的元素,el参数是原生js对象
  // elementObj 父级元素
  bind(elelementObj) {
    let dragBox = el//获取当前元素
    dragBox.style.position = 'absolute'// 拖拽元素使用定位,脱离文档流
    dragBox.onmousedown = e => {
      //鼠标相对元素的位置
      let disX = e.clientX - dragBox.offsetLeft;
      let disY = e.clientY - dragBox.offsetTop;
      document.onmousemove = e => {
        //鼠标的位置减去鼠标相对元素的位置,得到元素的位置
        let left = e.clientX - disX;
        let top = e.clientY - disY;
        //移动当前元素
        dragBox.style.left = left + 'px';
        dragBox.style.top = top + 'px';
      };
      document.onmouseup = e => {
        //鼠标弹起来的时候不再移动
        document.onmousemove = null;
        //预防鼠标弹起来后还会循环(即预防鼠标放上去的时候还会移动)
        document.onmouseup = null;
        // 对外暴露元素相对于父级位置
        elementObj.value.left = dragBox.style.left;
        elementObj.value.top = dragBox.style.top;
      };
    };
  }
});

export default drag;

 

在main.js 中引入

import drag from './utils/drag';

 使用 v-drag 

<template>
    <div>
        // 使用
        <div class="dragBox">
            <div v-drag="elementPos" class="dragMe"></div>
        </div>
    </div>
</template>

<script>
export default {
    name: 'DragRotateZoom',
    data() {
        return {
            // 元素相对于父级位置
            elementPos: {
                left: null,
                top: null
            }
        }
    },
    watch: {
        elementPos: {
            handler(val) {
                console.log(val, 789) // 实时获取拖拽元素相对于父级位置
            },
            deep: true,
            immediate: true
        }
    }
}
</script>

<style lang="scss" scope>
.demo-item {
    margin-bottom: 10px;
}
.dragBox {
    width: 300px;
    height: 300px;
    background: #ccc;
    position: relative;
    .dragMe {
        cursor: move;
        width: 100px;
        height: 100px;
        background: burlywood;
        display: flex;
        justify-content: center;
        align-items: center;
    }
}
</style>

 

 

 

posted @ 2021-09-29 14:26  CHUNYIN  阅读(90)  评论(0)    收藏  举报