范文健康探索娱乐情感热点
投稿投诉
热点动态
科技财经
情感日志
励志美文
娱乐时尚
游戏搞笑
探索旅游
历史星座
健康养生
美丽育儿
范文作文
教案论文
国学影视

8个非常实用的Vue自定义指令

  在 Vue,除了核心功能默认内置的指令 ( v-model 和 v-show ),Vue 也允许注册自定义指令。它的作用价值在于当开发人员在某些场景下需要对普通 DOM 元素进行操作。
  Vue自定义指令有全局注册和局部注册两种方式。先来看看注册全局指令的方式,通过 Vue.directive( id, [definition] ) 方式注册全局指令。然后在入口文件中进行 Vue.use() 调用。
  批量注册指令,新建 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) 复制代码
  指令定义函数提供了几个钩子函数(可选):bind: 只调用一次,指令第一次绑定到元素时调用,可以定义一个在绑定时执行一次的初始化动作。inserted: 被绑定元素插入父节点时调用(父节点存在即可调用,不必存在于 document 中)。update: 被绑定元素所在的模板更新时调用,而不论绑定值是否变化。通过比较更新前后的绑定值。componentUpdated: 被绑定元素所在模板完成一次更新周期时调用。unbind: 只调用一次, 指令与元素解绑时调用。
  下面分享几个实用的 Vue 自定义指令复制粘贴指令 v-copy长按指令 v-longpress输入框防抖指令 v-debounce禁止表情及特殊字符 v-emoji图片懒加载 v-LazyLoad权限校验指令 v-premission实现页面水印 v-waterMarker拖拽指令 v-draggablev-copy
  需求:实现一键复制文本内容,用于鼠标右键粘贴。
  思路:动态创建 textarea 标签,并设置 readOnly 属性及移出可视区域将要复制的值赋给 textarea 标签的 value 属性,并插入到 body选中值 textarea 并复制将 body 中插入的 textarea 移除在第一次调用时绑定事件,在解绑时移除事件const copy = {   bind(el, { value }) {     el.$value = value     el.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 及复制的文本即可    复制代码v-longpress
  需求:实现长按,用户需要按下并按住按钮几秒钟,触发相应的事件
  思路:创建一个计时器, 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 及回调函数即可    复制代码v-debounce
  背景:在开发中,有些提交保存按钮有时候会在短时间内被点击多次,这样就会多次重复请求后端接口,造成数据的混乱,比如新增表单的提交按钮,多次点击就会新增多条重复的数据。
  需求:防止按钮在短时间内被多次点击,使用防抖函数限制规定时间内只能点击一次。
  思路:定义一个延迟执行的方法,如果在延迟时间内再调用该方法,则重新计算执行时间。将时间绑定在 click 方法上。const debounce = {   inserted: function (el, binding) {     let timer     el.addEventListener("keyup", () => {       if (timer) {         clearTimeout(timer)       }       timer = setTimeout(() => {         binding.value()       }, 1000)     })   }, }   export default debounce 复制代码
  使用:给 Dom 加上 v-debounce 及回调函数即可    复制代码v-emoji
  背景:开发中遇到的表单输入,往往会有对输入内容的限制,比如不能输入表情和特殊字符,只能输入数字或字母等。
  我们常规方法是在每一个表单的 on-change 事件上做处理。    复制代码
  这样代码量比较大而且不好维护,所以我们需要自定义一个指令来解决这问题。
  需求:根据正则表达式,设计自定义处理表单输入规则的指令,下面以禁止输入表情和特殊字符为例。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/g     let $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 即可 复制代码v-LazyLoad
  背景:在类电商类项目,往往存在大量的图片,如 banner 广告图,菜单导航图,美团等商家列表头图等。图片众多以及图片体积过大往往会影响页面加载速度,造成不良的用户体验,所以进行图片懒加载优化势在必行。
  需求:实现一个图片懒加载指令,只加载浏览器可见区域的图片。
  思路:图片懒加载的原理主要是判断当前图片是否到了可视区域这一核心逻辑实现的拿到所有的图片 Dom ,遍历每个图片判断当前图片是否到了可视区范围内如果到了就设置图片的 src 属性,否则显示默认图片
  图片懒加载有两种方式可以实现,一是绑定 srcoll 事件进行监听,二是使用 IntersectionObserver 判断图片是否到了可视区域,但是有浏览器兼容性问题。
  下面封装一个懒加载指令兼容两种方法,判断浏览器是否支持 IntersectionObserver API,如果支持就使用 IntersectionObserver 实现懒加载,否则则使用 srcoll 事件监听 + 节流的方法实现。const LazyLoad = {   // install方法   install(Vue, options) {     const defaultSrc = options.default     Vue.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监听el   observe(el) {     var io = new IntersectionObserver((entries) => {       const realSrc = el.dataset.src       if (entries[0].isIntersecting) {         if (realSrc) {           el.src = realSrc           el.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.clientHeight     const elTop = el.getBoundingClientRect().top     const elBtm = el.getBoundingClientRect().bottom     const realSrc = el.dataset.src     if (elTop - windowHeight < 0 && elBtm > 0) {       if (realSrc) {         el.src = realSrc         el.removeAttribute("data-src")       }     }   },   // 节流   throttle(fn, delay) {     let timer     let prevTime     return function (...args) {       const currTime = Date.now()       const context = this       if (!prevTime) prevTime = currTime       clearTimeout(timer)         if (currTime - prevTime > delay) {         prevTime = currTime         fn.apply(context, args)         clearTimeout(timer)         return       }         timer = setTimeout(function () {         prevTime = Date.now()         timer = null         fn.apply(context, args)       }, delay)     }   }, }   export default LazyLoad 复制代码
  使用,将组件内 标签的 src 换成 v-LazyLoad 复制代码v-permission
  背景:在一些后台管理系统,我们可能需要根据用户角色进行一些操作权限的判断,很多时候我们都是粗暴地给一个元素添加 v-if / v-show 来进行显示隐藏,但如果判断条件繁琐且多个地方需要判断,这种方式的代码不仅不优雅而且冗余。针对这种情况,我们可以通过全局自定义指令来处理。
  需求:自定义一个权限指令,对需要权限判断的 Dom 进行显示隐藏。
  思路:自定义一个权限数组判断用户的权限是否在这个数组内,如果是则显示,否则则移除 Domfunction 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 赋值判断即可              复制代码vue-waterMarker
  需求:给整个页面添加背景水印
  思路:使用 canvas 特性生成 base64 格式的图片文件,设置其字体大小,颜色等。将其设置为背景图片,从而实现页面或组件水印效果function addWaterMarker(str, parentNode, font, textColor) {   // 水印文字,父元素,字体,文字颜色   var can = document.createElement("canvas")   parentNode.appendChild(can)   can.width = 200   can.height = 150   can.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 复制代码
  使用,设置水印文案,颜色,字体大小即可 复制代码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.offsetLeft       let disy = e.pageY - el.offsetTop       document.onmousemove = function (e) {         let x = e.pageX - disx         let y = e.pageY - disy         let 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 即可

华为又有新机曝光,华为Nova9下月发布,具备5G能力前不久华为新品发布会,我们终于有幸见到了这款经受了四轮制裁还能够面世的华为P50系列,遗憾的是,由于5G射频模块被卡脖子的缘由,P50Pro虽然搭载了麒麟9000,但只能当做4G芯定了!英特尔显卡系列获得全新品牌名称经过几个月的各种预告,英特尔终于开始为他们的第一个高性能独立GPU和显卡组建市场团队。英特尔显卡系列获得全新品牌名称昨晚,英特尔官方宣布这些显卡将以一个新的品牌名称Arc出售,并将惨崩!阿里巴巴和腾讯股价暴跌近5网络游戏股全应声跳水中国市场监管总局再传巨响FX168财经报社(香港)讯香港股市迎接不平静的早盘行情,除在线教育类股遭遇重挫外,网络科技与游戏类股也同样难逃监管担忧所害。中国市场监管总局发布禁止网络不正当竞争行为规定征求意见一定要去临沂,赶一场中国大集宋馥李文一hr8月,备战的气氛渐渐升温菜鸟的1号仓刚刚落户临沂作为跨境电商的旗舰中心,1号仓定位于国际商品的大进大出,顺丰德邦百世汇通几乎所有的物流巨头,都在临沂驻扎重兵频频动作。荣耀宣布面向全球发布荣耀Magic3系列手机这是标志性旗舰产品系列,提供非凡的用户体验最新款Magic系列智能手机搭载强大的高通(Qualcomm)骁龙(Snapdragon)888Plus5G移动平台,向全世界展示了荣耀最笔记本电脑选购攻略,小白也能看懂2021年的高考招生已经结束,想必大家都已经开始憧憬美好的大学生活了。本期小编来为大家介绍一下作为一个准大学生我们该如何选购适合自己的笔记本电脑。笔记本电脑大体可分为轻薄本和游戏本动辄万元的OLED笔记本出现了转机不足5000真香熟悉OLED屏幕的消费者对该屏幕都有一定的了解,OLED屏幕能达到高分辨率,高色域及高亮度,同时它还兼具硬件级防蓝光护眼的优势,对于普通的LCD屏幕而言,该屏幕占尽优势,对于屏幕要拿什么记录你,我的青春!开学季入门vlog装备推荐大家好,我是蘑菇转眼间又到了暑假后的开学季。大部分朋友的学生时代,并不曾像影视作品里那样光鲜亮丽色彩斑斓,但是再平凡的记忆也是闪光的,总有不经意的瞬间能撩拨到内心中的那段记忆。随着荣耀Magic3Pro硬核对比小米11Pro看看哪款更值得入手大家好,我是H酒窝。我给大家带来荣耀Magic3Pro和小米11Pro的对比,看看哪一款手机表现更加出色,最值得入手。(一)荣耀Magic3Pro先来看看手机的正面。手机正面采用了荣耀X20Max即将到来!曾经的大屏真香机还有多少用户买账呢?如今大屏手机已经是一个主打卖点,尤其是全面屏这块,目前我们所知道的主流屏幕大部分都在6。5寸左右,专门的大屏机型基本都消失了,不然都赶上平板了,你认为呢?8月12日晚上,是荣耀新品顺丰快递员一天大概有多少收入,有图有真相大家好,我是快递小哥小唐,上一个文章给大家讲解了一下顺丰快递的福利和待遇的情况,今天来说说大多数顺丰快递员一天可以跑到多少单,一单多少钱,一天下来能挣多少钱!这几天江阴这边天天下雨
小荷才露尖尖角(22)公司中的大数据开发在做什么?基本上每个大厂里面都有独立于业务产品研发部门的大数据开发团队,我们一般管他们叫BI,BI团队的工作职责有很多,但首先得收集数据,并进行建模。数据来源于公司面向用户或者客户的产品。用故事连环画新路。。。春节前这3款手机将迎来大幅降价,力度不低于双11,抓紧机会还有不到一个月的时间就要过年了,很多朋友都准备春节前买新机,也有朋友还在观望还在犹豫,其实现在应该是年前最好的换机时间,恰逢各大电商的年货节不少手机最近都有降价,学长大概看了一下,打算买新手机过年?这3款旗舰机建议避雷,行内人亲历的血泪史现如今的手机可以说是别出心裁,有的厂商在外观上下功夫,有的则在影像系统上深度优化,当然也有主打极致性能体验的。快过年了,相信应该有不少小伙伴会想买新机过年,但是今天小编给大家整理3不割韭菜,这四款千元机才是真正的良心,闭眼买系列盘点手机圈中谁割韭菜最厉害?那应该非苹果莫属了,上市时高价割一轮,然后每隔两三个月遇到节日促销,再迎来几百左右降价福利收割一轮又一轮,直到五六千的高端机最后降至两三千左右退市。虽然大家手机电池越来越不耐用?或许是这5点习惯导致的手机渐渐的走入我们的生活,对于一部手机而言,手机电池的续航时间,是取决于这部手机能否继续使用的主要因素之一,我们今天主要来讲,手机在使用的时候哪些不恰当的动作会让手机电池慢慢的变得北京市万人5G基站数全国第一来源新华网新华社北京1月7日电(记者邰思聪鲁畅)在1月7日举行的北京市第十五届人民代表大会第五次会议新闻发布会上,北京市经济和信息化局副局长王磊介绍,北京市万人5G基站数全国第一,福建省高速首家无人智能便利店开业近日,在福银高速官洋服务区,全省高速首家充满智能消费概念的驿佳购无人智能便利店开始营业。便利店内商品涵盖了饮料方便面休闲食品日用品等250多种产品,在高科技的护航下,无人收银自助结TINHIFIP1Plus千元级平板耳塞,感受比动圈更宽松耐听的声音得益于技术的进步,平板不再是大耳的专属,越来越多的厂家都开始尝试平板耳塞。记得接触过第一款平板耳塞是奥帝兹iSINE是20,虽然这款耳塞在圈内的知名度非常高,而且价格卖得也挺贵的,OPPOK9怎么样?值得入手吗?oppok9多少钱怎么样值得买吗oppok9售价参数一览OPPOK9多少钱?oppo手机于5月6日15点举行了oppok9系列发布会,作为超次元发布会中的收集,k9的价格是多少呢?小米MIX5Pro被曝,小米MIX5系列预计三月份左右发布据可靠消息,小米手机澎湃C2芯片将和小米MIX5系列手机一同推出,但仅搭载在MIX5Pro(L1)上。MIX5和5Pro两款仅在相机的传感器和相机的处理器上有所区别。关于小米手机M