目录
- 怎么使用JavaScript实现一个剪贴
- 上面的方法不是很完美我们优化一下
- 思考一个问题
- 使用react和typescript重写和优化一下
- 如何使用copyme
- 原文参考
写在最前面
- 有一个简单的需求,用户需要快捷的复制一些相关的信息,然后进行下一步信息的填写。前端这里需要做一个剪贴板方便用户体验。想直接参考 react 使用的可以看 使用react和typescript改写和优化一下
- 大概设计如下,有多条信息,然后用户可以点击右边的复制 icon 进行快捷的复制。
怎么使用JavaScript实现一个剪贴板
- 具体分为五步
- 1、创建一个
textarea
,把需要的文本放进textarea
中 - 2、将
textarea
元素插入body
中。 - 3、使用
HTMLInputElement.select()
方法选择textarea
中的文本内容 - 4、使用
document.execCommand('copy')
复制textarea
中的文本内容到剪贴板 - 5、从
body
删除textarea
元素
- 1、创建一个
- code
const copyToClipboard = str => {
const el = document.createElement('textarea');
el.value = str;
document.body.appendChild(el);
el.select();
document.execCommand('copy');
document.body.removeChild(el);
};
复制代码
必要 api 参考
- developer.mozilla.org/zh-CN/docs/…
上面的方法不是很完美我们优化一下
- 这个方法不是在每个地方都能运行,由于 textarea 的插入和移除,有时候会出现页面的频闪和抖动
- 下面用 css 优化一下我们的 textarea 样式,隐藏 textarea 的显示。
const copyToClipboard = str => {
const el = document.createElement('textarea');
el.value = str;
el.setAttribute('readonly', '');
el.style.position = 'absolute';
el.style.left = '-9999px';
document.body.appendChild(el);
el.select();
document.execCommand('copy');
document.body.removeChild(el);
};
复制代码
思考一个问题
- 我们用户在使用我们的剪贴板之前可能已经选择了已存在 html 中的文本内容了,所以我们这里需要多加一些判断防止遗漏用户选择的文本。
DocumentOrShadowRoot.getSelection(), Selection.rangeCount, Selection.getRangeAt(), Selection.removeAllRanges() and Selection.addRange()
这些方法存储用户选择的文本内容和解决范围选择的问题
const copyToClipboard = str => {
const el = document.createElement('textarea'); // Create a element</span>
el.value = str; <span class="hljs-comment">// Set its value to the string that you want copied</span>
el.setAttribute(<span class="hljs-string">'readonly'</span>, <span class="hljs-string">''</span>); <span class="hljs-comment">// Make it readonly to be tamper-proof</span>
el.style.position = <span class="hljs-string">'absolute'</span>;
el.style.left = <span class="hljs-string">'-9999px'</span>; <span class="hljs-comment">// Move outside the screen to make it invisible</span>
<span class="hljs-built_in">document</span>.body.appendChild(el); <span class="hljs-comment">// Append the <textarea> element to the HTML document</span>
<span class="hljs-keyword">const</span> selected =
<span class="hljs-built_in">document</span>.getSelection().rangeCount > <span class="hljs-number">0</span> <span class="hljs-comment">// Check if there is any content selected previously</span>
? <span class="hljs-built_in">document</span>.getSelection().getRangeAt(<span class="hljs-number">0</span>) <span class="hljs-comment">// Store selection if found</span>
: <span class="hljs-literal">false</span>; <span class="hljs-comment">// Mark as false to know no selection existed before</span>
el.select(); <span class="hljs-comment">// Select the <textarea> content</span>
<span class="hljs-built_in">document</span>.execCommand(<span class="hljs-string">'copy'</span>); <span class="hljs-comment">// Copy - only works as a result of a user action (e.g. click events)</span>
<span class="hljs-built_in">document</span>.body.removeChild(el); <span class="hljs-comment">// Remove the <textarea> element</span>
<span class="hljs-keyword">if</span> (selected) { <span class="hljs-comment">// If a selection existed before copying</span>
<span class="hljs-built_in">document</span>.getSelection().removeAllRanges(); <span class="hljs-comment">// Unselect everything on the HTML document</span>
<span class="hljs-built_in">document</span>.getSelection().addRange(selected); <span class="hljs-comment">// Restore the original selection</span>
}
};
<span class="copy-code-btn">复制代码</span></code></pre><h2 class="heading" data-id="heading-6">使用react和typescript改写和优化一下</h2>
<ul>
<li>学习了上面的文章,结合产品的需求改写一下相关代码。</li>
<li>思路
<ul>
<li>1、首先创建一个 targetNode,设置绝对布局,赢藏我们的元素</li>
<li>2、document.getSelection() 已经由 window.getSelection() 替代了,具体流程如上</li>
<li>3、创建一个 result 标记能否能正常 使用剪贴功能,不能的返回 false</li>
<li>4、删除这个 targetNode</li>
</ul>
</li>
</ul>
<pre><code class="hljs js copyable" lang="js"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">createNode</span>(<span class="hljs-params">text</span>) </span>{
<span class="hljs-keyword">const</span> node = <span class="hljs-built_in">document</span>.createElement(<span class="hljs-string">'div'</span>);
node.innerText = text;
node.style.cssText = <span class="hljs-string">'position:absolute; top: 0; left: 0; height:0; width:0; pointer-events: none;'</span>;
<span class="hljs-built_in">document</span>.body.appendChild(node);
<span class="hljs-keyword">return</span> node;
}
<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">copyMe</span>(<span class="hljs-params">text</span>) </span>{
<span class="hljs-keyword">const</span> targetNode = createNode(text);
<span class="hljs-keyword">const</span> range = <span class="hljs-built_in">document</span>.createRange();
<span class="hljs-keyword">const</span> selection = <span class="hljs-built_in">window</span>.getSelection()!;
<span class="hljs-keyword">const</span> selected = selection.rangeCount > <span class="hljs-number">0</span>
? selection.getRangeAt(<span class="hljs-number">0</span>)
: <span class="hljs-literal">false</span>;
targetNode.focus(); <span class="hljs-comment">// focus 我们需要的文本</span>
range.selectNodeContents(targetNode);
<span class="hljs-keyword">if</span>(selected){
selection.removeAllRanges();
selection.addRange(range);
}
<span class="hljs-keyword">let</span> result;
<span class="hljs-keyword">try</span> {
result = <span class="hljs-built_in">document</span>.execCommand(<span class="hljs-string">'copy'</span>);
} <span class="hljs-keyword">catch</span> (e) {
result = <span class="hljs-literal">false</span>;
}
<span class="hljs-built_in">document</span>.body.removeChild(targetNode);
<span class="hljs-keyword">return</span> result;
}
<span class="copy-code-btn">复制代码</span></code></pre><h3 class="heading" data-id="heading-7">如何使用copyme</h3>
<pre><code class="hljs js copyable" lang="js"><span class="hljs-keyword">import</span> React, { Fragment } <span class="hljs-keyword">from</span> <span class="hljs-string">'react'</span>;
<span class="hljs-keyword">import</span> copyMe <span class="hljs-keyword">from</span> <span class="hljs-string">'utils/copyMe'</span>;
interface ItemProps {
value?: string | number;
}
<span class="hljs-keyword">const</span> Item: React.FC<ItemProps> = <span class="hljs-function"><span class="hljs-params">props</span> =></span> {
<span class="hljs-keyword">const</span> { value } = props;
<span class="hljs-keyword">const</span> copyme = <span class="hljs-function"><span class="hljs-params">()</span> =></span> {
alert(copyMe(value) ? <span class="hljs-string">'Copied!'</span> : <span class="hljs-string">'Failed!'</span>);
};
<span class="hljs-keyword">return</span> (
<span class="xml"><span class="hljs-tag"><<span class="hljs-name">Fragment</span>></span>
{value && (
<span class="hljs-tag"><<span class="hljs-name">div</span>></span>
{value}
<span class="hljs-tag"><<span class="hljs-name">textarea</span> <span class="hljs-attr">value</span>=<span class="hljs-string">{value}</span> <span class="hljs-attr">readOnly</span>></span><span class="hljs-tag"></<span class="hljs-name">textarea</span>></span>
<span class="hljs-tag"><<span class="hljs-name">span</span> <span class="hljs-attr">onClick</span>=<span class="hljs-string">{copyme}</span>></span><span class="hljs-tag"></<span class="hljs-name">span</span>></span>
<span class="hljs-tag"></<span class="hljs-name">div</span>></span>
)}
<span class="hljs-tag"></<span class="hljs-name">Fragment</span>></span></span>
);
};
<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> Item;
<span class="copy-code-btn">复制代码</span></code></pre><h4 class="heading" data-id="heading-8">必要 api 参考</h4>
<ul>
<li><a target="_blank" href="https://developer.mozilla.org/zh-CN/docs/Web/API/Window/getSelection" rel="nofollow noopener noreferrer">window/getSelection</a></li>
<li><a target="_blank" href="https://developer.mozilla.org/zh-CN/docs/Web/API/Selection/getRangeAt" rel="nofollow noopener noreferrer">Selection/getRangeAt</a></li>
<li><a target="_blank" href="https://developer.mozilla.org/zh-CN/docs/Web/API/Range/selectNodeContents" rel="nofollow noopener noreferrer">Range/selectNodeContents</a></li>
</ul>
<h2 class="heading" data-id="heading-9">原文参考</h2>
<ul>
<li><a target="_blank" href="https://hackernoon.com/copying-text-to-clipboard-with-javascript-df4d4988697f" rel="nofollow noopener noreferrer">hackernoon.com/copying-tex…</a></li>
</ul>
</div> <div class="image-viewer-box" data-v-78c9b824=""><!----></div>