关于vue.js:Vue-常用自定义指令

46次阅读

共计 9997 个字符,预计需要花费 25 分钟才能阅读完成。

1、元素点击范畴扩大指令 v-expandClick
应用该指令能够隐式的扩大元素的点击范畴,因为借用伪元素实现,故不会影响元素在页面上的排列布局。

可传入的参数为:上右下左扩大的范畴,单位 px,默认向外扩大 10px。指令的代码如下:

export default function (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)
    }
}

参数 Attributes:

而后你能够在模板中任何元素上应用新的 v-expandClick property,如下:

<div v-expandClick="20,30,40,50" @click="glabClickoutside"> 点击范畴扩充 </div>

2、文本内容复制指令 v-copy
应用该指令能够复制元素的文本内容(指令反对单击复制 v-copy、双击复制 v-copy.dblclick、点击 icon 复制 v-copy.icon 三种模式),不传参数时,默认应用单击复制。

指令的代码如下:

export default {bind (el, binding) {
    // 双击触发复制
    if (binding.modifiers.dblclick) {el.addEventListener('dblclick', () => handleClick(el.innerText))
      el.style.cursor = 'copy'
    }
    // 点击 icon 触发复制
    else if (binding.modifiers.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'
    }
  }
}

function handleClick (text) {
  // 创立元素
  if (!document.getElementById('copyTarget')) {const copyTarget = document.createElement('input')
    copyTarget.setAttribute('style', 'position:fixed;top:0;left:0;opacity:0;z-index:-1000;')
    copyTarget.setAttribute('id', 'copyTarget')
    document.body.appendChild(copyTarget)
  }

  // 复制内容
  const input = document.getElementById('copyTarget')
  input.value = text
  input.select()
  document.execCommand('copy')
  // alert('复制胜利')
}

参数 Attributes:

而后你能够在模板中任何元素上应用新的 v-copy property,如下:

<div v-copy> 单击复制 </div>
<div v-copy.dblclick> 双击复制 </div>
<div v-copy.icon> icon 复制 </div>

3、元素全屏指令 v-screenfull
全屏指令,点击元素进行全屏 / 退出全屏的操作。反对元素前面是否插入 element-ui 的全屏图标 el-icon-full-screen。

指令的代码如下:

import screenfull from 'screenfull'

export default {bind (el, binding) {if (binding.modifiers.icon) {if (el.hasIcon) return
      // 创立全屏图标
      const iconElement = document.createElement('i')
      iconElement.setAttribute('class', 'el-icon-full-screen')
      iconElement.setAttribute('style', 'margin-left:5px')
      el.appendChild(iconElement)
      el.hasIcon = true
  }
    el.style.cursor = el.style.cursor || 'pointer'
    // 监听点击全屏事件
    el.addEventListener('click', () => handleClick())
  }
}

function handleClick () {if (!screenfull.isEnabled) {alert('浏览器不反对全屏')
    return
  }
  screenfull.toggle()}

参数 Attributes:

而后你能够在模板中任何元素上应用新的 v-screenfull property,如下:

<div v-screenfull.icon> 全屏 </div>

4、元素阐明指令 v-tooltip
为元素增加阐明,如同 element-ui 的 el-tooltip(问号 icon 在鼠标笼罩后,展现阐明文字)。

指令的代码如下:

import Vue from 'vue'
export default function (el, binding) {if (el.hasIcon) return
    const iconElement = structureIcon(binding.arg, binding.value)
    el.appendChild(iconElement)
    el.hasIcon = true
}

function structureIcon (content, attrs) {
    // 拼接绑定属性
    let attrStr = ''
    for (let 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
}

参数 Attributes:

而后你能够在模板中任何元素上应用新的 v-tooltip property,如下:

<div v-tooltip:content='tootipParams'> 提醒 </div>

举例:

<div v-tooltip: 提醒内容为 XXX1> 提醒 1 </div>
<div v-tooltip: 提醒内容为 XXX='tootipParams'> 提醒 2 </div>

为指令传入 element-ui 反对的参数:

data() {
    return {
        tootipParams: {
            placement: 'top',
            effect: 'light',
        }
    }
}

5、文字超出省略指令 v-ellipsis
应用该指令当文字内容超出宽度(默认 100 px)时主动变为省略模式。等同于应用 css:

width: 100px;
whiteSpace: nowrap
overflow: hidden;
textOverflow: ellipsis;

应用指令成果:

指令的代码如下:

export default function (el, binding) {
    el.style.width = binding.arg || 100 + 'px'
    el.style.whiteSpace = 'nowrap'
    el.style.overflow = 'hidden';
    el.style.textOverflow = 'ellipsis';
}

参数 Attributes:

而后你能够在模板中任何元素上应用新的 v-ellipsis property,如下:

<div v-ellipsis:100> 须要省略的文字是阿萨的正本阿萨的正本阿萨的正本阿萨的正本 </div>

6、回到顶部指令 v-backtop
应用该指令能够让页面或指定元素回到顶部。

可选指定元素,如果不指定则全局页面回到顶部。可选在元素偏移多少 px 后显示 backtop 元素,例如在滚动 400px 后显示回到顶部按钮。


指令的代码如下:

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) {const target = binding.arg ? document.getElementById(binding.arg) : window
    target.removeEventListener('scroll')
    el.removeEventListener('click')
  }
}

参数 Attributes:

而后你能够在模板中任何元素上应用新的 v-backtop property,如下示意在 id 为 app 的元素滚动 400px 后显示绑定指令的元素:

<div  v-backtop:app="400"> 回到顶部 </div>

也能够这样应用,示意为始终显示绑定指令的元素,并且是全局页面回到顶部:

<div  v-backtop> 回到顶部 </div>

7、空状态指令 v-empty
应用该指令能够显示缺省的空状态。能够传入默认图片(可选,默认无图片)、默认文字内容(可选,默认为暂无数据)、以及标示是否显示空状态(必选)。

指令的代码如下:

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%"></img>` : ''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)
    }
  },
}

参数 Attributes:

而后你能够在模板中任何元素上应用新的 v-empty property,如下传入对象 emptyValue:

<div style="height:500px;width:500px" v-empty="emptyValue"> 本来内容 

须要传入一个参数对象,例如显示文字为:暂无列表,图片门路为 ../../assets/images/blue_big.png,管制标示 visible:

emptyValue = {
  content: '暂无列表',
  img: require('../../assets/images/blue_big.png'),
  visible: true,
},

8、徽标指令 v-badge
应用该指令在元素右上角显示徽标。

反对配置徽标的背景色彩、徽标形态;反对传入徽标上显示的数字。

指令的代码如下:

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)
    let 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
  }
}

参数 Attributes:

而后你能够在模板中任何元素上应用新的 v-badge property,如下:

<div v-badge.dot.info="badgeCount" style="height:50px;width:50px;background:#999"> </div>

9、拖拽指令 v-drag
应用该指令能够对元素进行拖拽。

指令的代码如下:

export default {
  let _el = el
  document.onselectstart = function() {return false  // 禁止抉择网页上的文字}
  
  _el.onmousedown = e => {
    let disX = e.clientX - _el.offsetLeft // 鼠标按下,计算以后元素间隔可视区的间隔
    let disY = e.clientY - _el.offsetTop
    document.onmousemove = function(e){     
      let l = e.clientX - disX
      let t = e.clientY - disY;
      _el.style.left = l + "px"
      _el.style.top = t + "px"
    }
    document.onmouseup = e => {document.onmousemove = document.onmouseup = null}
    return false
  }
}

而后你能够在模板中任何元素上应用新的 v-drag property,如下:

<div v-drag> 反对拖拽的元素 </div>

10、响应缩放指令 v-resize
应用该指令能够响应元素宽高扭转时执行的办法。

指令的代码如下:

export default {bind(el, binding) {
    let width = '', height ='';
    function isReize() {const style = document.defaultView.getComputedStyle(el);
      if (width !== style.width || height !== style.height) {binding.value();  // 执行传入的办法
      }
      width = style.width;
      height = style.height;
     }
     el.__timer__ = setInterval(isReize, 300); // 周期性监听元素是否扭转
  },
  unbind(el) {clearInterval(el.__timer__);
  }
}

参数 Attributes:

而后你能够在模板中任何元素上应用新的 v-resize property,如下:

// 传入 resize() 办法
<div v-resize="resize"></div>

11、字符串整形指令 v-format
应用该指令能够批改字符串,如应用 v-format.toFixed 保留两位小数、v-format.price 将内容变成金额(每三位逗号分隔),能够同时应用,如 v-format.toFixed.price。

例如将数字 243112.331 变成 243112.33,或 243,112.33。

指令的代码如下:

export default {update (el, binding, vnode) {const { value, modifiers} = binding
    if (!value) return
    let formatValue = value
    if (modifiers.toFixed) {formatValue = value.toFixed(2)
    }
    console.log(formatValue)
    if (modifiers.price) {formatValue = formatNumber(formatValue)
    }
    el.innerText = formatValue
  },
}



function formatNumber (num) {
  num += '';
  let strs = num.split('.');
  let x1 = strs[0];
  let x2 = strs.length > 1 ? '.' + strs[1] : '';
  var rgx = /(\d+)(\d{3})/;
  while (rgx.test(x1)) {x1 = x1.replace(rgx, '$1' + ',' + '$2');
  }
  return x1 + x2
}

参数 Attributes:

而后你能够在模板中任何元素上应用新的 v-format property,如下:

<div v-format.toFixed.price="123333"> 123 </div>

如何应用这些指令?

为了便于管理指令,咱们将每个指令都存在于独自的 js 文件中。在我的项目的 src 下建一个 directives 目录,目录下新建 index.js 文件用于引入并注册指令。

├── src
|  ├── directive
|  |  ├── index.js
|  |  ├── backtop.js
|  |  ├── badge.js
|  |  ├── copy.js
|  |  ├── ellipsis.js
|  |  ├── empty.js
|  |  ├── expandClick.js
|  |  ├── screenfull.js
|  |  └── tooltips.js
|  ├── main.js

举个🌰:

directives 目录下新建 ellipsis.js 文件:

export default function (el, binding) {
    el.style.width = binding.arg || 100 + 'px'
    el.style.whiteSpace = 'nowrap'
    el.style.overflow = 'hidden';
    el.style.textOverflow = 'ellipsis';
}

directives 的 index.js 文件中引入 ellipsis 指令并注册:

import Vue from 'vue'
import ellipsis from './ellipsis' // 引入指令
// import other directives

const directives = {
  ellipsis
  // other directives
}

Object.keys(directives).forEach(name => Vue.directive(name, directives[name]))

最初在 mian.js 中引入 index.js 文件:

import '@/directives/index'

这样就能够失常应用这些指令了:

import '@/directives/index'

正文完
 0