vue2指令

v-copy(一键复制)

需求:实现一键复制文本内容,用于鼠标右键粘贴。
思路:
1、动态创建 textarea 标签,并设置 readOnly 属性及移出可视区域
2、将要复制的值赋给 textarea 标签的 value 属性,并插入到 body
3、选中值 textarea 并复制
4、将 body 中插入的 textarea 移除
5、在第一次调用时绑定事件,在解绑时移除事件

const copy = {
  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'
    }
  },
}

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('复制成功')
}
export default copy

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

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

v-textRoll(文字溢出滚动)

需求:实现文字在指定宽度的元素中无缝滚动,绑定参数可实现控制滚动速度

export default {
  inserted: (el, binding, vNode) => {
    el.style.overflow = 'hidden'
    el.style.whiteSpace = 'nowrap'
    const speed = binding.value || 60
    el.__text__ = `${vNode.children[0].text.trim()}`
    el.__span__ = document.createElement('span')
    el.__span__.innerHTML = el.__text__
    el.__span__.style.display = 'inline-block'
    el.innerHTML = ''
    el.appendChild(el.__span__)
    el.__spanWidth__ = el.__span__.offsetWidth
    el.isRoll = () => {
      if (el.__spanWidth__ > el.offsetWidth) {
        const times = binding.value || Math.max(Number(2 * el.__span__.offsetWidth - el.offsetWidth) / speed, 8)
        el.__span__.style.animation = `roll-text linear ${times}s normal infinite`
        el.__span__.innerHTML = `${el.__text__}&nbsp;&nbsp;&nbsp;&nbsp;${el.__text__}&nbsp;&nbsp;&nbsp;&nbsp;`
      } else {
        el.__span__.style.animation = 'none'
        el.__span__.innerHTML = `${el.__text__}`
      }
    }
    el.__observe__ = new ResizeObserver(el.isRoll)
    el.__observe__.observe(el, { box: 'border-box' })
  },
  componentUpdated(el, _, vNode) {
    el.__text__ = `${vNode.children[0].text.trim()}`
    el.__span__.innerHTML = el.__text__
    el.innerHTML = ''
    el.appendChild(el.__span__)
    el.__spanWidth__ = el.__span__.offsetWidth
    el.isRoll()
  },
  unbind: el => {
    el.__observe__.disconnect()
  },
}

需要配合动画样式实现

//文字滚动使用动画
@keyframes roll-text {
  0% {
    transform: translate3d(0%, 0, 0);
  }
  100% {
    transform: translate3d(-50%, 0, 0);
  }
}

v-clickOutside(点击外部触发)

需求:实现点击除设置指令的元素外部即可触发

参数:需要执行的方法

export default {
  bind(el, binding, vnode) {
    function documentHandler(e) {
      // 这里判断点击的元素是否是本身,是本身,则返回
      if (el.contains(e.target)) {
        return false
      }
      // 判断指令中是否绑定了函数
      if (binding && binding.expression) {
        // 如果绑定了函数 则调用那个函数,此处binding.value就是handleClose方法
        if (binding.value && binding.value(e)) {
          binding.value(e)
        }
      }
    }
    // 给当前元素绑定个私有变量,方便在unbind中可以解除事件监听
    el.__vueClickOutside__ = documentHandler
    document.addEventListener('click', documentHandler)
  },
  unbind(el, binding) {
    // 解除事件监听
    document.removeEventListener('click', el.__vueClickOutside__)
    delete el.__vueClickOutside__
  },
}

v-inputRule (限制输入框指定正则数据)

需求:输入框内容不满足输入的正则自动触发删除本次输入

// 正则规则可根据需求自定义

let findEle = (parent, type) => {
  return parent.tagName.toLowerCase() === type ? parent : parent.querySelector(type)
}

function isRegex(param) {
  return param instanceof RegExp
}

const trigger = (el, type) => {
  const e = new Event(type, { bubbles: true, cancelable: true })
  el.dispatchEvent(e)
}

const inputRule = {
  bind: function (el, binding, vnode) {
    el.regRule = binding.value
    el.$inp = findEle(el, 'input')
    el.$inp.handle = () => {
      let value = el.$inp.value
      if (value && isRegex(el.regRule)) {
        const splits = value.match(el.regRule)
        el.$inp.value = splits && splits.length ? splits[0] : ''
      }
      trigger(el.$inp, 'input')
    }
    el.$inp.handleBlur = () => {
      let value = el.$inp.value
      if (value && isRegex(el.regRule)) {
        const splits = value.match(el.regRule)
        el.$inp.value = splits && splits.length ? splits[0] : ''
      }
      trigger(el.$inp, 'input')
    }
    el.$inp.addEventListener('keyup', el.$inp.handle)
    el.$inp.addEventListener('blur', el.$inp.handleBlur)
  },
  unbind: function (el) {
    el.$inp.removeEventListener('keyup', el.$inp.handle)
    el.$inp.removeEventListener('blur', el.$inp.handleBlur)
  },
}

export default inputRule

常用正则:

正整数:/\d+/
负整数:/^-[1-9]\d*$/
大写英文字母:/^[A-Z]+$/
N位小数:new RegExp(`(^-)?\\d+(\\.\\d{0,${n}})?`)
 

上一篇:Ansible


下一篇:网际协议 - IP