vue2自定义指令

vue自定义指令

vue自定义指令

vue的自定义指令有很多不错的小功能

  1. 仅能输入数字

  2. 元素外部点击收起

  3. 防止重复提交

  4. 输入字符长度限制

  5. 渲染html

1.仅能输入数字 numberOnly常用于输入金额或分数场合,不能输入负数,最多可以输入两位小数

 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

    Vue.directive('numberOnly', {
        bind(el, binding, vnode) {
            let input = vnode.elm;
            input.addEventListener('compositionstart', () => {
                vnode.inputLocking = true
            })
            input.addEventListener('compositionend', () => {
                vnode.inputLocking = false
                input.dispatchEvent(new Event('input'))
            })
            input.addEventListener('input', () => {
                if(vnode.inputLocking) {
                    return;
                }
                let oldValue = input.value;
                let newValue = input.value;
                newValue = newValue.replace(/[^\d.]/g, '');
                newValue = newValue.replace(/^\./g, '');
                newValue = newValue.replace('.', '$#$').replace(/\./g, '').replace('$#$', '.');
                newValue = newValue.replace(/^(\-)*(\d+)\.(\d\d).*$/, '$1$2.$3')
                if(newValue) {
                    let arr = newValue.split('.')
                    newValue = Number(arr[0]) + (arr[1] === undefined ? '' : '.' + arr[1]) // 去掉开头多余的0
                }
                // 判断是否需要更新,避免进入死循环
                if(newValue !== oldValue) {
                    input.value = newValue
                    input.dispatchEvent(new Event('input')) // 通知v-model更新
                }
            })
            // input 事件无法处理小数点后面全是零的情况 因为无法确定用户输入的0是否真的应该清除,如3.02。放在blur中去处理
            input.addEventListener('blur', () => {
                let oldValue = input.value;
                let newValue = input.value;
                if(newValue) {
                    newValue = Number(newValue).toString()
                }
                // 判断是否需要更新,避免进入死循环
                if(newValue !== oldValue) {
                    input.value = newValue
                    input.dispatchEvent(new Event('input')) // 通知v-model更新
                }
            })
        }
    })

2.元素外部点击收起 clickOutSide带参数使用,参数为点击外部执行的方法,示例v-clickout-side=“function(){}” 表示点击外部触发的事件常见的应用场景是,点击div弹框外隐藏弹框。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24

    Vue.directive('clickOutSide', {
        bind(el, binding, vnode) {
            function documentHandler(e) {
                // 这里判断点击的元素是否是本身,是本身,则返回
                if (el.contains(e.target)) {
                    return false;
                }
                // 判断指令中是否绑定了函数
                if (binding.expression) {
                    // 如果绑定了函数 则调用那个函数,此处binding.value就是handleClose方法
                    binding.value(e);
                }
            }
            // 给当前元素绑定个私有变量,方便在unbind中可以解除事件监听
            el.__vueClickOutside__ = documentHandler;
            document.addEventListener('click', documentHandler);
        },
        update() {},
        unbind(el, binding) { // 解除事件监听
            document.removeEventListener('click', el.__vueClickOutside__);
            delete el.__vueClickOutside__;
        }
    })

3.防止重复提交 preventDoubleClick发起后端请求时使用,防止重复点击。对于耗时较长的请求使用。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13

    Vue.directive('preventDoubleClick', {
        inserted (el, binding) {
            el.addEventListener('click', () => {
                if (!el.disabled) {
                    el.disabled = true
                    setTimeout(() => {
                        el.disabled = false
                    }, binding.value '' 3000)
                }
            })
        }
    })

4.输入字符长度限制 maxlength输入框使用,用于限制输入字数限制,仅限制字数,如果需要更多复杂功能,可以使用el-input

 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

    Vue.directive('maxlength', {
        bind(el, binding, vnode) {
            let input = vnode.elm;
            let max = binding.value;
            input.addEventListener('compositionstart', () => {
                vnode.inputLocking = true
            })
            input.addEventListener('compositionend', () => {
                vnode.inputLocking = false
                input.dispatchEvent(new Event('input'))
            })
            input.addEventListener('input', () => {
                if(vnode.inputLocking) {
                    return;
                }
                let oldValue = input.value;
                let newValue = input.value;
                if(newValue.length > length) {
                    newValue = newValue.substring(0,max);
                }
                // 判断是否需要更新,避免进入死循环
                if(newValue !== oldValue) {
                    input.value = newValue
                    input.dispatchEvent(new Event('input')) // 通知v-model更新
                }
            })
        }
    })

5.渲染html类似于vue自带的v-html指令,v-html使用innerHTML在当前元素下插入html内容,会保留当前dom元素的标签。这个指令使用outerHTML,不在保留原有元素的标签,能够更灵活的应用。详见链接

1
2
3
4
5
6
7
8

    Vue.directive('oHtml', {
        inserted: (el, dir) => {
            if (dir.value) {
                el.outerHTML = dir.value
            }
        }
    })
Licensed under CC BY-NC-SA 4.0
最后更新于 Jun 07, 2025 02:36 UTC
comments powered by Disqus
使用 Hugo 构建
主题 StackJimmy 设计