【navigator.clipboard】复制链接弹出详情信息(模拟电商app)、页面中粘贴图片、复制文本自动添加版权信息
文章目录
- 复制链接弹出详情信息
- 页面中粘贴图片
- 复制文本自动添加版权信息
- 代码
参考:淘宝、京东复制好友链接弹出商品详情是如何实现的最近接到了一个需求很有意思,类似于我们经常在逛购物平台中,选择一个物品分享 -掘金
逛博客发现一个有趣的功能,加强了对navigator.clipboard
的理解,于是实现并记录一下。
复制链接弹出详情信息
复制链接到电商平台,会自动弹出商品详情信息。这里用前端技术栈实现一下。
思路:监听切回页面,查看剪切板第一个内容,如果是对应文案,则弹出一个弹窗。
切回页面:监听页面的visibilitychange
事件,当document.visibilityState === 'visible'
时,说明切回页面。(如果在客户端webview中,应该是onResume
事件。不过与本博客内容无关,不展开)
读剪切板:
navigator.clipboard
要在安全的上下文中使用,所以要判断兼容性setTimeout
是为了解决本地开发环境的报错:document is not focused,详情查看javascript - DOMException on calling navigator.clipboard.readText() - Stack Overflowdocument.execCommand
也可以实现复制粘贴等需求,且没有上述问题。但是此API已被声明弃用。权衡之下这里选择使用navigator.clipboard
。读者可以自行选择。详情查看:剪贴板操作 Clipboard API 教程 - 阮一峰的网络日志
if (window.isSecureContext && navigator.clipboard) {// setTimeout为了解决报错:https://stackoverflow.com/questions/56306153/domexception-on-calling-navigator-clipboard-readtext// document.execCommand 没有这个问题,但是已被声明弃用。权衡之下选择使用navigator.clipboardsetTimeout(() => {navigator.clipboard.readText().then((res) => {text.value = resif (isMyBlog(text.value)) {// 弹出一个弹窗dialogVisible.value = true}})}, 1000)} else {ElMessage.error('不支持剪切板navigator.clipboard')}
若剪切板的第一条是目标内容,则弹出弹窗:这里我将判断是否是我的博客。
const isMyBlog = (str: string) => {if (str.includes('/blog.csdn.net/karshey')) return truereturn false
}const handleVisibilityChange = () => {if (document.visibilityState === 'visible') {if (window.isSecureContext && navigator.clipboard) {// setTimeout为了解决报错:https://stackoverflow.com/questions/56306153/domexception-on-calling-navigator-clipboard-readtext// document.execCommand 没有这个问题,但是已被声明弃用。权衡之下选择使用navigator.clipboardsetTimeout(() => {navigator.clipboard.readText().then((res) => {text.value = resif (isMyBlog(text.value)) {dialogVisible.value = true}})}, 1000)} else {ElMessage.error('不支持剪切板navigator.clipboard')}}
}
页面中粘贴图片
在页面中粘贴图片,然后图片显示在页面上。
监听页面的粘贴:读取剪切板中第一个,若它是图片类型,则把它渲染到页面上。
// 页面中粘贴图片
const handlePaste = () => {if (window.isSecureContext && navigator.clipboard) {const clipboardApi = navigator.clipboardsetTimeout(() => {clipboardApi.read().then((clipboard) => {const img = clipboard[0]if (img.types.includes('image/png'))img?.getType('image/png').then((blob) => {// 如果之前有链接,要先释放它,否则会有内存泄漏if (imgUrl.value.length) {URL.revokeObjectURL(imgUrl.value)}imgUrl.value = URL.createObjectURL(blob)})})}, 1000)}
}
效果:
在csdn、掘金等博客平台,检测到粘贴时会把此图片上传到cdn,拿到图片链接后渲染。我们这里直接创建一个本地的链接。注意,当链接不需要时(这里的场景是粘贴了新图片),要释放链接:
if (imgUrl.value.length) {URL.revokeObjectURL(imgUrl.value)
}
否则会造成内存泄漏。
复制文本自动添加版权信息
监听复制事件,将选中内容+版权信息 写入剪切板。
const handleCopy = (e: Event) => {// 阻止默认的复制行为e.preventDefault()const selected = window.getSelection()?.toString()if (selected && window.isSecureContext && navigator.clipboard) {const copyWrite = '\n\n作者:karshey\n博客:https://blog.csdn.net/karshey'setTimeout(() => {const clipboardApi = navigator.clipboardclipboardApi.writeText(selected + copyWrite).then(() => {copyText.value = selected + copyWrite})}, 1000)}
}
代码
<template><div class="section"><h2>复制弹出详情</h2><div>当前剪切板:{{ text }}</div><div>如果复制了我的博客链接,则会弹出一个弹窗,模拟商品详情</div></div><div class="section"><h2>页面中粘贴图片</h2><img v-if="imgUrl.length" :src="imgUrl" alt="" height="200" /></div><div class="section"><h2>在此页面复制自动添加版权信息</h2><el-input v-model="copyText" disabled autosize type="textarea" :row="6"></el-input></div><el-dialog v-model="dialogVisible" title="Tips" width="500"><span><el-link :href="text" target="_blank">点击跳转到我的博客:{{ text }}</el-link></span><template #footer><div class="dialog-footer"><el-button type="primary" @click="dialogVisible = false"> 收到 </el-button></div></template></el-dialog>
</template><script lang="ts" setup>
import { onMounted, onUnmounted, ref } from 'vue'
import { ElMessage } from 'element-plus'
const text = ref('')
const dialogVisible = ref(false)
const imgUrl = ref('')
const copyText = ref('')onMounted(() => {document.addEventListener('visibilitychange', handleVisibilityChange)document.addEventListener('paste', handlePaste)document.addEventListener('copy', handleCopy)
})onUnmounted(() => {document.removeEventListener('visibilitychange', handleVisibilityChange)document.removeEventListener('paste', handlePaste)document.removeEventListener('copy', handleCopy)
})const isMyBlog = (str: string) => {if (str.includes('/blog.csdn.net/karshey')) return truereturn false
}const handleCopy = (e: Event) => {// 阻止默认的复制行为e.preventDefault()const selected = window.getSelection()?.toString()if (selected && window.isSecureContext && navigator.clipboard) {const copyWrite = '\n\n作者:karshey\n博客:https://blog.csdn.net/karshey'setTimeout(() => {const clipboardApi = navigator.clipboardclipboardApi.writeText(selected + copyWrite).then(() => {copyText.value = selected + copyWrite})}, 1000)}
}const handleVisibilityChange = () => {if (document.visibilityState === 'visible') {if (window.isSecureContext && navigator.clipboard) {// setTimeout为了解决报错:https://stackoverflow.com/questions/56306153/domexception-on-calling-navigator-clipboard-readtext// document.execCommand 没有这个问题,但是已被声明弃用。权衡之下选择使用navigator.clipboardsetTimeout(() => {navigator.clipboard.readText().then((res) => {text.value = resif (isMyBlog(text.value)) {dialogVisible.value = true}})}, 1000)} else {ElMessage.error('不支持剪切板navigator.clipboard')}}
}// 页面中粘贴图片
const handlePaste = () => {if (window.isSecureContext && navigator.clipboard) {const clipboardApi = navigator.clipboardsetTimeout(() => {clipboardApi.read().then((clipboard) => {const img = clipboard[0]if (img.types.includes('image/png'))img?.getType('image/png').then((blob) => {// 如果之前有链接,要先释放它,否则会有内存泄漏if (imgUrl.value.length) {URL.revokeObjectURL(imgUrl.value)}imgUrl.value = URL.createObjectURL(blob)})})}, 1000)}
}
</script><style lang="less" scoped>
.section {margin: 20px 0;
}
</style>
效果: