一键复制功能v-copy指令的开发

202 阅读2分钟

类似于github中代码模块上,有一个复制按钮,复制代码内容的功能。本次封装是基于clip-board:2.0.11版本开发的一键复制指令 效果如下

copy.gif

安装clip-board

npm i clip-board@2.0.11

指令实现代码

import Clipboard from "clipboard";
import { ElMessage } from "element-plus" // 基于自己项目的ui框架引入提示功能
import { Directive, type DirectiveBinding } from "vue" //vue3+ts的写法,如果是vue2也可以不定义类型
import { debounce } from "@pureadmin/utils" // 基于自己项目的防抖函数位置去引入

function copyText(el: string|Element|NodeListOf<Element>): any {
const clipboard = new Clipboard(el)
//clipboard持续性监听复制成功与失败返回
clipboard.on("success", function() {
    ElMessage({
        message:"复制成功",
        type:"success"
    })
});
clipboard.on("erroe", function() {
    ElMessage({
        message:"复制失败",
        type:"erroe"
    })
});

const styles = {
    visibility: "hidden",
    minWidth: "24px",
    height: "24px",
    cursor: "pointer",
    padding: "3px",
    borderRadius: "4px",
    border: "1px solid #e2e4e7",
    backgroundColor: "#f6f8fa",
    color: "#656d76",
    margin: "0 4px",
}

export const copy: Directive = {
    created(el: HTMLElement, binding?: DirectiveBinding) {
        el.setAttribute("data-clipboard-text", binding.value) // 给对应模块绑定上要复制的内容
        const icon = document.createElement("span");
        icon.innerHTML = `复制前的svg图标`// 给复制功能增加防抖函数
        const handleCopy = debounce(
            () => {
            // 执行复制监听函数并提示复制结果
            copyText(el);
            icon.innerHTML = `复制成功后的✔svg图标`
            setTimeout( () => {
                //定时疫苗后再恢复原图标
                icon.innerHTML = `复制前的svg图标`;
            },1000,true
            );
        ) 
        //给icon绑定点击事件
        icon.onclick = handleCopy;
        // 绑定元素样式,让复制按钮始终位于第一排右侧上方
        for (const key of Object.keys(styles)) {
            icon.style[key] = styles[key];
            //有些ts设置的校验规则不一样,可能需要另外一种写法
            //    ;(icon as any).style[key] = (styles as any)[key]
        }
        // 模拟hover
        icon.onmouseenter = () => {
            icon.style.backgroundColor = "#dfdfdf";
        }
        icon.onmouseleave = () => {
            icon.style.backgroundColor = "#f6f8fa";
        }
        
        el.style.display = "flex";
        el.style.justifyContent = "space-between";
        el.style.whiteSpace = "normal";
        el.appendChild(icon);
        
        el.onmouseenter = () => {
            icon.style.visibility = "visible"
        }
        el.onmouseleave = () => {
            icon.style.visibility = "hidden"
        }
    }
    
    updated(el: HTMLElement, binding?: DirectiveBinding) {
        数据更新的时候重新绑定最新值
        el.setAttribute("data-clipboard-text", binding.value)
    }
}

指令注册

// 这个项目中我是全局注册的
// main.js
import * as directives from "@/directives";
Object.keys(directives).forEach( key => {
    app.directive(key,(directives as {{key:string]: Directive})[key])
})

// 也可以局部引入方法去使用

使用方法

<div v-copy="data.name"></div> 就能够直接复制name里面的值了

其他有趣文章的传送门:

image.png