前端开发小技巧 - 【Vue / JS】 - 实现 复制、禁用复制、解禁 的功能

前言

  • 作为一名CV工程师,我经常在开发的过程中粘贴复制(纯纯的面向百度编程);
  • 但是在某些业务场景中需要我们开发粘贴复制功能;
  • 还有些业务场景需要我们去禁用复制功能;
  • 下面就来简单说一下基本的复制功能、禁用复制、还有解除禁用复制的基本实现;

一、Vue项目中使用VueUse实现复制功能

  • 以下是Vue3 + TS 的代码;
    • 如果在想在Vue2中使用VueUse,大家可以百度一下,等俺有空了补充上哈😁;
  • 使用VueUse提供的useClipboard函数实现复制功能;
  • 我们可以在 useClipboard() 里面解构很多东西,但是实现复制功能,我们只需要 copy()函数 和 isSupported属性;
ts 复制代码
import { useClipboard } from '@vueuse/core';
const { text, copy, copied, isSupported } = useClipboard();
// text ===> 文本
// copy ===> 拷贝函数
// copied ===> 是否拷贝成功,默认 1.5s 恢复状态
// isSupported ===> 是否支持拷贝(权限)
  • isSupported ===> 是否支持拷贝
    • 如果支持拷贝,给copy()传入字符串即可;
    • 只有在https的网站下才能去使用拷贝API,或者本地的localhost这种开发环境才能使用;
      • 从权限 Permissions API 获取权限之后,才能访问剪贴板内容;如果用户没有授予权限,则不允许读取或更改剪贴板内容;
      • 如果是https环境下,当使用剪贴板权限的时候,浏览器会弹出一个选择面板,如果选择的不授权,就没有拷贝权限,不能拷贝;
      • 如果是localhost本地环境,不换痰喘选择面板,默认就是支持拷贝的;
      • http网站是不支持的;
  • copy() ===> 拷贝函数
    • 该函数有一个参数,就是需要复制的字符串;
    • 该函数的返回值是 Promise,如果拷贝成功,Promise就执行成功;
html 复制代码
<script setup lang="ts">
import { ref } from 'vue';
import { useClipboard } from '@vueuse/core';
import{ showToast } from 'vant';

const { copy, isSupported } = useClipboard();

const text = ref<string>();

/** 复制函数 */
const onCopy = async () => {
    // 有权限才能去复制,没有权限就告诉用户没授权,提升用户体验
    if (!isSupported.value) return showToast('用户未授权!');
    // 这里需要判断,如果 text.value 为 undefined,就复制空串
    await copy(text.value || '');
    showToast('已复制!');
};
</script>

<template>
  <div>
    <input v-model="text" placeholder="请输入内容" />
    <button @click="onCopy">复制</button>
  </div>
</emplate>

<style>
div {
  display: flex;
}

input {
  font-size: 18px;
}

button {
  margin-left: 10px;
}
</style>
  • 效果展示

二、原生JS实现复制、禁用复制

2.1 实现复制功能

  • 这里就简单使用原生JS实现一下基本的复制功能;

  • 下面提供两种复制方法;

  • 模板代码:

    html 复制代码
    <!DOCTYPE html>
    <html lang="en">
    
    <head>
      <meta charset="UTF-8">
      <meta name="viewport" content="width=device-width, initial-scale=1.0">
      <title>Document</title>
      <style>
        * {
          margin: 0;
          padding: 0;
          box-sizing: border-box;
        }
    
        p {
          width: 500px;
          margin: 100px auto;
          font-size: 20px;
        }
    
        .copy-box {
          display: flex;
          justify-content: center;
          align-items: center;
          width: 500px;
          height: 100px;
          margin: 100px auto;
          padding: 20px;
          border: 2px solid red;
          border-radius: 8px;
        }
    
        input {
          width: 400px;
          height: 40px;
          padding: 10px;
          font-size: 20px;
          border-color: #fff;
          box-shadow: 0 0 10px 1px rgba(0, 0, 0, .2);
          outline: none;
        }
    
        button {
          width: 80px;
          height: 40px;
          margin-left: 20px;
          font-size: 20px;
          outline: none;
          cursor: pointer;
          border-radius: 20px;
          border-color: #fff;
          box-shadow: 0 0 10px 1px rgba(0, 0, 0, .2);
        }
    
        button:disabled {
          cursor: not-allowed;
        }
      </style>
    </head>
    
    <body>
      <div class="copy-box">
        <input type="text" name="" id="input" autocomplete="off">
        <button disabled>复制</button>
      </div>
    </body>
    
    </html>

2.1.1 ✅ 创建新元素实现复制

  • 点击 复制按钮 的时候,使用 documnet.createElement() 创建一个元素(b元素),将 a元素的文本内容(需要赋值的文本)赋值给b元素,使用select()方法选中创建元素的文本内容,执行复制命令,将复制的文本添加到用户的剪贴板;

疑问

  • 为什么不直接执行a元素的select()方法,这样就不用创建元素,直接将选中的文本添加到用户的剪贴板???
    • 这样也是可以的,但是会有问题,就是执行a元素的select()方法后,a元素中的文本内容的状态就是选中状态(整段文字的背景颜色是蓝色);
    • 如果当前部门业务那边对这一点没有意见的话,就可以直接使用这种方法(详细看2.1.1);
    • 关于选中状态之后的变化,下一小节详细说一下;
    • 当前小结只关注使用创建元素实现复制功能;
  • 基于上述模板代码;
js 复制代码
/**
 * 复制函数
 * @param { string } text 需要复制的文本内容
 * @returns { void }
 */
function copyToClipboard(text) {
  // 看当前需求,如果用户没有输入内容也能复制的话,就将 button 元素的 disabled 属性去掉,用户复制的就是空串;
  // 还有一种就是不禁用按钮,但是当用户没有输入内容就去点击复制的话,我们可以去给用户一个提示;
  
  // 创建元素
  const copyFrom = document.createElement('textarea');
  // 设置元素的内容
  copyFrom.value = text;
  // 将创建的元素添加到body中
  document.body.appendChild(copyFrom);
  // 选中元素
  copyFrom.select();
  // 执行复制命令,将文本添加到用户的剪贴板
  document.execCommand('copy');
  // 删除创建的元素
  document.body.removeChild(copyFrom);
}

// 获取 input 元素
const input = document.querySelector('#input');

// 获取 button 按钮
const btn = document.querySelector('button');

// 给 button 元素 绑定事件
button.addEventListener('click', () => {
  copyToClipboard(input.value);
  alert('复制成功!');
});
  • 效果演示:

2.1.2 复制现有元素的文本

  • 在点击复制按钮的时候,使用select()选中input元素的值,将input的值添加到用户的剪贴板即可;
  • 问题
    • 使用select()方法之后,文本的状态会变成选中状态(选中的文本背景颜色变为蓝色);
  • 解决问题
    • 修改选中文本的背景颜色;
  • 基于上述模板代码;
js 复制代码
// 获取元素
const btn = document.querySelector('button');
const input = document.querySelector('#text');

// 监听input的输入事件,有值就解除button按钮的禁用状态
input.addEventListener('input', (e) => {
  if (e.target.value) btn.removeAttribute('disabled');
  else btn.setAttribute('disabled', true);
});

// 给button按钮绑定事件
btn.addEventListener('click', (e) => {
  try {
    // 选中input框中的文本
    input.select();
    // 将选中的文本复制到剪贴板
    document.execCommand('copy');
    alert('复制成功!');
  } catch (err) {
    console.log(err);
  }
});
  • 效果演示:

  • 修改选中文本的背景颜色:

    ::selectio 该伪类选择器的可选属性有四个,分别是: color、background、cursor、outline

    css 复制代码
    #input::selection {
      // 将选中文本的背景颜色改为透明色
      background: transparent;
    }
    
    // 火狐浏览器
    #input::-moz-selection {
      // 将选中文本的背景颜色改为透明色
      background: transparent;
    }
js 复制代码
<script>
    // 监听整个文件流的复制
    document.addEventListener('copy', function (e) {
        // 阻止浏览器的默认行为,不让复制
        e.preventDefault();
        // 给用户的剪贴板里面增加一些数据
        // e.clipboardData ===> 剪贴板对象
        // text/plain ===> 纯文本数据 
        e.clipboardData.setData('text/plain', '复制成功');
    });
</script>

2.2 禁用复制

  • 模板代码:

    html 复制代码
    <!DOCTYPE html>
    <html lang="en">
    
    <head>
      <meta charset="UTF-8">
      <title>Title</title>
      <style>
        p {
          width: 500px;
          margin: 100px auto;
          font-size: 20px;
        }
      </style>
    </head>
    
    <body>
      <p>
        In the flood of darkness, hope is the light. It brings comfort, faith, and confidence. It
        gives us guidance when we are lost, and gives support when we are afraid. And the moment we give up hope, we give
        up our lives. The world we live in is disintegrating into a place of malice and hatred, where we need hope and
        find it harder. In this world of fear, hope to find better, but easier said than done, the more meaningful life of
        faith will make life meaningful.
      </p>
    </body>
    
    </html>
  • 在JS的事件中,有个 copy事件 ,当检测到 复制 的时候会 触发该事件

  • 事件对象.clipboardData ===> 剪贴板对象 提供了以下方法:
    • setData(type, data) :
      • 将指定的 type 类型的数据设置为剪贴板的内容。data 参数是要设置的数据。
    • getData(type) :
      • 返回剪贴板中指定 type 类型的数据。如果找不到指定类型的 data,则返回 null。
    • clearData() :
      • 清除剪贴板中所有类型的数据。
    • readData() :
      • 返回一个包含剪贴板中所有类型的数据的对象。
  • ❗❗ 注意
    • e.clipboardData 对象只在 'copy' 事件中可用。
  • 代码展示:

    js 复制代码
    // 监听复制事件
    document.addEventListener('copy', (e) => {
      // 阻止默认行为 - 复制行为
      e.preventDefault();
      // 给用户的剪贴板设置文本数据
      e.clipboardData.setData('text/plain', '复制成功!');
      alert('复制一次1块钱!');
      
      // 相关逻辑 - 弹出一个微信收款码😂😂
    });

三、解除禁用复制

  • 解除禁用复制用的最多的莫过于我们去一些网站复制文本的时候,他不让我们复制,还要收费,直接就是干他😡;
  • 废话不多说,直接上动画,以各位的聪明才智,一看就懂:
相关推荐
小镇程序员3 分钟前
vue2 src_Todolist消息订阅版本
前端·javascript·vue.js
Zack No Bug11 分钟前
解决报错:rror: error:0308010C:digital envelope routines::unsupported
前端·javascript·vue.js
飞奔的波大爷21 分钟前
springboot vue工资管理系统源码和答辩PPT论文
vue.js·spring boot·后端
QTX1873022 分钟前
原生JS和CSS,HTML实现开屏弹窗
javascript·css·html
rhythmcc1 小时前
【GoogleChrome】在开发者工具中修改js、css并生效
开发语言·javascript·css
凌虚1 小时前
Web 端语音对话 AI 示例:使用 Whisper 和 llama.cpp 构建语音聊天机器人
前端·人工智能·后端
小宇python1 小时前
Web应用安全入门:架构搭建、漏洞分析与HTTP数据包处理
前端·安全·架构
珹洺2 小时前
从 HTML 到 CSS:开启网页样式之旅(二)—— 深入探索 CSS 选择器的奥秘
前端·javascript·css·网络·html
竺梓君2 小时前
JavaScript内存管理机制解析
javascript·全栈
liro2 小时前
CSS盒子模型
前端