vue-自定义directive实现v-copy指令

2,436 阅读2分钟

这是我参与更文挑战的第2天,活动详情查看: 更文挑战

注:以下是个人理解、如有不对还望指正!大概的效果

需求:

  • 项目多个页面需要使用、点击按钮默认选中文本复制、用户只需按ctrl + v 粘贴

考虑到技术栈是vue、而且vue也给我们提供了插件指令的形式、很简单的上手就能写出一个v-copy指令、所以开干吧

插件文档学习

文档地址

//template
<button v-copy:a="text">指令测试</button>

//data
data(){
    return {
        text:'复制的内容'
    }
}

//directive
Vue.directive('copys',{
    //被绑定元素插入父节点时调用 (仅保证父节点存在,但不一定已被插入文档中)
    inserted (el) {
        // console.log('父节点dom',el)
    },
    //只调用一次,指令第一次绑定到元素时调用。在这里可以进行一次性的初始化设置。
    bind(el,binding){
        console.log('dom',el)
        console.log(binding)
        // binding:{
        //     arg: "a" 传给指令的参数 v-copy:a
        //     def: {inserted: ƒ, bind: ƒ}
        //     expression: "day" 字符串形式的指令表达式
        //     modifiers: {}  修饰符的对象
        //     name: "copys"  指令名
        //     rawName: "v-copys:a"  //指令整体
        //     value:"复制的内容" //指令的绑定值
        // }
    },
    //在组件的 VNode 更新时调用
    update(el,binding,vnode,oldVnode){
    },
    //指令所在组件的 VNode 及其子 VNode 全部更新后调用
    componentUpdated(el,binding,vnode,oldVnode){
    },
    // 只调用一次,指令与元素解绑时调用
    unbind(el,binding,vnode,oldVnode,status){
        console.log(arguments)
    }
})

实战v-copy

  • 创建copy.js
export default { 
    bind(el, { value }) { 
        el.$value = value; 
        el.handler = (e) => {
            //阻止冒泡
            e.stopPropagation();
            //创建提示元素
            let addelement = (text,color) =>{
                //获取鼠标位置
                let scrollX = document.documentElement.scrollLeft || document.body.scrollLeft;
                let scrollY = document.documentElement.scrollTop || document.body.scrollTop;
                let x = e.pageX || e.clientX + scrollX;
                let y = e.pageY || e.clientY + scrollY;
                const $mes  = document.createElement('span');
                $mes.setAttribute('class','Copyspan');
                $mes.style = `position:fixed;left:${ x + 6 }px;top:${ y - 14}px;z-index:9999;font-size:12px; color:#343435; animation: Copyspan 800ms ease-in-out;color:${color}`;
                $mes.innerText = text;
                document.body.appendChild($mes);
                //500ms后移除
                setTimeout(()=>{
                    document.body.removeChild($mes);
                }, 500);
            }
            if (!el.$value) {
                addelement('复制成功','#f56c6c')
                return;
            }
            //创建copy元素textarea
            const $textarea = document.createElement('textarea');
            $textarea.readOnly = 'readonly';
            $textarea.style = {
                position:'absolute',
                left:'-9999px'
            }
            //赋值copy内容
            $textarea.value = el.$value;
            document.body.appendChild($textarea);
            $textarea.select();
            const result = document.execCommand('Copy');
            if (result) {
                addelement('复制成功','#67c23a')
            }
            document.body.removeChild($textarea);
        };
        el.addEventListener('click', el.handler);
    },
    //监听vnode变化后重新获取value
    componentUpdated(el, { value }) {
      el.$value = value;
    },
    //移除事件
    unbind(el) {
      el.removeEventListener('click', el.handler);
    },
};


  • main.js 全局注入
import copy from '@/directive/copy.js'
Vue.directive('copy',copy)

使用

<div v-copy="text">  复制的内容 </div>

总结

整体写下来不难、在vue的钩子做自己想做的逻辑操作、对原生js要求高一些