Vue自定义指令的使用详细介绍

目录
  • 1. 概述
  • 2. 钩子函数
  • 3. 自定义全局指令
  • 4. 自定义局部指令
  • 5. 使用自定义指令实现权限管理
  • 6. 使用自定义指令实现表单验证

1. 概述

除了核心功能默认内置的指令,Vue也允许注册自定义指令。有的情况下,对普通 DOM 元素进行底层操作,这时候就会用到自定义指令绑定到元素上执行相关操作。

自定义指令分为:

全局指令和局部指令,当全局指令和局部指令同名时以局部指令为准。

局部指令:只对当前实例(或组件)生效

全局指令:对全部实例(或组件)都生效

2. 钩子函数

自定义指令常用钩子函数:

  1. bind 第一次绑定到元素时调用(初始化)
  2. inserted 被绑定元素插入父节点时调用 (仅保证父节点存在,但不一定已被插入文档中)
  3. update 数据更新时调用
  4. componentUpdated 指令所在组件的 VNode 及其子 VNode 全部更新后调用。
  5. unbind 只调用一次,指令与元素解绑时调用。

指令的钩子会传递以下几种参数:

el:指令绑定到的元素。这可以用于直接操作 DOM。

binding:一个对象,包含以下属性。

  1. value:传递给指令的值。例如在 v-my-directive="1 + 1" 中,值是 2。
  2. oldValue:之前的值,仅在 beforeUpdateupdated 中可用。无论值是否更改,它都可用。
  3. arg:传递给指令的参数 (如果有的话)。例如在 v-my-directive:foo 中,参数是 "foo"
  4. modifiers:一个包含修饰符的对象 (如果有的话)。例如在 v-my-directive.foo.bar 中,修饰符对象是 { foo: true, bar: true }
  5. instance:使用该指令的组件实例。
  6. dir:指令的定义对象。

vnode:代表绑定元素的底层 VNode。

prevNode:之前的渲染中代表指令所绑定元素的 VNode。仅在 beforeUpdateupdated 钩子中可用。

钩子函数可以理解为一个类,类中的构造函数绑定了5个函数(即钩子函数),当我们自定义钩子函数时,就会初始化这个类,然后让我们的相关代码按顺序执行这5个函数。

有关钩子函数更详细的解释,下面这篇文章中的前两个教程写得很通俗易懂,特此推荐:

传送门

钩子函数的执行顺序:

<div id="app1">
    <div v-red v-if="isShow">
        <input type="text" v-model="title">
    </div>
</div>
<script>
    Vue.directive('red', {
        // bind 第一次绑定到元素时调用
        bind(el, bindings) {
            console.log('bind');
        },
        // inserted
        inserted(el, bindings) {
            console.log('inserted');
        },
        // update
        update(el, bindings) {
            console.log('update');
        },
        // componentUpdate
        componentUpdated(el, bindings) {
            console.log('componentUpdated');
        },
        // unbind
        unbind(el, bindings) {
            console.log('unbind');
        },
    })
    const vm1 = new Vue({
        el: '#app1',
        data: {
            isShow: true,
            title: '钩子函数执行顺序'
        }
    })
</script>

程序一执行,当数据源中的数据第一次绑定了元素就会执行bind函数,当绑定元素插入到父元素中,即显示到视图中时,会执行inserted函数:

当我们改变视图,使得数据发生改变时,就会执行updatecomponentUpdated函数:

当我们销毁被绑定元素时,即被绑定元素和数据源解绑,就会触发unbind函数:

3. 自定义全局指令

描述:

全局定义的指令,所有的组件或vue的实例都会生效。

语法:

Vue.directive('指令名称,不需要写v-开头',对象或函数)

Vue.directive('test',{
	bind(el,bind){
		console.log(el)
	}
})

案例:

<div id="app1">
    <div v-red>{{title}}</div>
</div>
<div id="app2">
    <div v-red>标题2</div>
</div>
<script>
	//自定义全局指令
    Vue.directive('red', {
        // bind 第一次绑定到元素时调用
        bind(el, bindings) {
            el.style.cssText = `color:red;font-size:30px`
        }

    })
    const vm1 = new Vue({
        el: '#app1',
        data: {
            isShow: true,
            title: '标题1'
        }
    })
    const vm2 = new Vue({
        el: '#app2',
        data: {
        }
    })
</script>

4. 自定义局部指令

描述:

定义局部指令,只有当前的实例能用。

语法:

new Vue({
	directives: {
		test:{
			bind(el,bind){}
		},
		// bind/update
		test2(el,bind){}
	}
})

案例:

<div id="app1">
    <div v-red>{{title}}</div>
</div>
<div id="app2">
    <div v-red>标题2</div>
</div>
<script>
    const vm1 = new Vue({
        el: '#app1',
        data: {
            isShow: true,
            title: '标题1'
        },
        // 定义局部指令,只有当前的实例能用
        directives: {
            red: {
                // bind它还没有绑定到父元素中,初始化
                bind(el) {
                    el.style.cssText = `color:red;font-size:30px`
                }
            }
        }
    })
    const vm2 = new Vue({
        el: '#app2',
        data: {
        },
        directives: {
            red: {
                bind(el) {
                    el.style.cssText = `color:blue;font-size:30px`
                }
            }
        }
    })
</script>

利用自定义局部指令操作Dom:

<div id="app1">
    <div v-red>{{title}}</div>
</div>
<div id="app2">
    <div v-red>标题2</div>
</div>
<script>
    const vm1 = new Vue({
        el: '#app1',
        data: {
            isShow: true,
            title: '标题1'
        },
        directives: {
            red: {
                // bind表示被绑定元素还没有插入到父元素中
                bind(el) {
                    el.style.cssText = `color:red;font-size:30px`
                    const divDom = document.createElement('div')
                    divDom.innerHTML = '我是标题1的孩子'
                    el.appendChild(divDom)
                },
                // 这时被绑定元素已经插入到父元素中去了,所以可以打印出被绑定元元素的父节点
                inserted(el) {
                    console.log(el.parentNode);
                }
            }
        }
    })
    const vm2 = new Vue({
        el: '#app2',
        data: {
        },
        directives: {
            red: {
                bind(el) {
                    el.style.cssText = `color:blue;font-size:30px`
                }
            }
        }
    })
</script>

注意:在上面的代码中,我们在bind函数中,不能获取当前被绑定元素的父节点,因为此时被绑定元素刚刚初始化,还没有插入到父节点当中。在inserted函数中才能获取被绑定元素的父节点,因为此时元素已经插入到父节点当中去了。

5. 使用自定义指令实现权限管理

目标:

根据地址栏中的数据,决定是否显示 button 按钮。如果地址栏中的 username 的值是 admin 时,就显示 button 按钮,否则不显示。

注意:目标中的显示与不显示,是取决于该 Dom 元素(button 按钮)是否存在,而不是通过 css 来进行显示与隐藏。

代码:

<div id="app1">
    <button v-auth>查看工资</button>
</div>
<script>
    const vm1 = new Vue({
        el: '#app1',
        data: {
            isShow: true,
            title: '标题1'
        },
        directives: {
            auth: {
                // 注意:是否删除按钮的操作,必须在被绑定元素(即当前元素)已经插入父节点(插入到视图)当中后进行
                inserted(el) {
                    // 这是一种比较粗暴的写法,可维护性较低
                    // if (location.search != '?username=admin') {
                    //   el.remove()
                    // }
                    // URLSearchParams它是html5提供的新的Api方法,用于获取url地址中的search转为对象
                    let urlSearch = new URLSearchParams(location.search)
                    // 这样的写法可维护性较高,假如显示元素的权限还需要给到 张三 用户,则直接修改判断条件中的表达式即可
                    if (urlSearch.get('username') != 'admin') {
                        // 以前兼容性更好的写法,但是现在可以不管
                        // el.parentNode.removeChild(el)
                        el.remove()
                    }
                }
            }
        }
    })
</script>

6. 使用自定义指令实现表单验证

首先我们先完成验证手机号的功能。

目标:

在初始化(在 bind 函数中进行)和更新数据(在 update 函数中进行)时都要进行手机号的验证。

思路:

先获取手机号(收集数据),再用正则表达式判断输入框中的手机号是否合法,如果合法则手机号显示黑色,如果不合法则手机号显示红色。

代码:

<div id="app">
    <div>
        <input type="text" v-phone="phone" v-model="phone">
    </div>
</div>
<script>
    Vue.directive('phone', {
        // 方法1:直接通过dom来完成数据的收集
        // update(el) {
        //   console.log(el.value);
        // }
        // 方法2:可以通过传值的方式(钩子函数)完成数据收集
        bind(el, { value }) {
            // 手机号码
            let reg = /^1[3-9]\d{9}$/
            if (!reg.test(value)) {
                // 不合法
                el.style.color = 'red'
            } else {
                el.style.color = 'black'
            }
        },
        update(el, { value }) {
            // 手机号码
            let reg = /^1[3-9]\d{9}$/
            if (!reg.test(value)) {
                // 不合法
                el.style.color = 'red'
            } else {
                el.style.color = 'black'
            }
        }
    })
    const vm1 = new Vue({
        el: '#app',
        data: {
            phone: '13525125121',
        }
    })
</script>

在上面代码中,通过钩子函数完成数据获取与验证,代码重复率高,所以在钩子函数部分,我们可以简写成下面这种方式:

Vue.directive('phone', (el, { value }) => {
    // 手机号码
    let reg = /^1[3-9]\d{9}$/
    if (!reg.test(phone)) {
        // 不合法
        el.style.color = 'red'
    } else {
        el.style.color = 'black'
    }
})

注意:简写方式就是自定义指令语法中,第二个参数是函数的写法。自定义指令的简写,指的是将 bind 函数和 update 函数封装起来的写法。

在上面的基础上,我们再加上验证错误信息的显示:

<!DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="UTF-8">
        <meta http-equiv="X-UA-Compatible" content="IE=edge">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <title>vue学习使用</title>
        <script src="./js/vue.js"></script>
    </head>
    <body>
        <div id="app">
            <div>
                <input type="text" v-phone="phone" v-model="phone">
            </div>
        </div>
        <script>
            Vue.directive('phone', (el, { value }) => {
                // 手机号码
                let reg = /^1[3-9]\d{9}$/
                if (!reg.test(value)) {
                    // 不合法
                    el.style.color = 'red'
                    // 没有 span 标签时,就创建 span 标签
                    if (!el.nextSibling) {
                        const spanDom = document.createElement('span')
                        spanDom.innerHTML = '不合法,修改一下'
                        // 这里是防止初始化时数据就不合法,导致被绑定元素不能成功插入到父结点中
                        // el.parentNode?.appendChild(spanDom)
                        // 上面的写法要求的浏览器版本较高,下面的写法兼容性更好
                        el.parentNode && el.parentNode.appendChild(spanDom)
                    }
                } else {// 输入正确时,移除 span 标签
                    el.style.color = 'black'
                    el.nextSibling && el.nextSibling.remove()
                }
            })
            const vm1 = new Vue({
                el: '#app',
                data: {
                    phone: '13525125121',
                    phoneMsg: ''
                }
            })
        </script>
    </body>
</html>

最后,我们使用模块化的的思路,将案例完善一下:

<!DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="UTF-8">
        <meta http-equiv="X-UA-Compatible" content="IE=edge">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <title>vue学习使用</title>
        <script src="./js/vue.js"></script>
    </head>
    <body>
        <div id="app">
            <div>
                <!-- 这种写法的 value 值直接就是 phone -->
                <!-- <input type="text" v-validate="phone" v-model="phone"> -->
                <input type="text" v-validate.phone v-model="phone">
            </div>
            <div>
                <input type="text" v-validate.email v-model="email">
            </div>
            <div>
                <!-- "{len:3,msg:'长度过长'}":v-validate指令的value值 -->
                <input type="text" v-validate.str="{len:3,msg:'长度过长'}" v-model="str">
            </div>
        </div>
        <script>
            // 在对象里存方法
            const validateMethod = {
                phone(el) {
                    // 手机号码
                    let reg = /^1[3-9]\d{9}$/
                    if (!reg.test(el.value)) {
                        // 不合法
                        el.style.color = 'red'
                        if (!el.nextSibling) {
                            const spanDom = document.createElement('span')
                            spanDom.innerHTML = '不合法,修改一下'
                            // el.parentNode?.appendChild(spanDom)
                            el.parentNode && el.parentNode.appendChild(spanDom)
                        }
                    } else {
                        el.style.color = 'black'
                        el.nextSibling && el.nextSibling.remove()
                    }
                    console.log('phone');
                },
                email(el, value) {
                    console.log('email')
                },
                str(el, value) {
                    // 这里这个判断是容错处理,也可以不写。因为我们上面的代码中给 value传值了
                    // 如果当前封装好的代码(当作组件)给别人使用的话,使用者可能不穿值
                    if (value) {
                        if (el.value.length > value.len) {
                            if (!el.nextSibling) {
                                const spanDom = document.createElement('span')
                                spanDom.innerHTML = value.msg
                                // 防止初始化数据不合法,父节点不存在
                                el.parentNode?.appendChild(spanDom)
                            }
                        } else {
                            el.nextSibling?.remove()
                        }
                    }
                }
            }
            Vue.directive('validate', (el, { value, modifiers }) => {
                // modifiers:一个包含修饰符的对象 (如果有的话)。
                // console.log(Object.keys(modifiers))===phone
                Object.keys(modifiers).forEach(name => {
                    // 调用对象中的方法
                    validateMethod[name](el, value)
                })
            })
            const vm1 = new Vue({
                el: '#app',
                data: {
                    phone: '13525125121',
                    email: 'aa@aa.com',
                    str: 'aaa'
                },
                methods: {
                }
            })
        </script>
    </body>
</html>

注意:

v-validate="phone"的 value 值是数据源中的 phone,v-validate.phone的 value 值是 undefined,v-validate.str="{len:3,msg:'长度过长'}"的 value 值是{len:3,msg:'长度过长'}

到此这篇关于Vue自定义指令的使用详细介绍的文章就介绍到这了,更多相关Vue自定义指令内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • Vue自定义指令中无法获取this的问题及解决

    目录 自定义指令中无法获取this 解决方法 Vue使用this的这几个坑你都知道吗 一.普通函数 二.Vue中的this 自定义指令中无法获取this 问题 最近在使用自定义指令时遇到一个问题,我想在指令里通过this直接去访问vue实例数据,但是显示未定义,经大佬提醒,里面的this很可能不是指向vue实例 解决方法 在函数里增加第三个参数vnode,vnode.context就是指向当前的vue实例 总结 指令里的this不是指向vue实例,可以使用vnode.context获取this

  • VUE中的自定义指令钩子函数讲解

    目录 自定义指令钩子函数 自定义指令 先上官方解释 小贴士 钩子函数运行顺序 自定义指令钩子函数 自定义指令 除了VUE 内置指令外,VUE也支持我们自定义注册指令,分为局部和全局注册 但这些想必大家都不陌生,其中官方API也是写的明明白白 官方API点这里 而且自定义指令也会极大程度上帮助我们日常的编程,但这是很有意思的事情出现了,就是钩子函数,很多老铁都弄不明白这五个函数的具体区别 先上官方解释 bind:只调用一次,指令第一次绑定到元素时调用.在这里可以进行一次性的初始化设置. inser

  • vue自定义指令实现元素滑动移动端适配及边界处理

    目录 效果演示 核心属性 实现思路 代码 注意 自定义指令this指向问题 滑动后点击事件被触发 移动端滑动问题 效果演示 核心属性 Element.clientWidth:元素可视宽度. Element.clientHeight:元素可视高度. MouseEvent.clientX:鼠标相对于浏览器左上顶点的水平坐标. MouseEvent.clientY:鼠标相对于浏览器左上顶点的垂直坐标. Touch.clientX:触点相对于浏览器左上顶点的水平坐标(移动端属性). Touch.clie

  • Vue自定义指令v-focus实例详解

    目录 前言 自定义指令 directive 项目实际使用 技术背景 实际操作 优势 setTimeout(fn, 0) 永远的神 $nextTick(callback) 小结 前言 本文直接参考vue2.0官方文档, 并演示博主项目中的使用 自定义指令 directive 除了核心功能默认内置的指令 (v-model 和 v-show),Vue 也允许注册自定义指令.注意,在 Vue2.0 中,代码复用和抽象的主要形式是组件.然而,有的情况下,你仍然需要对普通 DOM 元素进行底层操作,这时候就

  • vue中的for循环以及自定义指令解读

    目录 vue for循环及自定义指令 v-for 自定义指令 vue自定义指令动态参数 通过自定义指令中的修饰符的key作为值,更改显示的颜色 vue for循环及自定义指令 v-for 1.v-for用来循环的数组怎么发生变化可以被vue检测到: push.pop.shift.unshift.splice.sort.reverse等方法可以被检测到 vue对于这些方法的处理是重写了这些方法,并在最后会触发一次notify方法来通知这个array已经发生变化 vue还增加了两个方法来观测arra

  • vue3使用自定义指令实现el dialog拖拽功能示例详解

    目录 实现el-dialog的拖拽功能 通过自定义指令实现拖拽功能 实现拖拽功能 使用方式 实现el-dialog的拖拽功能 这里指的是 element-plus 的el-dialog组件,一开始该组件并没有实现拖拽的功能,当然现在可以通过设置属性的方式实现拖拽. 自带的拖拽功能非常严谨,拖拽时判断是否拖拽出窗口,如果出去了会阻止拖拽. 如果自带的拖拽功能可以满足需求的话,可以跳过本文. 通过自定义指令实现拖拽功能 因为要自己操作dom(设置事件),所以感觉还是使用自定义指令更直接一些,而且对原

  • Vue自定义指令的使用详细介绍

    目录 1. 概述 2. 钩子函数 3. 自定义全局指令 4. 自定义局部指令 5. 使用自定义指令实现权限管理 6. 使用自定义指令实现表单验证 1. 概述 除了核心功能默认内置的指令,Vue也允许注册自定义指令.有的情况下,对普通 DOM 元素进行底层操作,这时候就会用到自定义指令绑定到元素上执行相关操作. 自定义指令分为: 全局指令和局部指令,当全局指令和局部指令同名时以局部指令为准. 局部指令:只对当前实例(或组件)生效 全局指令:对全部实例(或组件)都生效 2. 钩子函数 自定义指令常用

  • vue.js指令和组件详细介绍及实例

    大家好,本文给各位做一下vue.js一个最基本的概念介绍. vue.js 指令 <div id="app"> <div v-text="message"></div> </div> var app = new Vue({ el: '#app', data: { message: 'Hello Vue!' } }) 这个例子我们会得到,v-text所在的div元素的内部插入了'Hello Vue!'这段字符串,那么我们为

  • Vue自定义指令详细

    目录 1.背景 2.局部自定义指令 3.全局自定义指令 4.1 自定义指令钩子函数 4.2 钩子函数参数 4.3 动态指令传参 5.拓展 1.背景 最近在面试找工作,然后面试官就问了有关自定义指令的问题,然后由于平时自定义指令用的不多,只是看过官方文档大概知道需要用到Vue.directive来自定义指令:面试结束之后,立刻就去网上找有关自定义指令的资料,发现自定义指令还是有很多学问的,于是就想写个博客记录下也是鞭策自己,要多尝试,多学习!!! 这是官方文档有关自定义指令的模块:自定义指令包括全

  • vue中自定义指令directive的详细指南

    目录 一. 什么是自定义指令 二. 如何自定义指令 钩子函数 三.应用场景 输入框防抖 图片懒加载 一键 Copy的功能 拖拽 总结 一. 什么是自定义指令 我们看到的v-开头的行内属性,都是指令,不同的指令可以完成或实现不同的功能,对普通 DOM元素进行底层操作,这时候就会用到自定义指令.除了核心功能默认内置的指令 (v-model 和 v-show),Vue 也允许注册自定义指令 指令使用的几种方式: //会实例化一个指令,但这个指令没有参数 `v-xxx` // -- 将值传到指令中 `v

  • 关于Vue 自定义指令实现元素拖动的详细代码

    昨天在做的一个功能时,同时弹出多个框展示多个表格数据. 这些弹出框可以自由拖动.单独的拖动好实现,给元素绑定 mousedowm 事件. 这里就想到了 Vue 里面自定义指令来实现. 一.自定义指令 在使用自定义指令之前,先对自定义指令有一定的了解.从以下几个方面着手: 1.自定义指令定义范围 全局注册和组件内注册(注册的范围根据实际业务需求来) // 注册一个全局指令,可以在任何组件使用 Vue.directive('focus',{ // 当被绑定的元素插入 DOM 时 inserted:

  • Vue自定义指令介绍(2)

    Vue指令 Vue的指令以v-开头,作用在HTML元素上,将指令绑定在元素上,给绑定的元素添加一些特殊行为. 例如: <h1 v-if="yes">Yes</h1> 其中,v-是Vue的标识,if是指令ID,yes是expression.yes是MVVM中的VM即ViewModel,当它的值发生变化,就会触发指令,改变View视图的显示. expression还可以使用内联的模式,任何依赖的属性发生变化时都会触发指令的执行.如: <h1 v-if=&quo

  • 基于Vue自定义指令实现按钮级权限控制思路详解

    思路: 登录:当用户填写完账号和密码后向服务端验证是否正确,验证通过之后,服务端会返回一个token,拿到token之后(我会将这个token存贮到sessionStorage中,保证刷新页面后能记住用户登录状态),前端会根据token再去拉取一个 user_info 的接口来获取用户的详细信息(如用户权限,用户名等等信息). 权限验证:通过token获取用户对应的 role,自定义指令,获取路由meta属性里btnPermissions( 注: meta.btnPermissions是存放按钮

  • Vue自定义指令拖拽功能示例

    下面给大家分享vue自定义指令拖拽功能代码,具体代码如下所示: <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>实例方法</title> <meta name="viewport" content="width=device-width, initial-scale=1

  • vue自定义指令directive实例详解

    下面给大家介绍vue自定义指令directive,具体内容如下所示: 官网截图实例 vue除了一些核心的内部定义的指令(v-model,v-if,v-for,v-show)外,vue也允许用户注册自己的一些功能性的指令,有时候你实在是要对Dom操作,这个时候是自定义指令最合适的了. 来直接看例子:当页面加载时使得元素获得焦点(autofocus 在移动版 Safari 是不支持的),就是当页面加载好了,不做任何的操作使得表单自动获得焦点,光标自动在某个表单上代码如下: Vue.directive

  • 使用vue自定义指令开发表单验证插件validate.js

    这段时间在进行一个新项目的前期搭建,新项目框架采用vue-cli3和typescirpt搭建.因为项目比较轻量,所以基本没有使用额外的ui组件,有时候我们需要的一些基础组件我就直接自己开发了.今天就来介绍一下如何利用vue的自定义指令directive来开发一个表单验证插件的过程. 1.vue插件开发 关于vue的插件开发,官方文档里有很清晰的说明,详情可以去阅读开发文档.我自己开发的表单验证插件validate.ts和loading,messageBox插件都是利用了这种方式.今天先来看表单验

随机推荐