js中navigator.clipboard的兼容性问题
作者:oxygen_ls
使用navigator.clipboard实现复制的时候,在本地测试没有问题,但是上线之后复制不能正常使用,这个问题可能是由于浏览器安全策略导致的,下面就来介绍一下navigator.clipboard兼容性,感兴趣的可以了解一下
问题描述
在实现快捷复制的时候出现的一个问题,使用navigator.clipboard实现复制的时候,在本地测试没有问题,但是上线之后复制不能正常使用。
问题分析
这个问题可能是由于浏览器安全策略导致的。在本地开发环境中,navigator.clipboard API 可以正常工作,但在生产环境中,由于安全限制,只有在以下条件下才能使用剪贴板API:1. 网站必须使用HTTPS协议;2. 网页必须处于活动标签页;3. 用户必须已经授予剪贴板权限。建议检查生产环境是否满足这些条件,特别是HTTPS协议的支持情况。如果确实是HTTPS环境,那么可能是浏览器没有正确授予剪贴板权限,或者在某些浏览器中clipboard API的支持存在兼容性问题。但是我使用同一个浏览器,排除浏览器兼容,发现是上线之后的协议是http协议。
解决方案
由于环境使用的是HTTP协议,而navigator.clipboard API在非HTTPS环境下会受到安全策略限制。有以下解决方案:1. 将网站升级到HTTPS协议(推荐);2. 使用传统的document.execCommand(‘copy’)方法作为降级方案;3. 如果必须使用HTTP,可以考虑使用第三方复制库如clipboard.js作为替代方案。因为使用什么协议不是我决定的,所以最后用传统的document.execCommand(‘copy’)做降级处理。
代码:
降级之前代码
<template>
<div class="text-container" @mouseenter="showButton = true" @mouseleave="showButton = false">
<!-- 复制按钮,仅在鼠标悬停时显示 -->
<el-tooltip placement="top" content="复制">
<el-icon v-if="showButton" class="copy-button" @click="handleCopy"><CopyDocument /></el-icon>
</el-tooltip>
<!-- 显示的内容 -->
<div class="content">
<slot></slot>
</div>
</div>
</template>
<script setup>
import { ref } from "vue";
import { CopyDocument } from "@element-plus/icons-vue";
import { message } from "@/utils/message";
// 定义 Props
const props = defineProps({
text: {
type: String,
required: true // 必填项,表示需要复制的文字
}
});
// 控制复制按钮的显示状态
const showButton = ref(false);
// 复制文本到剪贴板
const handleCopy = () => {
navigator.clipboard
.writeText(props.text)
.then(() => {
message("复制成功", { type: "success" });
})
.catch(err => {
console.error("复制失败:", err);
message("复制失败", { type: "error" });
});
};
</script>
<style lang="scss">
/* 基本样式 */
.text-container {
position: relative; /* 父容器设置为相对定位 */
display: block;
padding: 0 10px;
min-height: 24px; /* 确保容器有足够的高度 */
}
/* 内容区域 */
.content {
padding-right: 30px; /* 为图标预留空间 */
word-break: break-word; /* 允许文字换行 */
}
/* 复制按钮样式 */
.copy-button {
position: absolute;
top: 50%;
right: 10px; /* 固定在最右侧并留出一些间距 */
transform: translateY(-50%); /* 垂直居中 */
color: #409eff;
cursor: pointer;
font-size: 16px;
transition: all 0.3s;
&:hover {
color: #66b1ff;
}
}
/* 使用伪类创建背景区域 */
.copy-button::after {
content: "";
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
width: 32px; /* 背景宽度 */
height: 32px; /* 背景高度 */
background-color: rgba(0, 0, 0, .03); /* 背景颜色和透明度 */
border-radius: 6px; /* 圆角效果 */
z-index: -1; /* 确保背景区域在图标后面 */
opacity: 0; /* 默认隐藏 */
transition: opacity 0.3s; /* 平滑过渡效果 */
}
/* 悬停时显示背景区域 */
.copy-button:hover::after {
opacity: 1; /* 显示背景 */
}
</style>
优雅降级之后
<template>
<div class="text-container" @mouseenter="showButton = true" @mouseleave="showButton = false">
<!-- 复制按钮,仅在鼠标悬停时显示 -->
<el-tooltip placement="top" content="复制">
<el-icon v-if="showButton" class="copy-button" @click="handleCopy"><CopyDocument /></el-icon>
</el-tooltip>
<!-- 显示的内容 -->
<div class="content">
<slot></slot>
</div>
</div>
</template>
<script setup>
import { ref } from "vue";
import { CopyDocument } from "@element-plus/icons-vue";
import { message } from "@/utils/message";
// 定义 Props
const props = defineProps({
text: {
type: String,
required: true // 必填项,表示需要复制的文字
}
});
// 控制复制按钮的显示状态
const showButton = ref(false);
// 复制文本到剪贴板
const handleCopy = async () => {
try {
// 优先使用 navigator.clipboard API
if (navigator.clipboard && window.isSecureContext) {
await navigator.clipboard.writeText(props.text);
message("复制成功", { type: "success" });
return;
}
// 降级使用 document.execCommand
const textArea = document.createElement('textarea');
textArea.value = props.text;
document.body.appendChild(textArea);
textArea.select();
const successful = document.execCommand('copy');
document.body.removeChild(textArea);
if (successful) {
message("复制成功", { type: "success" });
} else {
message("复制失败", { type: "error" });
}
} catch (err) {
console.error("复制失败:", err);
message("复制失败", { type: "error" });
}
};
</script>
<style lang="scss">
/* 基本样式 */
.text-container {
position: relative; /* 父容器设置为相对定位 */
display: block;
padding: 0 10px;
min-height: 24px; /* 确保容器有足够的高度 */
}
/* 内容区域 */
.content {
padding-right: 30px; /* 为图标预留空间 */
word-break: break-word; /* 允许文字换行 */
}
/* 复制按钮样式 */
.copy-button {
position: absolute;
top: 50%;
right: 10px; /* 固定在最右侧并留出一些间距 */
transform: translateY(-50%); /* 垂直居中 */
color: #409eff;
cursor: pointer;
font-size: 16px;
transition: all 0.3s;
&:hover {
color: #66b1ff;
}
}
/* 使用伪类创建背景区域 */
.copy-button::after {
content: "";
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
width: 32px; /* 背景宽度 */
height: 32px; /* 背景高度 */
background-color: rgba(0, 0, 0, .03); /* 背景颜色和透明度 */
border-radius: 6px; /* 圆角效果 */
z-index: -1; /* 确保背景区域在图标后面 */
opacity: 0; /* 默认隐藏 */
transition: opacity 0.3s; /* 平滑过渡效果 */
}
/* 悬停时显示背景区域 */
.copy-button:hover::after {
opacity: 1; /* 显示背景 */
}
</style>
到此这篇关于js中navigator.clipboard的兼容性问题的文章就介绍到这了,更多相关navigator.clipboard兼容性内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!
