前端js常用剪贴板(复制粘贴)操作和应用,以及navigator.clipboard新粘贴板API使用

最近的项目上需要做复制粘贴相关的操作,来总结下吧

复制、剪切、粘贴事件:

  • copy 发生复制操作时触发;
  • cut 发生剪切操作时触发;
  • paste 发生粘贴操作时触发;

每个事件都有一个 before 事件对应:beforecopy、beforecut、beforepaste;
这几个 before 一般不怎么用,所以我们把注意力放在三个事件就可以了。

触发条件:

  1. 鼠标右键菜单的复制、粘贴、剪切;
  2. 使用了相应的键盘组合键,比如:ctrl+c、ctrl+v;

复制操作:

copy事件使用示例:

<body>
	gggwgzgf
</body>
<script type="text/javascript">
	document.body.oncopy = e => {
     
     
	  // 监听全局复制 做点什么
	  console.log(e)
	};
</script>

在这里插入图片描述
我们可以看到事件对象中的属性:
在这里插入图片描述
我们主要研究的是里面的clipboardData属性对象

clipboardData 对象: 用于访问以及修改剪贴板中的数据
clipboardData对象中有两个方法:

  • getData():常配合copy事件使用,用于设置到剪贴板中的值

  • setData():常配合paste事件使用,用于获取设置到剪贴板中的值

兼容:

不同浏览器,所属的对象不同:在 IE
中这个对象是window对象的属性,在Chrome、Safari和Firefox中,这个对象是相应的event对象的属性。所以我们在使用的时候,需要做一下如下兼容:

document.body.oncopy = e => {
    
    
  let clipboardData = e.clipboardData || window.clipboardData;
  // 获取clipboardData对象 + do something
};

copy配合getSelection实现复制某段文本:

<body>
		gggwgzgf
	</body>
	<script type="text/javascript">
		document.body.oncopy = e => {
     
     
			console.log(window.getSelection().toString())
			let copyMsg = window.getSelection().toString()
			//把值设置到剪贴板中,方便paste事件触发去拿
			e.clipboardData.setData("Text", copyMsg);
		};
	</script>

为了方便,这次,我直接使用ctrl+c测试了
在这里插入图片描述

注意:window.getSelection().toString()我是调用toString()方法转成文本的,如果不调用这个方法,直接通过window.getSelection()取到值存到剪贴板会有出奇的效果,后面会说到,需要配合paste事件

粘贴paste事件

使用示例:

<body>
		gggwgzgf
		<input placeholder="这里存放粘贴操作的值" />
	</body>
	<script type="text/javascript">
		document.body.oncopy = e => {
     
     
			console.log(window.getSelection().toString())
			let copyMsg = window.getSelection().toString()
			e.clipboardData.setData("Text", copyMsg);
		};
		
		document.body.onpaste=function(e){
     
     
				var data = e.clipboardData.getData("Text")
				document.querySelector("input").value = data
			}
	</script>

在这里插入图片描述
到这里,你可能有个疑问,只能复制粘贴文本吗,图片可以吗?
这是可以的。

通过patse事件获取剪切板中的图片:

<script type="text/javascript">
		document.addEventListener('paste', function(event) {
     
     
			var items = (event.clipboardData && event.clipboardData.items) || [];
			var file = null;
			if(items && items.length) {
     
     
				for(var i = 0; i < items.length; i++) {
     
     
					if(items[i].type.indexOf('image') !== -1) {
     
     
						file = items[i].getAsFile();
						break;
					}
				}
			}
			console.log(file)
		});
</script>

解释: 当粘贴事件触发时遍历剪切版对象(clipboardData)中的所有items,找到类型为图片的item并调用getAsFile方法得到文件对象

拿到file 对象后我们有几种选择:

  1. 通过fileReader得到文件对象的base64字符串
var reader = new FileReader();
reader.onload = function(e){
    
    
// 通过e.target.result取到base64然后上传
// 作为src设到image标签上预览
}
reader.readAsDataURL(file); //此处的file为上面得到的文件对象```
  1. 通过formData文件对象转换为二进制数据
var formData = new FormData();
formData.append('file', file);
  1. 通过 URL.createObjectURL转成url地址预览
var blobUrl=URL.createObjectURL(file)

示例代码:

    <body>
		<img src="" id="imgTest" />
	</body>
	<script type="text/javascript">
		document.addEventListener('paste', function(event) {
     
     
			var items = (event.clipboardData && event.clipboardData.items) || [];
			var file = null;
			if(items && items.length) {
     
     
				for(var i = 0; i < items.length; i++) {
     
     
					if(items[i].type.indexOf('image') !== -1) {
     
     
						file = items[i].getAsFile();
						break;
					}
				}
			}
			var blobUrl = URL.createObjectURL(file);
			document.getElementById("imgTest").src = blobUrl;
		});
	</script>

在这里插入图片描述
局限性:
对于qq,微信等的截图或者按print screen得到的截图,还有任意网页的右击复制图片都能完美支持,但是,对于电脑本地图片文件的复制没办法从剪切版获取到



进阶用法:

配合window.getSelection(),文字图片混合复制粘贴:

    <body>
		<span>gegegseraw</span>
		<img src="a1.png" width="100" />
		<hr />
		下面为粘贴区域:
		<div></div>
	</body>
	<script type="text/javascript">
		document.body.oncopy = function(e) {
     
      
			let copyMsg = window.getSelection()
			e.clipboardData.setData("Text", copyMsg);
		}

		document.body.addEventListener('paste', function(event) {
     
     
			var data = (event.clipboardData && event.clipboardData.items) || [];
			console.log(data)
			let div = document.querySelector("div")
			for(var i = 0; i < data.length; i += 1) {
     
     
				if((data[i].kind == 'string') &&
					(data[i].type.match('^text/plain'))) {
     
     
					// This item is the target node
					console.log("... Drop:plain")
				} else if((data[i].kind == 'string') &&
					(data[i].type.match('^text/html'))) {
     
     
					// Drag data item is HTML
					data[i].getAsString(function(s) {
     
     
						div.innerHTML = s
					});
					console.log("... Drop: HTML");
				} else if((data[i].kind == 'string') &&
					(data[i].type.match('^text/uri-list'))) {
     
     
					// Drag data item is URI
					console.log("... Drop: URI");
				} else if((data[i].kind == 'file') &&
					(data[i].type.match('^image/'))) {
     
     
					// Drag data item is an image file
					console.log("... Drop: File ");
				}
			}

		});
	</script>

效果:
在这里插入图片描述


navigator.clipboard介绍:

异步剪贴板 API 是一个相对较新的 API,浏览器仍在逐渐实现它。由于潜在的安全问题和技术复杂性,大多数浏览器正在逐步集成这个 API。剪贴板 Clipboard APINavigator 接口添加了只读属性 clipboard,该属性返回一个可以读写剪切板内容的 Clipboard 对象。 在 Web 应用中,剪切板 API 可用于实现剪切、复制、粘贴的功能。

系统剪贴板暴露于全局属性 Navigator.clipboard 之中,Navigator.clipboard对象中有四个常用方法:都是异步的

  • read():从剪贴板读取数据(比如图片),返回一个 Promise 对象。
  • readText():从操作系统读取文本,返回一个 Promise 对象。
  • write():写入任意数据至操作系统剪贴板,返回一个 Promise 对象。
  • writeText():写入文本至操作系统剪贴板,返回一个 Promise 对象。

注意:只有在用户事先授予网站或应用对剪切板的访问许可之后,才能使用异步剪切板读写方法。许可操作必须通过取得权限 Permissions API"clipboard-read" 和/或 "clipboard-write" 项获得。

使用实例:

复制writeText():

navigator.clipboard.writeText('要复制的文本')
  .then(() => {
    
    
    console.log('文本已经成功复制到剪切板');
  })
  .catch(err => {
    
    
    // 如果用户没有授权,则抛出异常
    console.error('无法复制此文本:', err);
  });

async,await优化写法:

async function copyPageUrl() {
    
    
  try {
    
    
    await navigator.clipboard.writeText(location.href);
    console.log('Page URL copied to clipboard');
  } catch (err) {
    
    
    console.error('Failed to copy: ', err);
  }
}

粘贴readText():

navigator.clipboard.readText()
  .then(text => {
    
    
    console.log('Pasted content: ', text);
  })
  .catch(err => {
    
    
    console.error('Failed to read clipboard contents: ', err);
  });

同理也可写成async,await

write()写入数据/图片:

function setClipboard(text) {
    
    
  let data = new DataTransfer();
  data.items.add("text/plain", text);
  navigator.clipboard.write(data).then(function() {
    
    
    /* success */
  }, function() {
    
    
    /* failure */
  });
}

代码创建了一个 DataTransfer 对象,要替换的内容存储在这里。执行 DataTransferItemList.add() 将数据写入进去,然后执行 write() 方法,指定执行成功或错误的结果。

read()读取数据/图片:

 navigator.clipboard.read().then(data => {
    
    
      for (let i=0; i<data.items.length; i++) {
    
    
        if (data.items[i].type != "text/plain") {
    
    
          alert("Clipboard contains non-text data. Unable to access it.");
        } else {
    
    
          textElem.innerText = data.items[i].getAs("text/plain");
        }
      }
    });



应用:

实现类知乎/掘金复制大段文本添加版权信息:

  <body>
		<span>0123456789abcdefg</span>
		<hr /> 下面为粘贴区域:
		<div></div>
	</body>
	<script type="text/javascript">
		document.body.oncopy = event => {
     
     
			event.preventDefault(); // 取消默认的复制事件
			let textFont = null
			let copyFont = window.getSelection().toString(); // 被复制的文字 等下插入
			// 防知乎掘金 复制一两个字则不添加版权信息 超过一定长度的文字 就添加版权信息
			if(copyFont.length > 10) {
     
     
				textFont =`
					内容: ${
       
       copyFont} 
					作者:codingWeb 
					链接:https://blog.csdn.net/fesfsefgs
					来源:csdn 
					著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。`
			} else {
     
     
				textFont = copyFont; // 没超过十个字 则采用被复制的内容。
			}
		   event.clipboardData.setData('text', textFont); // 将信息写入粘贴板
		};

		document.body.onpaste = function(event) {
     
     
			var data = event.clipboardData.getData("text")
			document.querySelector("div").innerHTML = data
		}
		
	</script>	

在这里插入图片描述


实现类起点网的防复制功能:

  1. 禁止复制+剪切
  2. 禁止右键,右键某些选项:全选,复制,粘贴等。
  3. 禁用文字选择,能选择却不能复制,体验很差。
  4. user-select 用 css 禁止选择文本。
// 禁止右键菜单
document.body.oncontextmenu = e => {
    
    
    console.log(e, '右键');
    return false;
    // e.preventDefault();
};
// 禁止文字选择。
document.body.onselectstart = e => {
    
    
    console.log(e, '文字选择');
    return false;
    // e.preventDefault();
};
// 禁止复制
document.body.oncopy = e => {
    
    
    console.log(e, 'copy');
    return false;
    // e.preventDefault();
}
// 禁止剪切
document.body.oncut = e => {
    
    
    console.log(e, 'cut');
    return false;
    // e.preventDefault();
};
// 禁止粘贴
document.body.onpaste = e => {
    
    
    console.log(e, 'paste');
    return false;
    // e.preventDefault();
};
// css 禁止文本选择 这样不会触发js
body {
    
    
    user-select: none;
    -moz-user-select: none;
    -webkit-user-select: none;
    -ms-user-select: none;
}

提示: 使用e.preventDefault()也可以禁用,示例中document.body全局都禁用了,也可以对 dom(某些区域)进行禁用。


点击复制功能:

不能使用 clipboardData:

在 IE 中可以用window.clipboardData.setData('text','内容')实现。因为,在 IE
clipboardDatawindow的属性。而其他浏览器则是相应的event对象的属性,这实际上是一种安全措施,防止未经授权的访问,为了兼容其他浏览器,所以我们不能通过clipboardData来实现这种操作。

具体做法:

  1. 创建一个隐藏的input框
  2. 点击的时候,将要复制的内容放进input框中
  3. 选择文本内容input.select()
  4. 这里只能用input或者textarea才能选择文本。
  5. document.execCommand(“copy”),执行浏览器的复制命令。

示例:

<body>
		<button>#aaaaaa</button>
		<button>#bbbbbb</button>
		<button>#ffffff</button>
		<input />
	</body>
	<script type="text/javascript">
		function copyText(e) {
     
     
			var text = e.target.innerHTML; // 获取要复制的内容也可以传进来
			var input = document.querySelector('input'); // 获取隐藏input的dom
			input.value = text; // 修改文本框的内容
			input.select(); // 选中文本
			document.execCommand('copy'); // 执行浏览器复制命令
			console.log('复制成功');
		}
		
		document.body.onclick=copyText
	</script>

在这里插入图片描述

扩展:

如果不通过手动点击元素触发click事件,代码控制,我们都知道,可以使用dom.click()触发一次点击操作
那别的事件也可以通过代码控制触发吗?
答案是可以的

事件模拟:

		function trigger(el,type){
    
    
				let ev = document.createEvent("HTMLEvents")
				ev.initEvent(type,true,true)
				el.dispatchEvent(ev)
			}

使用:

trigger(domEle,"copy")
trigger(domEle,"paste")

键盘模拟:

 let mockKeyboardEvent = new KeyboardEvent('keyup', {
    
     shiftKey: true, keyCode: 49 })
   document.dispatchEvent(mockKeyboardEvent)

鼠标模拟:

let mockClickEvent = new MouseEvent('click', {
    
    ...});
document.dispatchEvent(mockClickEvent);

自定义事件模拟:(推荐)

//绑定
 document.body.onpaste = function (e) {
    
    
      console.log(e)
    }
//触发,携带自定义参数
   let myEvent = new CustomEvent('paste', {
    
    
     detail: {
    
    
       username: 'aaaaaaa',
       password: '11111111'
     }
   })
   document.body.dispatchEvent(myEvent)

在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/fesfsefgs/article/details/111875639
今日推荐