user-select:none真的能禁止文本的复制粘贴吗?

news2024/11/17 17:29:12

1. 前言

面向搜索引擎开发时,我们经常看到这样的情况:登录后复制。

由于设置了css属性 user-select:none,此时鼠标无法实现选中文本,也就无法复制文本,通常会采用这种方式来禁止复制文本。打开开发者工具-审查元素,取消此样式,就可以选中文本了。

但是,你们有尝试过这样的复制、粘贴吗?

咦,原来也可以不用登录后复制嘛。😎😎

其实,在记事本、textarea等纯文本框内粘贴是可以通过此属性达到禁止复制的功能,但是在富文本框内粘贴也就无能为力了。

那我们先了解下user-select,然后完善禁止复制的能力。

2. user-select

该属性用来控制用户能否选中文本。其对应常用的值:

  • none:元素及其子元素的文本不可选中。
  • auto:具体取值取决于一系列条件,具体如下:* 在 ::before 和 ::after 伪元素上,采用的属性值是 none* 如果元素是可编辑元素,则采用的属性值是 contain* 否则,如果此元素的父元素的 user-select 采用的属性值为 all,则该元素采用的属性值也为 all* 否则,如果此元素的父元素的 user-select 采用的属性值为 none,则该元素采用的属性值也为 none* 否则,采用的属性值为 text
  • text:用户可以选中文本。
  • all:当单击文本时,会选中这一行文本。

全部值如下:

/* Keyword values */
user-select: none;
user-select: auto;
user-select: text;
user-select: contain;
user-select: all;

/* Global values */
user-select: inherit;
user-select: initial;
user-select: revert;
user-select: revert-layer;
user-select: unset; 

3. 选中、复制、粘贴操作

单独选中带有user-select:none的文本样式是无法选中的,但是,我们借用可以选中的文本,虽然中间那个文本是无法看到拖蓝,跨段选中然后复制。

我们发现在富文本框,可以将设置了none的文本正确地粘贴了。前提需要借助可以复制的文本跨段选中。所以前言中“登录后复制”的代码也能使用这种方式,在wps等富文本编辑器中粘贴获得完整代码。

4. user-select:none如何实现禁止复制文本

在掘金中复制文章粘贴时,会发现文本最后会带上版权信息。既然可以悄悄的改动复制的文本内容,那我们也就可以控制哪些文本是否可以复制。

最终我们要实现的效果是,设置了user-select:none的节点,无论在纯文本内还是富文本框内粘贴,都不会粘贴出来,实现了真正的禁止复制,顺便添加版权信息。😏😏

首先,为网页添加copy事件。梦想开始的地方。

采用Selection对象获取到选中的文本,这里面包含了user-select:none节点。

window.addEventListener('copy',()=>{const selection = window.getSelection()const copyNode = selection.getRangeAt(0).cloneContents();
}) 

创建一个div,将copyNode放在div内,并挂载到dom树上,以便获取节点的user-select属性值,来控制是否需要复制该节点。

const div = document.createElement('div');
div.appendChild(copyNode);
// 通过getComputedStyle获取style值,需要将节点挂载到dom树上,因此append到body
document.body.appendChild(div);
const nodelist = div.childNodes;
for (let i = 0; i < nodelist.length; i++) {const curnode = nodelist[i];const nodeType = curnode.nodeType;// 重点操作// 将节点类型为元素节点,并且设置了user-select:none的节点从复制的内容中过滤掉if (nodeType === 1 && window.getComputedStyle(curnode).userSelect === 'none') {div.removeChild(curnode);}
}
// 获取过滤后的数据
const cpt = div.innerHTML; 

将处理好的数据设置为选中,顺便设置个版权信息。

// 又创建个div,将选区设置为此div
const div2 = document.createElement('div');
const copyright = `
<br><br>作者:Yue栎廷
<br>来源:<a href='https://juejin.cn/user/3421335917437134' target='_blank'>https://juejin.cn/user/3421335917437134掘金@Yue栎廷</a>
<br>著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
`
div2.innerHTML = cpt + copyright;
// 要设置选区,需要挂载在dom树上
document.body.appendChild(div2);
// 更新选区
selection.selectAllChildren(div2); 

我们创建了2个div,并且append到了页面上,这不应该对用户可见。因此:

1.通过设置css,将div放在页面不可见地方

const div2 = document.createElement('div');
+ div2.style.position = 'fixed';
+ div2.style.left = '9999px';
const copyright = `
<br><br>作者:Yue栎廷
<br>来源:<a href='https://juejin.cn/user/3421335917437134' target='_blank'>掘金@Yue栎廷</a>
<br>著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
` 

2.或者在操作最后及时移除节点

// 更新选区
selection.selectAllChildren(div2)
+ setTimeout(() => {
+document.body.removeChild(div2);
+document.body.removeChild(div);
+}) 

以上就是实现完整地禁止复制的全部代码。

戳一戳👇,快速体验:

5.你的👍是我创作的动力

网上大部分复制文本添加版权的做法是,通过window.getSelection().toString()获取到选中的文本,但是这种方法不会过滤掉设置了user-select:none的文本。

为什么没有通过剪切板去获取复制的文本数据呢? 因为copy事件触发时间是在实际复制操作之前,所以此时剪贴板内还没有数据,曲线救国采用了selection

其次,添加版权信息的做法是,通过window.clipboardData.setData('text', copyNode + copyright)将数据设置到剪贴板上,但是这种方法只能设置纯文本,无法粘贴带样式的文本,但是也可以通过设置新的选区来实现获取富文本数据。

之前在项目里用了此css属性来实现部分敏感信息的禁止复制,自己在开发自测时确实无法选中文本复制,但是上线后,用户反馈文本仍是可以复制并粘贴到同界面的一个富文本框内。后面了解到用户的复制操作是在鼠标拖蓝选中的文本中将不可选中的文本一起复制了,并刚好在富文本框内粘贴,防不胜防啊😭😭。

不过,看到此文的你们一定不会再有此bug!

最后

为大家准备了一个前端资料包。包含54本,2.57G的前端相关电子书,《前端面试宝典(附答案和解析)》,难点、重点知识视频教程(全套)。



有需要的小伙伴,可以点击下方卡片领取,无偿分享

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/186124.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

k-means聚类

一、概述 当前人工智能技术实现的一种主要手段是机器学习&#xff0c;而机器学习能够解决的问题主要有三种&#xff1a;分类、聚类、回归&#xff0c;有监督的是分类&#xff0c;无监督的是聚类。所谓聚类&#xff0c;就是以一定的方法将一堆样本依它们本身的数据特性划分成不同…

docker安装mongdb

MongoDB是一个介于关系数据库和非关系数据库之间的产品&#xff0c;是非关系数据库当中功能最丰富&#xff0c;最像关系数据库的。它支持的数据结构非常松散&#xff0c;是类似json的bson格式&#xff0c;因此可以存储比较复杂的数据类型。Mongo最大的特点是它支持的查询语言非…

【操作系统】备忘录

进程上下文切换 用户态、内核态 内核态&#xff1a;也叫内核空间&#xff0c;是内核进程/线程所在的区域。主要负责运行系统、硬件交互。 用户态&#xff1a;也叫用户空间&#xff0c;是用户进程/线程所在的区域。主要用于执行用户程序。 内核态与用户态的区别 内核态与用户…

spring mvc文档阅读笔记——02

目录标题一、Asynchronous Requests&#xff08;异步请求&#xff09;&#xff08;一&#xff09;阻塞和非阻塞,同步和异步&#xff08;二&#xff09;DeferredResult&#xff08;三&#xff09;Callable二、跨域请求CORS&#xff08;一&#xff09;实现跨域请求的方式&#xf…

数据持久化-RDB-AOF

定义 将数据从掉电易失的内存放到永久储存的设备上 因为所有的数据都在内存是&#xff0c;所有必须得持久化 redis提供两种持久化方案 RDB默认开启、AOF RDB 1,保存真是的数据 2&#xff0c;将服务器包含的所有数据库数据以二进制文件形式保存到磁盘里面 3&#xff0c;默认…

JDBC管理事务

基本介绍 就是处理在mysql的事务 复习一下:事务是一组sql语句需要开启和提交&#xff0c;事务中的sql语句要么全部生效&#xff0c;要么全部不生效&#xff0c;提交之后就是全部生效&#xff0c;中间可以设置保存点&#xff0c;回退到保存点&#xff0c;或直接回退到最开始事务…

1.2.1存储结构:层次化存储结构、外存(辅存)、内存(主存)、CPU内部的寄存器、Cache(相联存储器)

1.2.1存储结构&#xff1a;层次化存储结构、外存&#xff08;辅存&#xff09;、内存&#xff08;主存&#xff09;、CPU内部的寄存器、Cache&#xff08;相联存储器&#xff09;存储系统--层次化存储结构外存&#xff08;辅存&#xff09;内存&#xff08;主存&#xff09;CPU…

并发编程学习(八):ReentrantLock

ReentrantLock 是java.util.concurrent.locks包下的类。相对于synchronized,它具备如下特性&#xff1a;可中断。可以设置超时时间。可以设置公平锁。支持多个条件变量。即可以有个多个waitset等待队列。与synchronized都支持可重入。ReentrantLock的基本语法&#xff1a;// 获…

数学建模相关竞赛零基础上手与入门介绍

文章目录1、赛事介绍与报名2、学习与训练2.1 比赛题目选择范围2.2 赛前组队与分工2.3 比赛时间分配1、赛事介绍与报名 什么是数学建模&#xff1f; 定义&#xff1a; 生活中的各种问题(如股票预测、火灾报警统计等)&#xff0c;运用数学的方式去阐述并解决它。 数学建模赛事 …

cisp证书含金量怎么样?值不值得考?

这是CISP考试报名条件参考&#xff1a; 成为CISP&#xff0c;必须满足以下基本要求&#xff1a; 申请CISE、CISO注册资质&#xff0c;需满足以下教育和工作经验要求&#xff1a; &#xff08;1&#xff09;教育和工作经历要求&#xff1a;硕士及硕士以上学历&#xff0c;具备…

LabVIEW在实时目标上使用文件路径

LabVIEW在实时目标上使用文件路径文件路径和结构因目标操作系统而异。本文档讨论了推荐的LabVIEW编码实践&#xff0c;用于指定文件路径&#xff0c;以便应用程序可以无缝地从目标移动目标。实时操作系统选项所有NI实时控制器运行三种不同的操作系统之一&#xff0c;即PharLap、…

Find My资讯|美国航班取消,出行者疯狂购买苹果AirTag追踪行李箱

美国西南航空&#xff08;Southwest Airlines Co.&#xff09;由于所使用的 SkySolver 系统在圣诞假期间崩溃&#xff0c;导致航班出现大面积延误或取消&#xff08;大约 13000 个航班受到影响&#xff09;&#xff0c;让公司损失超过 8 亿美元&#xff08;当前约 53.76 亿元人…

5.kafka--生产调优

文章目录Leader Partition负载均衡消费者初始化流程消费者再平衡生产者和消费者如何提高吞吐量如何发送大消息Leader Partition负载均衡 参数名称描述auto.leader.rebalance.enable默认是true。自动LeaderPartition平衡。生产环境中&#xff0c;leader重选举的代价比较大&…

ADB快速入门

ADB快速入门 一、 简介 Android Debug Bridge&#xff0c;我们一般简称为adb&#xff0c;主要存放在sdk安装目录下的platform-tools文件夹中&#xff0c;它是一个非常强大的命令行工具&#xff0c;通过这个工具用来连接电脑和Android设备&#xff08;手机、电脑、电视、平板、…

LIO-SAM代码解析——imuPreintegration.cpp

目录imuPreintegration.cpp1. TransformFusion 类1.1. lidarOdometryHandler1.2. imuOdometryHandler2. IMUPreintegration 类2.1. imuHandler2.2. odometryHandler⭐2.2.1. 初始化系统, 把初始的lidar位姿&#xff0c;速度&#xff0c;零偏加入到因子图中2.2.2. 将两帧之间的i…

【深度学习】简述CNN分类网络的演变脉络及各自的贡献与特点

问题 简述CNN分类网络的演变脉络及各自的贡献与特点 综述 深度学习的浪潮就是从CNN开始的,它结构形态的变化也见证着这门技术的发展。现在涌进来学习深度学习的大部分人都是做计算机视觉的,因为这个门槛相对较低,业界数据集开源了很多,也比较直观,而且对硬件设备的要求…

2023年二月份图形化四级打卡试题

活动时间 从2023年 1月1日至1月21日&#xff0c;每天一道编程题。 本次打卡的规则如下&#xff1a; &#xff08;1&#xff09;小朋友每天利用10~15分钟做一道编程题&#xff0c;遇到问题就来群内讨论&#xff0c;我来给大家答疑。 &#xff08;2&#xff09;小朋友做完题目后&…

Spring Boot 整合Redis分布式锁 Lua脚本

参考&#xff1a;微服务 Spring Boot 整合Redis分布式锁 Lua脚本 实现优惠卷秒杀 一人一单_Bug 终结者的博客-CSDN博客 一、什么是Lua&#xff1f; Lua 是一个小巧的脚本语言。 其设计目的是为了通过灵活嵌入应用程序中从而为应用程序提供灵活的扩展和定制功能。Lua由标准C编…

MySQL事务学习笔记

事务就是保证一组数据库操作&#xff0c;要么全部成功&#xff0c;要么全部失败。事务的实现是在引擎层&#xff0c; 因此我们说的是InnoDB的事务。为何需要事务&#xff1f;比如有一个转钱的业务&#xff0c;A给B转100&#xff0c; 那么就是两条sql语句&#xff0c;一个是A的钱…

Spring Boot 热部署(热加载)

idea 热部署作用&#xff1a;自动帮开发者重启 spring boot 项目&#xff0c;从而达到修改代码之后能够“实时”的看到最新的效果1.添加热部署框架支持<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-devtools</…