vue常见自定义指令

  • vue常见自定义指令已关闭评论
  • 94 次浏览
  • A+
所属分类:Web前端

常见自定义指令

一、响应缩放指令


  1. 使用
<div v-resize="resize"></div> 
  1. 代码
/**  *  响应缩放指令  *  @direction 使用该指令可以响应元素宽高改变时执行的方法。  *  @resize {function} 传入对应resize方法  *  v-resize="resize"  **/  export default {   bind(el, binding) {     let width = '', height = '';     function isResize() {       const style = document.defaultView.getComputedStyle(el);       if (width !== style.width || height !== style.height) {         binding.value(); // 执行传入的方法       }       width = style.width;       height = style.height;     }     el.__timer__ = setInterval(isResize, 300); // 周期性监听元素是否改变   },   unbind(el) {     clearInterval(el.__timer__);   } } 

二、元素点击范围扩展指令


  1. 使用
<div v-expandClick="20,30,40,50"></div> 
  1. 代码
/**  *  元素点击范围扩展指令  *  @direction 使用该指令可以隐式的扩展元素的点击范围,由于借用伪元素实现,故不会影响元素在页面上的排列布局。法。  *  @top {string} 上扩展的范围,单位 px,默认向外扩展 10px  *  @right {string} 右扩展的范围,单位 px,默认向外扩展 10px  *  @bottom {string} 下扩展的范围,单位 px,默认向外扩展 10px  *  @left {string} 左扩展的范围,单位 px,默认向外扩展 10px  *  v-expandClick="top, right, bottom, left" (10, 10, 10, 10)  **/ export default {   bind(el, binding) {     const s = document.styleSheets[document.styleSheets.length - 1]     const DEFAULT = -10 // 默认向外扩展10px     const ruleStr = `content:"";position:absolute;top:-${top || DEFAULT}px;bottom:-${bottom || DEFAULT}px;right:-${right || DEFAULT}px;left:-${left || DEFAULT}px;`     const [top, right, bottom, left] = binding.expression && binding.expression.split(',') || []     const classNameList = el.className.split(' ')     el.className = classNameList.includes('expand_click_range') ? classNameList.join(' ') : [...classNameList, 'expand_click_range'].join(' ')     el.style.position = el.style.position || 'relative'     if (s.insertRule) {       s.insertRule('.expand_click_range::before' + '{' + ruleStr + '}', s.cssRules.length)     } else { /* IE */       s.addRule('.expand_click_range::before', ruleStr, -1)     }   } } 

三、文本内容复制指令


  1. 使用
<div v-copy> 单击复制 </div> <div v-copy.dblclick> 双击复制 </div> <div v-copy.icon> icon复制 </div> 
  1. 代码
/**  *  文本内容复制指令  *  @direction 使用该指令可以复制元素的文本内容(指令支持单击复制 v-copy、双击复制 v-copy.dblclick、点击icon复制 v-copy.icon三种模式),不传参数时,默认使用单击复制。  *  @dblclick {string} dblclick 双击复制文本内容  *  @icon {string} icon 单击icon复制文本内容  *  v-copy 单击复制  *  v-copy.dblclick 双击复制  *  v-copy.icon icon复制  **/ export default {   bind(el, binding) {     // 双击触发复制     if (binding.modifiers.dblclick) {       el.addEventListener('dblclick', () => handleClick(el.innerText))       el.style.cursor = 'copy'     } else if (binding.modifiers.icon) { // 点击icon触发复制       if (el.hasIcon) return       const iconElement = document.createElement('i')       iconElement.setAttribute('class', 'el-icon-document-copy')       iconElement.setAttribute('style', 'margin-left:5px')       el.appendChild(iconElement)       el.hasIcon = true       iconElement.addEventListener('click', () => handleClick(el.innerText))       iconElement.style.cursor = 'copy'     } else { // 单击触发复制       el.addEventListener('click', () => handleClick(el.innerText))       el.style.cursor = 'copy'     }   } } 

四、元素说明指令


  1. 使用
<div v-tooltip:content='tootipParams'> 提示 </div> 
  1. 代码
/**  *  元素说明指令  *  @direction 为元素添加说明,同 element-ui 的el-tooltip  *  @content {string} 传给指令的参数  *  @tooltipParams	 {Object} element-ui 支持的 tooltip属性  *  v-tooltip:content='tooltipParams'  **/  import Vue from 'vue'  function structureIcon(content, attrs) {   // 拼接绑定属性   let attrStr = ''   for (const key in attrs) {     attrStr += `${key}=${attrs[key]} `   }   const a = `<el-tooltip content=${content} ${attrStr}><i class="el-icon-question" style="margin:0 10px"></i></el-tooltip>`   // 创建构造器   const tooltip = Vue.extend({     template: a   })   // 创建一个 tooltip 实例并返回 dom 节点   const component = new tooltip().$mount()   return component.$el }  export default {   bind(el, binding) {     if (el.hasIcon) return     const iconElement = structureIcon(binding.arg, binding.value)     el.appendChild(iconElement)     el.hasIcon = true   } } 

五、文字超出省略指令


  1. 使用
<div v-ellipsis:100> 需要省略的文字是阿萨的副本阿萨的副本阿萨的副本阿萨的副本</div> 
  1. 代码
/**  *  文字超出省略指令  *  @direction 使用该指令当文字内容超出宽度。  *  @width {number} 元素宽度  *  v-ellipsis:width  **/  export default {   bind(el, binding) {     el.style.width = binding.arg || 100 + 'px'     el.style.whiteSpace = 'nowrap'     el.style.overflow = 'hidden';     el.style.textOverflow = 'ellipsis';   } } 

六、回到顶部指令


  1. 使用
<div  v-backtop:app="400"> 回到顶部 </div> 
  1. 代码
/**  *  回到顶部指令  *  @direction 使用该指令可以让页面或指定元素回到顶部。  *  @id {string} 给需要回到顶部的元素添加的id  *  @offset {number} 偏移距离为 height 时显示指令绑定的元素  *  v-backtop:id="offset"  **/  export default {   bind(el, binding, vnode) {     // 响应点击后滚动到元素顶部     el.addEventListener('click', () => {       const target = binding.arg ? document.getElementById(binding.arg) : window       target.scrollTo({         top: 0,         behavior: 'smooth'       })     })   },   update(el, binding, vnode) {     // 滚动到达参数值才出现绑定指令的元素     const target = binding.arg ? document.getElementById(binding.arg) : window     if (binding.value) {       target.addEventListener('scroll', (e) => {         if (e.srcElement.scrollTop > binding.value) {           el.style.visibility = 'unset'         } else {           el.style.visibility = 'hidden'         }       })     }     // 判断初始化状态     if (target.scrollTop < binding.value) {       el.style.visibility = 'hidden'     }   },   unbind(el, binding) {     const target = binding.arg ? document.getElementById(binding.arg) : window     target.removeEventListener('scroll')     el.removeEventListener('click')   } } 

七、拖拽指令


  1. 使用
<div v-drag> 支持拖拽的元素 </div> 
  1. 代码
/**  *  拖拽指令  *  @direction 使用该指令可以对元素进行拖拽。  *  v-drag=“[width, height]”  **/  export default {   inserted(el, binding) {     let { value } = binding;     if (!value || value.length === 0) value = [0, 0]     el.style.cursor = 'move'     el.onmousedown = function(e) {       const disx = e.pageX - el.offsetLeft       const disy = e.pageY - el.offsetTop       document.onmousemove = function(e) {         let x = e.pageX - disx         let y = e.pageY - disy         const maxX = document.body.clientWidth - parseInt(window.getComputedStyle(el).width) - value[0]         const maxY = document.body.clientHeight - parseInt(window.getComputedStyle(el).height) - value[1]         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       }     }   } } 

八、长按指令


  1. 使用
<div v-longpress="longPress"></div> 
  1. 代码
/**  *  长按指令  *  @direction 实现长按,用户需要按下并按住按钮几秒钟,触发相应的事件  *  @longPress {function} 长按的回调  *  v-longpress="longPress"  **/  export default {   bind: function(el, binding, vNode) {     if (typeof binding.value !== 'function') {       throw 'callback must be a function'     }     // 定义变量     let pressTimer = null     // 创建计时器( 2秒后执行函数 )     const start = (e) => {       if (e.type === 'click' && e.button !== 0) {         return       }       if (pressTimer === null) {         pressTimer = setTimeout(() => {           handler()         }, 2000)       }     }     // 取消计时器     const 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)   } } 

九、防抖指令


  1. 使用
 <el-button v-debounce="debounceClick"> 防抖 </el-button> 
  1. 代码
/**  *  防抖指令  *  @direction 防止按钮在短时间内被多次点击,使用防抖函数限制规定时间内只能点击一次。  *  @debounceClick {function} 按钮的点击事件  *  v-debounce="debounceClick"  **/  export default {   inserted(el, binding) {     let timer     el.addEventListener('keyup', () => {       if (timer) {         clearTimeout(timer)       }       timer = setTimeout(() => {         binding.value()       }, 1000)     })   } } 

十、水印指令


  1. 使用
<div v-waterMarker="{text:'版权所有',textColor:'rgba(180, 180, 180, 0.4)', font:'16px Microsoft JhengHei'}"></div> 
  1. 代码
/**  *  水印指令  *  @direction 给整个页面添加背景水印  *  @data {Object} 水印文案,颜色,字体  *  v-waterMarker="{text:'版权所有',textColor:'rgba(180, 180, 180, 0.4)', font:'16px Microsoft JhengHei'}"  **/  function addWaterMarker(str, parentNode, font, textColor) {   // 水印文字,父元素,字体,文字颜色   const can = document.createElement('canvas')   parentNode.appendChild(can)   can.width = 200   can.height = 150   can.style.display = 'none'   const 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') + ')' }  export default {   bind(el, binding) {     addWaterMarker(binding.value.text, el, binding.value.font, binding.value.textColor)   } } 

十一、懒加载指令select


  1. 使用
<el-select v-loadselect="loadmore"></el-select> 
  1. 代码
/**  *  el-select懒加载指令  *  @direction 下拉框数据较多,需要下拉的时候懒加载数据  *  @load {function} 懒加载调用方法  *  v-loadselect="load"  **/  export default {   inserted(el, binding) {     const selectWarpDom = el.querySelector(       '.el-select-dropdown .el-select-dropdown__wrap'     )     selectWarpDom.addEventListener('scroll', function() {       if (this.scrollHeight - this.scrollTop <= this.clientHeight) {         binding.value()       }     })   } }   

十二、徽标指令


  1. 使用
<div v-badge.dot.info="10"></div> > 
  1. 代码
/**  *  徽标指令  *  @direction 使用该指令在元素右上角显示徽标。  *  @shape {string} 形状 [normal(正常徽标), dot(仅展示一个点)]  *  @type {string} 徽标颜色类型 [success, error, info, warning]  *  @num {number} 懒加载调用方法  *  v-badge.shape.type="num"  **/  import Vue from 'vue'  const SUCCESS = '#72c140' const ERROR = '#ed5b56' const WARNING = '#f0af41' const INFO = '#4091f7' const HEIGHT = 20 let flag = false export default {   update(el, binding, vnode) {     const { modifiers, value } = binding     const modifiersKey = Object.keys(modifiers)     const isDot = modifiersKey.includes('dot')     let backgroundColor = ''     if (modifiersKey.includes('success')) {       backgroundColor = SUCCESS     } else if (modifiersKey.includes('warning')) {       backgroundColor = WARNING     } else if (modifiersKey.includes('info')) {       backgroundColor = INFO     } else {       backgroundColor = ERROR     }      const targetTemplate = isDot       ? `<div style="position:absolute;top:-5px;right:-5px;height:10px;width:10px;border-radius:50%;background:${backgroundColor}"></div>`       : `<div style="background:${backgroundColor};position:absolute;top:-${HEIGHT / 2}px;right:-${HEIGHT / 2}px;height:${HEIGHT}px;min-width:${HEIGHT}px;border-radius:${HEIGHT / 2}px;text-align:center;line-height:${HEIGHT}px;color:#fff;padding:0 5px;">${value}</div>`      el.style.position = el.style.position || 'relative'     const badge = Vue.extend({       template: targetTemplate     })     const component = new badge().$mount().$el     if (flag) {       el.removeChild(el.lastChild)     }     el.appendChild(component)     flag = true   } } 

十三、空状态指令


  1. 使用
<div v-empty="emptyValue" style="height:500px;width:500px"> 原本内容 </div> 
  1. 代码
/**  *  空状态指令  *  @direction 使用该指令可以显示缺省的空状态, 可以传入默认图片(可选,默认无图片)、默认文字内容(可选,默认为暂无数据)、以及标示是否显示空状态(必选)。  *  @emptyValue  {Object} 懒加载调用方法  *  @content: '暂无列表', 可选  *  @img: require('../../assets/images/xxx.png'), 可选  *  @visible: 'true', 是否显示. 必传  *  v-empty="emptyValue "  **/  import Vue from 'vue'; export default {   update(el, binding, vnode) {     el.style.position = el.style.position || 'relative'     const { offsetHeight, offsetWidth } = el     const { visible, content, img } = binding.value     const image = img ? `<img src="${img}" height="30%" width="30%">` : ''     const defaultStyle = 'position:absolute;top:0;left:0;z-index:9999;background:#fff;display:flex;justify-content: center;align-items: center;'     const empty = Vue.extend({       template: `<div style="height:${offsetHeight}px;width:${offsetWidth}px;${defaultStyle}">       <div style="text-align:center">         <div>${image}</div>         <div>${content || '暂无数据'}</div>       </div>     </div>`     })     const component = new empty().$mount().$el     if (visible) {       el.appendChild(component)     } else {       el.removeChild(el.lastChild)     }   } } 

十四、输入框聚焦指令


  1. 使用
<div v-focus></div> 
  1. 代码
/**  *  输入框聚焦指令  *  @direction 页面加载时,输入框自动聚焦。  *  v-focus  **/  export default {   inserted(el) {     // 聚焦元素     el.focus()   } }