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__} ${el.__text__} `
} 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}})?`)