位置: IT常识 - 正文

Vue自定义指令(含常用8种指令封装)(vue自定义指令生命周期)

编辑:rootadmin
Vue自定义指令(含常用8种指令封装) 基本概念

推荐整理分享Vue自定义指令(含常用8种指令封装)(vue自定义指令生命周期),希望有所帮助,仅作参考,欢迎阅读内容。

文章相关热门搜索词:vue自定义指令两种方式,vue自定义指令控制按钮权限,vue自定义指令生命周期,vue自定义指令生命周期,vue自定义指令两种方式,vue自定义指令,vue自定义指令钩子函数,vue自定义指令构造函数,内容如对您有帮助,希望把文章链接给更多的朋友!

一、自定义指令是用来操作dom的,尽管vue推崇数据驱动试图的理念,但并非所又情况都适合数据驱动。自定义指令就是一种有效的补充和扩展,不仅仅可用于定义任何dom操作,并且是可以复用的‘

比如谷歌图片的加载做的非常优雅,在图片未完成加载前,用随机的背景色占位背景图片加载晚成后才直接渲染出来。用自定义只能怪可以非常方便的实现这个功能。

Vue 自定义指令有全局注册和局部注册两种方式。先来看看注册全局指令的方式,通过 Vue.directive( id, [definition] ) 方式注册全局指令。然后在入口文件中进行 Vue.use() 调用。

全局:

比如一个input自动聚焦的例子:在main.js中写入以下内容

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

局部:

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

使用的时候要在自定义的指令前面加上v-,然后你可以在模板中任何元素上使用新的 v-focus

<input v-focus></input> 钩子函数

指令定义函数提供了几个钩子函数(可选,执行顺序排序)。

bind:只调用一次,指令第一次绑定到元素时调用,可以用这个钩子函数定义一个在绑定时执行一次的初始化动作。

inserted:被绑定的元素插入父节点时调用(父节点存在即可调用,不必存在于document中)。

update:被绑定元素所在的模板更新时调用,而不论绑定值是否变化。通过比较更新前后的绑定值,可以忽略不必要的模板更新。

componentUpdated:被绑定元素所在模板完成一次更新周期时调用。

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

钩子函数的参数主要有以下几项

el:指令所绑定的元素,可以用来直接操作DOM。

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

name:指令名,不包括v-前缀。

value:指令的绑定值,例如v-my-directive=“1+1”,value的值是2。

oldValue:指令绑定的前一个值,仅在update和componentUpdated钩子中可用,无论值是否改变都可用。

expression:绑定值的表达式或变量名,例如v-my-directive=“1+1”,expression的值是"1+1"。

arg:传给指令的参数,例如v-my-directive:foo,arg的值是"foo"。

modifiers:一个包含修饰符的对象,例如v-my-directive.foo.bar,修饰符对象modifiers的值是{foo:true,bar:true}。

vnode:Vue编译生成的虚拟节点。

oldVnode:上一个虚拟节点,仅在update和componentUpdated钩子中可用。

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

<div v-demo="{ color: 'white', text: 'hello!' }"></div><script>Vue.directive('demo', function (el, binding) {console.log(binding.value.color) // "white"console.log(binding.value.text) // "hello!"})</script>

一些自定义指令的应用场景:

防抖、图片懒加载、一键 Copy的功能、拖拽、页面水印、权限校验、输入框自动聚焦、相对时间转换、下拉菜单

批量注册指令

新建 directives/index.js 文件

import copy from './copy'import longpress from './longpress'// 自定义指令const directives = {copy,longpress,}export default {install(Vue) {Object.keys(directives).forEach((key) => {Vue.directive(key, directives[key])})},}

在 main.js 引入并调用

import Vue from 'vue'import Directives from './JS/directives'Vue.use(Directives)下面分享几个实用的 Vue 自定义指令

复制粘贴指令 v-copy

长按指令 v-longpress

输入框防抖指令 v-debounce

禁止表情及特殊字符 v-emoji

图片懒加载 v-LazyLoad

权限校验指令 v-premission

实现页面水印 v-waterMarker

拖拽指令 v-draggable

1、v-copy

需求:

实现一键复制文本内容,用于鼠标右键粘贴。

思路:

动态创建 textarea 标签,并设置 readOnly 属性及移出可视区域

将要复制的值赋给 textarea 标签的 value 属性,并插入到 body

选中值 textarea 并复制

将 body 中插入的 textarea 移除

在第一次调用时绑定事件,在解绑时移除事件

const copy = {bind(el, { value }) {el.$value = valueel.handler = () => {if (!el.$value) {// 值为空的时候,给出提示。可根据项目UI仔细设计console.log('无复制内容')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()const result = document.execCommand('Copy')if (result) {console.log('复制成功') // 可根据项目UI仔细设计}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 copy

使用:

给 Dom 加上 v-copy 及复制的文本即可

<template><button v-copy="copyText">复制</button></template><script>export default {data() {return {copyText: 'a copy directives',}},}</script>2、v-longpress

需求:

实现长按,用户需要按下并按住按钮几秒钟,触发相应的事件

思路:

Vue自定义指令(含常用8种指令封装)(vue自定义指令生命周期)

创建一个计时器, 2 秒后执行函数

当用户按下按钮时触发 mousedown 事件,启动计时器;用户松开按钮时调用 mouseout 事件。

如果 mouseup 事件 2 秒内被触发,就清除计时器,当作一个普通的点击事件

如果计时器没有在 2 秒内清除,则判定为一次长按,可以执行关联的函数。

在移动端要考虑 touchstart,touchend 事件

const longpress = {bind: function (el, binding, vNode) {if (typeof binding.value !== 'function') {throw 'callback must be a function'}// 定义变量let pressTimer = null// 创建计时器( 2秒后执行函数 )let start = (e) => {if (e.type === 'click' && e.button !== 0) {return}if (pressTimer === null) {pressTimer = setTimeout(() => {handler()}, 2000)}}// 取消计时器let cancel = (e) => {if (pressTimer !== null) {clearTimeout(pressTimer)pressTimer = null}}// 运行函数const handler = (e) => {binding.value(e)}// 添加事件监听器el.addEventListener('mousedown', start)el.addEventListener('touchstart', start)// 取消计时器el.addEventListener('click', cancel)el.addEventListener('mouseout', cancel)el.addEventListener('touchend', cancel)el.addEventListener('touchcancel', cancel)},// 当传进来的值更新的时候触发componentUpdated(el, { value }) {el.$value = value},// 指令与元素解绑的时候,移除事件绑定unbind(el) {el.removeEventListener('click', el.handler)},}export default longpress

使用:

给 Dom 加上 v-longpress 及回调函数即可

<template><button v-longpress="longpress">长按</button></template><script>export default {methods: {longpress () {alert('长按指令生效')}}}</script>3、v-debounce

背景:

在开发中,有些提交保存按钮有时候会在短时间内被点击多次,这样就会多次重复请求后端接口,造成数据的混乱,比如新增表单的提交按钮,多次点击就会新增多条重复的数据。

需求:

防止按钮在短时间内被多次点击,使用防抖函数限制规定时间内只能点击一次。

思路:

定义一个延迟执行的方法,如果在延迟时间内再调用该方法,则重新计算执行时间。

将时间绑定在 click 方法上。

const debounce = {inserted: function (el, binding) {let timerel.addEventListener('keyup', () => {if (timer) {clearTimeout(timer)}timer = setTimeout(() => {binding.value()}, 1000)})},}export default debounce

使用:

给 Dom 加上 v-debounce 及回调函数即可

<template><button v-debounce="debounceClick">防抖</button></template><script>export default {methods: {debounceClick () {console.log('只触发一次')}}}</script>4、v-emoji

背景:

开发中遇到的表单输入,往往会有对输入内容的限制,比如不能输入表情和特殊字符,只能输入数字或字母等。

我们常规方法是在每一个表单的 on-change 事件上做处理。

<template><input type="text" v-model="note" @change="vaidateEmoji" /></template><script> export default {methods: {vaidateEmoji() {var reg = /[^u4E00-u9FA5|d|a-zA-Z|rns,.?!,。?!…—&$=()-+/*{}[]]|s/gthis.note = this.note.replace(reg, '')},},} </script>

这样代码量比较大而且不好维护,所以我们需要自定义一个指令来解决这问题。

需求:

根据正则表达式,设计自定义处理表单输入规则的指令,下面以禁止输入表情和特殊字符为例。

let findEle = (parent, type) => {return parent.tagName.toLowerCase() === type ? parent : parent.querySelector(type)}const trigger = (el, type) => {const e = document.createEvent('htmlEvents')e.initEvent(type, true, true)el.dispatchEvent(e)}const emoji = {bind: function (el, binding, vnode) {// 正则规则可根据需求自定义var regRule = /[^u4E00-u9FA5|d|a-zA-Z|rns,.?!,。?!…—&$=()-+/*{}[]]|s/glet $inp = findEle(el, 'input')el.$inp = $inp$inp.handle = function () {let val = $inp.value$inp.value = val.replace(regRule, '')trigger($inp, 'input')}$inp.addEventListener('keyup', $inp.handle)},unbind: function (el) {el.$inp.removeEventListener('keyup', el.$inp.handle)},}export default emoji

使用:

将需要校验的输入框加上 v-emoji 即可

<template><input type="text" v-model="note" v-emoji /></template>5、v-LazyLoad

背景:在类电商类项目,往往存在大量的图片,如 banner 广告图,菜单导航图,美团等商家列表头图等。图片众多以及图片体积过大往往会影响页面加载速度,造成不良的用户体验,所以进行图片懒加载优化势在必行。

需求:实现一个图片懒加载指令,只加载浏览器可见区域的图片。

思路:

图片懒加载的原理主要是判断当前图片是否到了可视区域这一核心逻辑实现的

拿到所有的图片 Dom ,遍历每个图片判断当前图片是否到了可视区范围内

如果到了就设置图片的 src 属性,否则显示默认图片

图片懒加载有两种方式可以实现,一是绑定 srcoll 事件进行监听,二是使用 IntersectionObserver 判断图片是否到了可视区域,但是有浏览器兼容性问题。

下面封装一个懒加载指令兼容两种方法,判断浏览器是否支持 IntersectionObserver API,如果支持就使用 IntersectionObserver 实现懒加载,否则则使用 srcoll 事件监听 + 节流的方法实现。

const LazyLoad = {// install方法install(Vue, options) {const defaultSrc = options.defaultVue.directive('lazy', {bind(el, binding) {LazyLoad.init(el, binding.value, defaultSrc)},inserted(el) {if (IntersectionObserver) {LazyLoad.observe(el)} else {LazyLoad.listenerScroll(el)}},})},// 初始化init(el, val, def) {el.setAttribute('data-src', val)el.setAttribute('src', def)},// 利用IntersectionObserver监听elobserve(el) {var io = new IntersectionObserver((entries) => {const realSrc = el.dataset.srcif (entries[0].isIntersecting) {if (realSrc) {el.src = realSrcel.removeAttribute('data-src')}}})io.observe(el)},// 监听scroll事件listenerScroll(el) {const handler = LazyLoad.throttle(LazyLoad.load, 300)LazyLoad.load(el)window.addEventListener('scroll', () => {handler(el)})},// 加载真实图片load(el) {const windowHeight = document.documentElement.clientHeightconst elTop = el.getBoundingClientRect().topconst elBtm = el.getBoundingClientRect().bottomconst realSrc = el.dataset.srcif (elTop - windowHeight < 0 && elBtm > 0) {if (realSrc) {el.src = realSrcel.removeAttribute('data-src')}}},// 节流throttle(fn, delay) {let timerlet prevTimereturn function (...args) {const currTime = Date.now()const context = thisif (!prevTime) prevTime = currTimeclearTimeout(timer)if (currTime - prevTime > delay) {prevTime = currTimefn.apply(context, args)clearTimeout(timer)return}timer = setTimeout(function () {prevTime = Date.now()timer = nullfn.apply(context, args)}, delay)}},}export default LazyLoad

使用,将组件内 标签的 src 换成 v-LazyLoad

<img v-LazyLoad="xxx.jpg" />6、v-permission

背景:

在一些后台管理系统,我们可能需要根据用户角色进行一些操作权限的判断,很多时候我们都是粗暴地给一个元素添加 v-if / v-show 来进行显示隐藏,但如果判断条件繁琐且多个地方需要判断,这种方式的代码不仅不优雅而且冗余。针对这种情况,我们可以通过全局自定义指令来处理。

需求:自定义一个权限指令,对需要权限判断的 Dom 进行显示隐藏。

思路:

自定义一个权限数组

判断用户的权限是否在这个数组内,如果是则显示,否则则移除 Dom

function checkArray(key) {let arr = ['1', '2', '3', '4']let index = arr.indexOf(key)if (index > -1) {return true // 有权限} else {return false // 无权限}}const permission = {inserted: function (el, binding) {let permission = binding.value // 获取到 v-permission的值if (permission) {let hasPermission = checkArray(permission)if (!hasPermission) {// 没有权限 移除Dom元素el.parentNode && el.parentNode.removeChild(el)}}},}export default permission

使用:

给 v-permission 赋值判断即可

<!-- 显示 --><button v-permission="'1'">权限按钮1</button><!-- 不显示 --><button v-permission="'10'">权限按钮2</button></div>7、vue-waterMarker

需求:给整个页面添加背景水印

思路:

使用 canvas 特性生成 base64 格式的图片文件,设置其字体大小,颜色等。

将其设置为背景图片,从而实现页面或组件水印效果

function addWaterMarker(str, parentNode, font, textColor) {// 水印文字,父元素,字体,文字颜色var can = document.createElement('canvas')parentNode.appendChild(can)can.width = 200can.height = 150can.style.display = 'none'var cans = can.getContext('2d')cans.rotate((-20 * Math.PI) / 180)cans.font = font || '16px Microsoft JhengHei'cans.fillStyle = textColor || 'rgba(180, 180, 180, 0.3)'cans.textAlign = 'left'cans.textBaseline = 'Middle'cans.fillText(str, can.width / 10, can.height / 2)parentNode.style.backgroundImage = 'url(' + can.toDataURL('image/png') + ')'}const waterMarker = {bind: function (el, binding) {addWaterMarker(binding.value.text, el, binding.value.font, binding.value.textColor)},}export default waterMarker

使用,设置水印文案,颜色,字体大小即可

<template><div v-waterMarker="{text:'lzg版权所有',textColor:'rgba(180, 180, 180, 0.4)'}"></div></template>8、v-draggable

需求:

实现一个拖拽指令,可在页面可视区域任意拖拽元素。

思路:

设置需要拖拽的元素为相对定位,其父元素为绝对定位。

鼠标按下(onmousedown)时记录目标元素当前的 left 和 top 值。

鼠标移动(onmousemove)时计算每次移动的横向距离和纵向距离的变化值,并改变元素的 left 和 top 值

鼠标松开(onmouseup)时完成一次拖拽

const draggable = {inserted: function (el) {el.style.cursor = 'move'el.onmousedown = function (e) {let disx = e.pageX - el.offsetLeftlet disy = e.pageY - el.offsetTopdocument.onmousemove = function (e) {let x = e.pageX - disxlet y = e.pageY - disylet maxX = document.body.clientWidth - parseInt(window.getComputedStyle(el).width)let maxY = document.body.clientHeight - parseInt(window.getComputedStyle(el).height)if (x < 0) {x = 0} else if (x > maxX) {x = maxX}if (y < 0) {y = 0} else if (y > maxY) {y = maxY}el.style.left = x + 'px'el.style.top = y + 'px'}document.onmouseup = function () {document.onmousemove = document.onmouseup = null}}},}export default draggable

使用:

在 Dom 上加上 v-draggable 即可

<template><div class="el-dialog" v-draggable></div></template>
本文链接地址:https://www.jiuchutong.com/zhishi/298467.html 转载请保留说明!

上一篇:解读YOLO v7的代码(三)损失函数(yolo v5详解)

下一篇:机器学习中的预测评价指标MSE、RMSE、MAE、MAPE、SMAPE

  • 快手发照片配乐怎么显示歌词(快手发照片配乐怎么显示歌词华为手机)

    快手发照片配乐怎么显示歌词(快手发照片配乐怎么显示歌词华为手机)

  • 降噪耳机怎么选(降噪耳机怎么选择耳机帽型号)

    降噪耳机怎么选(降噪耳机怎么选择耳机帽型号)

  • 华为nova7如何隐藏返回键(华为nova7如何隐藏软件)

    华为nova7如何隐藏返回键(华为nova7如何隐藏软件)

  • 快手怎么@别人名字(快手怎么别人看不到我的作品)

    快手怎么@别人名字(快手怎么别人看不到我的作品)

  • 腾讯app扫一扫在哪(腾讯 扫一扫)

    腾讯app扫一扫在哪(腾讯 扫一扫)

  • 华为p40有扫描功能吗(华为p40扫描功能怎么使用)

    华为p40有扫描功能吗(华为p40扫描功能怎么使用)

  • 手机指纹解锁功能在设置不见了(手机指纹解锁功能删除了怎么恢复)

    手机指纹解锁功能在设置不见了(手机指纹解锁功能删除了怎么恢复)

  • EC是什么(ec是什么意思)

    EC是什么(ec是什么意思)

  • 快手直播限流怎么办(快手直播限流怎样解决)

    快手直播限流怎么办(快手直播限流怎样解决)

  • 二极管符号怎么看方向(二极管符号怎么看导通)

    二极管符号怎么看方向(二极管符号怎么看导通)

  • 3dmax的三大要素(3dmax包括什么)

    3dmax的三大要素(3dmax包括什么)

  • 华为手机验证码不弹出是怎么回事(华为手机验证码自动填充设置)

    华为手机验证码不弹出是怎么回事(华为手机验证码自动填充设置)

  • 苹果11长宽多少厘米(苹果长宽多少厘米)

    苹果11长宽多少厘米(苹果长宽多少厘米)

  • 华为p30拍视频防抖吗(华为手机拍视频防抖功能怎么打开)

    华为p30拍视频防抖吗(华为手机拍视频防抖功能怎么打开)

  • 在计算机的储存单元中储存的是(在计算机的储存单元中,ASCII码的最高位用作)

    在计算机的储存单元中储存的是(在计算机的储存单元中,ASCII码的最高位用作)

  • 费的锂电池可以回收吗(锂电池能直接扔掉吗)

    费的锂电池可以回收吗(锂电池能直接扔掉吗)

  • 小米真无线蓝牙耳机air2支持苹果吗(小米真无线蓝牙耳机air2se)

    小米真无线蓝牙耳机air2支持苹果吗(小米真无线蓝牙耳机air2se)

  • 荣耀手环功能怎么使用(荣耀手环功能怎么用)

    荣耀手环功能怎么使用(荣耀手环功能怎么用)

  • 共享单车无法实名怎么办(共享单车无法实名认证)

    共享单车无法实名怎么办(共享单车无法实名认证)

  • 拼多多下单时从哪备注(拼多多已下单是什么意思)

    拼多多下单时从哪备注(拼多多已下单是什么意思)

  • 淘工厂是如何做C2B的(淘工厂怎么收费)

    淘工厂是如何做C2B的(淘工厂怎么收费)

  • 小米8支持北斗导航吗(小米8支持北斗系统吗)

    小米8支持北斗导航吗(小米8支持北斗系统吗)

  • 苹果otg在哪里设置

    苹果otg在哪里设置

  • 哈罗单车如何免押金(哈罗单车如何免费)

    哈罗单车如何免押金(哈罗单车如何免费)

  • WordPress更换域名教程(wordpress换域名后主题乱了)

    WordPress更换域名教程(wordpress换域名后主题乱了)

  • Python导入模块的搜索顺序(python导入模块的本质)

    Python导入模块的搜索顺序(python导入模块的本质)

  • 收到个人开票会计分录怎么做
  • 减税性质代码及名称是什么意思
  • 法人转让股权后还是法人吗
  • 航空公司能开电动车吗
  • 税务局的信用等级是多少
  • 应收账款贷方有余额是什么意思
  • 国际机票可以抵扣进项税吗
  • 企业转让固定资产要交什么税
  • 讲师讲课费标准2019
  • 财务报表没有申报表
  • 开发产品计入什么科目
  • 持有待售固定资产按照账面价值与可收回金额
  • 公司与公司之间合作协议
  • 固定资产台账登记表明细科目写什么
  • 运输费计入采购成本的分录
  • 工资薪金所得适用的税率是
  • 国税怎么查缴税明细
  • 销项负数发票怎么填报增值税报表
  • 合同印花税进哪个科目
  • 逃避缴纳税款征管法第几条
  • 税收分类编码里的劳务是劳务派遣的意思吗
  • 利润表为什么没有主营业务收入
  • 销项负数发票需要抵扣吗
  • 金税盘减免税款贷方余额
  • 股东投入的资金可以计入资本公积吗
  • mac dash
  • 咋激活windows
  • 杜鹃花怎么养家庭养法视频
  • 电脑怎样设置共享文件夹
  • kavsvc.exe - kavsvc是什么进程 有什么作用
  • php常用设计模式(大总结)
  • 工会举办的比赛有哪些
  • 交通费补贴算工资吗?
  • php中imagestring
  • 无形资产期末余额在哪方
  • thinkphp常用函数
  • css盒子模型怎么做
  • python快速检索
  • mla指令
  • 公司期货套期保值会计处理方法
  • 存根联明细是自动生成
  • 银行对账单冲正的单据在财务软件哪里找
  • phpcms api
  • dedecms采集怎么用
  • 税控系统维护费抵扣申报表怎么填
  • sql server 2005 数据库还原
  • 技术服务费会计科目
  • 核定征收和查账征收可以自己选择吗
  • 取得交易性金融资产支付的相关税费计入
  • 小规模纳税人附加税减免政策2023
  • 暂估主营业务成本怎么冲销
  • 支付的税费现金流量表公式
  • 接受小规模纳税人的货运服务
  • 国家资产负债表
  • 应交税费进项税额转出
  • 上次年检怎么查
  • 会计里面权益是什么
  • 存储过程的输出参数有且只能有一个
  • ubuntu怎样
  • centos 7 安装vnc
  • window98到windows10
  • linux date-u
  • 电脑禁用u盘软件
  • fstab文件详解修改
  • win8隐藏的文件夹怎么找出来
  • certutil - decode/encode BASE64/HEX strings.Print symbols by HEX code
  • javascriptcsdn
  • nodejs bull
  • cocos2dx3.0的label字体去描边
  • jquery使用教程
  • unicode编码实现方案
  • jQuery+JSON实现AJAX二级联动实例分析
  • jquery如何做登录
  • 公司代扣税怎么办理
  • 充值卡和预付卡区别
  • 责令立即改正和责令限期整改
  • 票种删除需要怎么弄
  • 城市配套费需要缴纳契税
  • 消费税的税收筹划案例分析
  • 成都车辆购置税2024年新政策
  • 免责声明:网站部分图片文字素材来源于网络,如有侵权,请及时告知,我们会第一时间删除,谢谢! 邮箱:opceo@qq.com

    鄂ICP备2023003026号

    网站地图: 企业信息 工商信息 财税知识 网络常识 编程技术

    友情链接: 武汉网站建设