关于clipboard的复制功能及使用方法,相信大家并不陌生,难的是如何解决首次点击两次才复制成功的问题?
这个问题真的是纠结了我好长时间,好在最后也算是有了解决的方法,接下来简单说一下怎么使用以及点击两次才生效的解决办法。
1、在项目中下载所需要的依赖:
npm install clipboard --save
2、点击复制链接,实现复制
先说一下正常的情况,一般是这样:
方案一
// html
<a id="copyBtn" data-clipboard-text="复制的内容" onClick={() => copy()} >复制链接</a>
// js
copyWarrantLink = () => {
let clipboard = new Clipboard('#copyBtn');
clipboard.on('success', function(e) {
console.log("复制成功");
clipboard.destroy();
})
}
方案二
// html
<a id="copyBtn" onClick={() => copy()} >复制链接</a>
// js
copy = () => {
let clipboard = new Clipboard('#copyBtn',{
text: () => "复制的内容"
});
clipboard.on('success', function(e) {
console.log("复制成功");
clipboard.destroy();
})
}
这种情况下,复制的问题是不大的。但你很快就能发现首次复制是无效的,必须点击两次才能够解决。
之前我居然天真的以为我项目中需要点击两次才成功是因为我需要复制的文本是动态的,结果发现,静态的也是这样。。。
项目中的需求是点击复制链接动态获取地址,也就是需要通过请求来动态更新url的地址,具体如下:
// html
<a id="copyBtn" data-clipboard-text={getLink} onClick={() => copy()} >复制链接</a>
// js
// 此处省略了复制的代码
copy = () => {
let params = {};
axios.post(url, params).then((result) => {
this.setState({getLink: result});
})
}
和之前两个例子差不多,唯一不同的就是复制的文本是从请求中拿的,搜罗了一下网上的解决方案,大抵是以下几种:
- 请求变为同步,不使用异步请求
- 设置setTimeOut,延迟执行
- 创建对象不应该写在方法里面,应该在页面加载完成之后就创建
- 手动添加一次点击事件
经过实践,我发现前面三种解决方案对我来说好像并没有什么效果(可能是我的打开方式不对?)
emm,所以我采用的是第四种,手动添加点击事件。但是,使用这种方法的时候也要注意不要在方法里调用呀,否则会陷入死循环的。
为了避免重复发请求,在点击复制链接的时候我先进行了判断,具体代码如下:
// html
<a id="copyBtn" data-clipboard-text={getLink} onClick={() => beforeCopy()} >复制链接</a>
// js
let copyBtn = null;
// 页面渲染完成后创建一个对象
componentDidMount = () => {
let obj = this;
copyBtn = new Clipboard('#copyWarrantLinkBank');
copyBtn.on('success', function(e) {
console.log("复制成功");
// 复制成功之后销毁
copyBtn.destroy();
obj.setState({getLink: ""})
})
}
// 监听复制文本的变化
componentDidUpdate (prevProps, prevState) {
let obj = this;
if(prevState.getLink !== this.state.getLink && document.getElementById("copyBtn")){
if(this.state.getLink) {
// 手动点击一次
document.getElementById("copyBtn").click();
copyBtn = new Clipboard('#copyBtn');
copyBtn.on('success', function(e) {
console.log("复制成功");
copyBtn.destroy();
obj.setState({getLink: ""})
})
}
}
}
// 在调用请求之前,先判断复制的文本是否为空
beforeCopy = () =>{
if(this.state.getLink){
return
}else{
this.copy();
}
}
// 发请求获取复制的文本信息
copy = () => {
let params = {};
axios.post(url, params).then((result) => {
this.setState({getLink: result});
})
}
简单说一下流程:
- getLink是一个状态值,初始值是空
- 点击复制链接,getLink为空,调用copy的方法获取复制文本
- 此时的componentDidUpdate中的条件是满足的,所以手动点击一次
- 点击后调用beforeCopy方法,此时getLink已经有值啦,就不会再发请求了
这里需要注意的是在页面渲染完成后需创建一个对象,这里主要是用于第一次的时候,在复制成功后销毁创建的对象,并将getLink置空,这样后面才能进行判断。
当然,这个方法也可能还有不足的地方,期待后面有更好的解决方案。
补充:如果可以的话,使用原生js的复制文案更为便捷哦,可以看看这个js实现复制文案到剪切板