ph-utils
Version:
js 开发工具集,前后端都可以使用(commonjs和es module)
102 lines (101 loc) • 3.21 kB
JavaScript
/**
* 创建一个临时节点缓存待复制数据
* @param {String} value
* @return {HTMLElement}
*/
function createFakeElement(value) {
const fakeElement = document.createElement("textarea");
fakeElement.style.border = "0";
fakeElement.style.padding = "0";
fakeElement.style.margin = "0";
fakeElement.style.position = "absolute";
fakeElement.style.left = "-9999px";
fakeElement.style.top = "-9999";
fakeElement.setAttribute("readonly", "");
fakeElement.value = value;
return fakeElement;
}
/** 通过执行 execCommand 来执行复制 */
function copyFromCommand(text) {
// 添加节点
const fakeEl = createFakeElement(text);
document.body.append(fakeEl);
fakeEl.focus();
fakeEl.select();
// 执行复制
const res = document.execCommand("copy");
fakeEl.remove(); // 删除节点
return Promise.resolve(res);
}
/** 使用 navigator.clipboard 复制 */
function copyFromClipboard(text) {
const theClipboard = navigator.clipboard;
if (theClipboard != null) {
return theClipboard
.writeText(text)
.then(() => {
Promise.resolve(true);
})
.catch(() => Promise.resolve(false));
}
return Promise.resolve(false);
}
/** 解析待复制的文本 */
function parseCopyText(source) {
let copyText = null; // 待复制文本
let sourceEl = null;
// 获取待复制数据
if (typeof source === "string") {
// 从节点拿数据
if (source.startsWith("#") || source.startsWith(".")) {
sourceEl = document.querySelector(source);
if (sourceEl == null) {
copyText = source;
}
}
else {
copyText = source;
}
}
if (source instanceof HTMLElement) {
sourceEl = source;
}
// 从节点获取待复制数据
if (sourceEl != null) {
if (sourceEl.hasAttribute("data-copy-text")) {
copyText = sourceEl.getAttribute("data-copy-text");
}
else {
const tagName = sourceEl.tagName;
if (tagName === "INPUT" || tagName === "TEXTAREA") {
copyText = sourceEl.value;
}
else {
copyText = sourceEl.textContent;
}
}
}
return copyText;
}
/**
* 复制数据, 可以从多种类型的数据
* 1. 直接复制文本: await copy("待复制的文本")
* 2. 复制节点上的 data-copy-text:
* <button data-copy-text="这是待复制的文本">复制</button>
* await copy(e.target) // or await copy("#a") or await copy(document.querySelector('#a'))
* 3. 直接复制节点本身数据: await copy('#a')
* @param {string | HTMLElement} source 复制源, 从中解析待复制的数据
* @returns {Promise<boolean>} 是否复制成功
*/
export async function copy(source) {
// 待复制文本
const copyText = parseCopyText(source);
if (copyText == null) {
return Promise.resolve(false);
}
const v = await copyFromClipboard(copyText);
if (v === false) {
return copyFromCommand(copyText);
}
return Promise.resolve(true);
}