一直非常不喜欢类似clipboardjs
的使用方式(至于依赖flash的ZeroClipboard.js
那就更不推荐了),和DOM耦合太重,使用起来非常不方便:
<button class="btn">
Copy to clipboard
</button>
<script>
// 如果是SPA页面,切换页面时还需要调用 clipboard.destroy() ,否则会出现重复触发成功的问题
var clipboard = new ClipboardJS('.btn');
clipboard.on('success', function(e) {
console.info('Action:', e.action);
console.info('Text:', e.text);
console.info('Trigger:', e.trigger);
e.clearSelection();
});
clipboard.on('error', function(e) {
console.error('Action:', e.action);
console.error('Trigger:', e.trigger);
});
</script>
其实复制剪贴板最简单1行代码navigator.clipboard.writeText
就可以实现,兼容性好的6行代码也足够了,所以封装了一个更简单、更易使用的copyToClipboard
函数,可以直接替代clipboardjs
:
/**
* 复制一段文本到剪贴板,如果失败会抛出异常,推荐使用姿势:
* await copyToClipboard('要复制的文本', message => alert(`复制到剪贴板失败:${message}`));
* alert('复制到剪贴板成功!');
* @param {*} text 要复制的文本
* @param {*} onFailure 失败回调,接受一个 message 参数
* @param {*} supportSilent 是否支持后台静默复制,如果是则优先采用 execCommand
* @returns
*/
function copyToClipboard(text, onFailure, supportSilent) {
if (!text) {
throw new Error('text can not be empty.');
}
onFailure = onFailure || (msg => console.error(`复制到剪贴板失败:${msg || ''}`));
// 优先采用现代化API
if (navigator.clipboard && !supportSilent) {
// 注意 writeText API 要求:文档被激活 & 页面已启用HTTPS
return navigator.clipboard.writeText(text).catch(e => {
onFailure(e.message);
throw e;
});
}
// execCommand 原本是一个同步API,这里为了和 writeText 保持一致统一包成proimse
return new Promise((resolve, reject) => {
const input = document.createElement('input');
input.value = text;
input.style.cssText = 'position:fixed;left:0;top:0;opacity:0;';
document.body.appendChild(input);
input.select();
try {
if (document.execCommand('copy')) {
resolve();
} else {
const message = "Failed to execute 'document.execCommand'.";
onFailure(message);
reject(new Error(message));
}
} catch (e) {
onFailure(e.message);
reject(e);
} finally {
document.body.removeChild(input);
}
});
}
使用方法:
// 如果复制失败不会继续往后执行
await copyToClipboard('要复制的文本', message => alert(`复制到剪贴板失败:${message}`));
alert('复制到剪贴板成功!');