首先需要拿到要复制的内容,然后调用https的navigator.clipboard方法进行复制,但是这个因为浏览器策略只能在本地localhost和https环境下才能生效,http环境访问不到这个方法,在http环境在可以使用传统方式创建 textarea 进行复制
下面展示我在项目中用到的两种情况下的复制代码:
①复制的内容格式比较复杂,外面的大盒子里展示内容有很多逻辑判断,不方便直接获取到盒子里的内容,这个时候复制的内容需要手动用模板字符串进行拼接
// 获取到要复制的内容,带格式
const copyQuestions = () => {
const selected = localQuestions.value.filter((item) => item.isSelected);
if (selected.length === 0) return;
const text = selected
.map((item, idx) => {
const topic = item.topic;
const options = Object.entries(topic.option)
.map(([key, val], i) => `选项${String.fromCharCode(65 + i)}:\t${val}`)
.join("\n");
return (
`题目${getCircleNumber(idx + 1)}:${questionType[item.topicType]}\n` +
`题目内容:\t${topic.question}\n` +
options +
"\n" +
`正确答案:\t${topic.answer}\n` +
`答案解析:\t${topic.desc}\n`
);
})
.join("\n");
copyToClipboard(text);
};
//复制方法
const copyToClipboard = async (text) => {
try {
if (navigator.clipboard && window.isSecureContext) {
// 优先使用现代方式(仅在 HTTPS 或 localhost 下有效)
await navigator.clipboard.writeText(text);
} else {
// 非 HTTPS 环境,使用传统方式创建 textarea 进行复制
console.log("非 HTTPS 环境,使用传统方式创建 textarea 进行复制");
const textarea = document.createElement("textarea");
textarea.value = text;
textarea.style.position = "fixed"; // 防止滚动到页面底部
textarea.style.opacity = "0";
document.body.appendChild(textarea);
textarea.focus();
textarea.select();
const successful = document.execCommand("copy");
document.body.removeChild(textarea);
if (!successful) {
throw new Error("execCommand 复制失败");
}
}
ElMessage.success("复制成功");
} catch (err) {
console.error("复制失败:", err);
ElMessage.error("复制失败,请手动复制");
}
};
② 有编辑和非编辑模式,两种模式都支持一键复制,编辑模式用的是@wangeditor/editor-for-vue,5.1.12版本的,复制代码如下
template代码
<template>
<div v-if="!editMode">
<!-- <button @click="editMode = true">编辑</button> -->
<div
class="text-content"
v-html="formattedText"
ref="textContainer"
></div>
</div>
<div v-if="editMode">
<!-- <button @click="editMode = false">保存</button> -->
<Editor
ref="editorContainer"
class="editor_box"
style="height: max-content; overflow-y: hidden"
v-model="valueHtml"
:defaultConfig="editorConfig"
mode="default"
@onCreated="handleCreated"
@onChange="handleEditorChange"
/>
</div>
</template>
script中的代码示例
const textContainer = ref<HTMLElement | null>(null);
const handleCreated = (editor: any) => {
editorRef.value = editor; // 记录 editor 实例,重要!
};
// 富文本复制(去除高亮样式)
const copyFormattedContent = async () => {
try {
let html = "";
if (props.editMode) {
if (!editorRef.value || typeof editorRef.value.getHtml !== "function") {
ElMessage.info("编辑器未初始化或类型错误");
return;
}
html = editorRef.value.getHtml();
} else {
const textToCopy = textContainer.value;
if (!textToCopy) {
ElMessage.info("复制区域未找到");
return;
}
html = textToCopy.innerHTML;
}
// ✅ 创建 DOM,清除高亮样式
const tempDiv = document.createElement("div");
tempDiv.innerHTML = html;
// ✅ 清除高亮样式
tempDiv.querySelectorAll("span, strong").forEach((el: any) => {
const hasBgColor =
el.style.backgroundColor ||
el.getAttribute("style")?.includes("background");
if (hasBgColor) {
el.removeAttribute("style");
}
});
// ✅ 移除高亮 class 和 data-word
tempDiv.querySelectorAll(".highlight-word").forEach((el) => {
el.classList.remove("highlight-word");
el.removeAttribute("data-word");
});
const cleanedHtml = tempDiv.innerHTML;
// ✅ 使用 Clipboard API 复制处理后的 HTML
await navigator.clipboard.write([
new ClipboardItem({
"text/html": new Blob([cleanedHtml], { type: "text/html" }),
}),
]);
ElMessage.success("内容已复制");
} catch (err) {
console.error("复制失败:", err);
ElMessage.error("复制失败");
}
};