vue自定义指令

一、什么是自定义指令

vue官方提供很多指令,如:v-model,v-show,v-if,v-if等,他们都以v-开头。当这些指令不能满足我们实际开发需求时,我们还可以自定义指令。自定义指令主要分为全局自定义指令和局部自定义指令。

二、全局自定义指令directive

在main.js中写全局自定义指令

1

2

3

4

5

6

// vue2写法 自动获取焦点

Vue.directive('focus', {

  inserted: function (el) {

    el.focus()

  }

}) 

// vue3 写法 这是一个 Vue 插件对象。当通过 app.use() 使用该插件时,会自动调用 install 方法

// 定义插件
const AuthorityPlugin = {
  install(app) {
    // 注册一个叫 v-focus的指令
    app.directive('focus', {
      mounted:(el, binding)=> {
   el.focus()
      }
    });
  }
};

// 在 main.js 中使用插件
app.use(AuthorityPlugin);

三、局部自定义指令directives

可以在任意组件中定义自定义指令,directives是一个对象,他的每一个属性就只一个自定义指令,这里定义了一个focus指令。

1

2

3

4

5

6

7

directives: {

  focus: {

    inserted: function (el) {

      el.focus()

    }

  }

}

四、自定义指令的调用

和普通指令的使用方式一样v-自定义指令名称

如 v-focus

五、自定义指令

有以下五个钩子函数:

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

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

  • mounted:当指令绑定的元素插入到其父节点中的时候调用。注意这里的描述与 Vue 2 中的 inserted 钩子功能相同 vue3。

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

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

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

每个钩子函数有以下参数:

  • 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 编译生成的虚拟节点。
  • oldVnode:上一个虚拟节点,仅在 update 和 componentUpdated 钩子中可用。

钩子应用场景

  • bind: 初始化数据或者配置。
  • inserted: 添加DOM操作,例如添加第三方库所需的元素属性 vue2 钩子。
  • mounted:当指令绑定的元素插入到其父节点中的时候调用。注意这里的描述与 Vue 2 中的 inserted 钩子功能相同 vue3 钩子。
  • update: 根据新的值更新DOM,适合需要响应式更新的场景。
  • componentUpdated: 在所有相关联的DOM更新完成后进行调整,避免在更新过程中出现不完整的状态。
  • unbind: 清理工作,如解除事件绑定或清除定时器等。

通过这些钩子函数,你可以非常灵活地控制自定义指令的行为和生命周期,实现各种复杂的交互效果和功能。

注意:bind和insert都只调用一次;bind在insert前执行,也就是bind在dom树绘制前调用,insert在dom树绘制后调用;涉及dom操作的,我们一般都用insert,如自动获取焦点指令,只能用insert函数

六、自定义指令传参

1

<div v-test:[data1]>这是测试页。。。。</div>

可以用binding.arg去接收" : "后的参加参数,这里传递了data1这个变量,data1必须用[]包裹,否则就是‘data1’这个字符串,[ ]中只能传递一个变量,多个变量可以用对象或数组组装。binding.value去接收"="后的参数,这里是个函数所以用bingding.value()去调用。

1

2

3

4

5

6

7

8

9

10

<div v-test:[data1]='func'>这是测试页。。。。</div>

test: {

    inserted(el, binding, vnode) {

        // 获取data1得参数

        console.log('test',binding.arg);

        // 执行传递的函数

        binding.value({success: true,data:{}});

    },

}

七、常见自定义指令

 1、拖拽

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

dragV: {

    bind(drag, binding, vNode) {

        drag.style.position = 'absolute';

        drag.style.zIndex = '9999';

        //当鼠标按下时

        drag.onmousedown = e => {

            //做到浏览器兼容

            e = e || window.event 

            let diffX = e.clientX - drag.offsetLeft

            let diffY = e.clientY - drag.offsetTop

            //当拉着box移动时

            document.onmousemove = e => {

                // 浏览器兼容

                e = e || window.event;

                let left = e.clientX - diffX;

                let top = e.clientY - diffY;

                drag.style.left = left + 'px';

                drag.style.top = top + 'px';

            }

            // 当鼠标抬起时

            document.onmouseup = function() {

                this.onmousemove = null

                this.onmouseup = null

            }

        }

    }

},

2、防抖

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

<div v-debounce:[time]="debounceFunc">这是测试页。。。。</div>

debounce:{

    inserted(el, binding) {

        let timer;

        let delay = binding.arg || 500;

        el.addEventListener('click', () => {

            if (timer) {

                clearTimeout(timer)

            }

            timer = setTimeout(() => {

                binding.value()

            }, delay)

        })

    },

}

八. 应用场景

8.1 自动获取焦点(官方示例)

1

2

3

4

5

6

7

8

// 注册一个全局自定义指令 `v-focus`

Vue.directive('focus', {

  // 当被绑定的元素插入到 DOM 中时……

  inserted: function (el) {

    // 聚焦元素

    el.focus()

  }

})

8.2 一键 Copy的功能

  • 首先建一个 js 文件(v-copy.js)。定义一个对象。( 指令实际就是一个对象 )

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

import { Message } from 'ant-design-vue';

const vCopy = { // 名字爱取啥取啥

  /*

    bind 钩子函数,第一次绑定时调用,可以在这里做初始化设置

    el: 作用的 dom 对象

    value: 传给指令的值,也就是我们要 copy 的值

  */

  bind(el, { value }) {

    el.$value = value; // 用一个全局属性来存传进来的值,因为这个值在别的钩子函数里还会用到

    el.handler = () => {

      if (!el.$value) {

      // 值为空的时候,给出提示,我这里的提示是用的 ant-design-vue 的提示,你们随意

        Message.warning('无复制内容');

        return;

      }

      // 动态创建 textarea 标签

      const textarea = document.createElement('textarea');

      // 将该 textarea 设为 readonly 防止 iOS 下自动唤起键盘,同时将 textarea 移出可视区域

      textarea.readOnly = 'readonly';

      textarea.style.position = 'absolute';

      textarea.style.left = '-9999px';

      // 将要 copy 的值赋给 textarea 标签的 value 属性

      textarea.value = el.$value;

      // 将 textarea 插入到 body 中

      document.body.appendChild(textarea);

      // 选中值并复制

      textarea.select();

      // textarea.setSelectionRange(0, textarea.value.length);

      const result = document.execCommand('Copy');

      if (result) {

        Message.success('复制成功');

      }

      document.body.removeChild(textarea);

    };

    // 绑定点击事件,就是所谓的一键 copy 啦

    el.addEventListener('click', el.handler);

  },

  // 当传进来的值更新的时候触发

  componentUpdated(el, { value }) {

    el.$value = value;

  },

  // 指令与元素解绑的时候,移除事件绑定

  unbind(el) {

    el.removeEventListener('click', el.handler);

  },

};

export default vCopy;

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值