ChatGPT解决这个技术问题 Extra ChatGPT

在 reactJS 中,如何将文本复制到剪贴板?

我正在使用 ReactJS,当用户单击链接时,我想将一些文本复制到剪贴板。

我使用的是 Chrome 52,不需要支持任何其他浏览器。

我不明白为什么这段代码不会导致数据被复制到剪贴板。 (代码片段的来源来自 Reddit 帖子)。

我做错了吗?任何人都可以建议使用reactjs实现复制到剪贴板的“正确”方法吗?

copyToClipboard = (text) => {
  console.log('text', text)
  var textField = document.createElement('textarea')
  textField.innerText = text
  document.body.appendChild(textField)
  textField.select()
  document.execCommand('copy')
  textField.remove()
}
您是否尝试过使用第三方解决方案,例如 clipboardjs.comgithub.com/zeroclipboard/zeroclipboard
@EugZol 我真的更喜欢编写代码而不是添加另一个依赖项,假设代码相当小。
@elmeister这个问题是特定于reactjs的

G
Gary Vernon Grubb

如果您想以编程方式将数据写入剪贴板,请在按钮上使用这个简单的内联 onClick 函数。

onClick={() => {navigator.clipboard.writeText(this.state.textToCopy)}}

navigator.clipboard 不支持所有浏览器
似乎它在 2018 年对主要浏览器有很好的支持caniuse.com/#search=clipboard
根据您提供的链接,它似乎只在 safari 中完全受支持...
最适合我的用例,要复制的文本实际上不在页面上。谢谢
由于我被困在这个问题上(在 Chrome 上),navigator.clipboard 仅在您的页面从安全来源(HTTPS 或 localhost)加载时才有效。如果需要,您可以检查 window.isSecureContext
H
HoldOffHunger

我个人认为不需要图书馆。看看 http://caniuse.com/#feat=clipboard,它现在得到了相当广泛的支持,但是您仍然可以执行一些操作,例如检查当前客户端中是否存在该功能,如果不存在则简单地隐藏复制按钮。

import React from 'react';

class CopyExample extends React.Component {

  constructor(props) {
    super(props);

    this.state = { copySuccess: '' }
  }

  copyToClipboard = (e) => {
    this.textArea.select();
    document.execCommand('copy');
    // This is just personal preference.
    // I prefer to not show the whole text area selected.
    e.target.focus();
    this.setState({ copySuccess: 'Copied!' });
  };

  render() {
    return (
      <div>
        {
         /* Logical shortcut for only displaying the 
            button if the copy command exists */
         document.queryCommandSupported('copy') &&
          <div>
            <button onClick={this.copyToClipboard}>Copy</button> 
            {this.state.copySuccess}
          </div>
        }
        <form>
          <textarea
            ref={(textarea) => this.textArea = textarea}
            value='Some text to copy'
          />
        </form>
      </div>
    );
  }

}
    
export default CopyExample;

更新:在 React 16.7.0-alpha.0 中使用 React Hooks 重写

import React, { useRef, useState } from 'react';

export default function CopyExample() {

  const [copySuccess, setCopySuccess] = useState('');
  const textAreaRef = useRef(null);

  function copyToClipboard(e) {
    textAreaRef.current.select();
    document.execCommand('copy');
    // This is just personal preference.
    // I prefer to not show the whole text area selected.
    e.target.focus();
    setCopySuccess('Copied!');
  };

  return (
    <div>
      {
       /* Logical shortcut for only displaying the 
          button if the copy command exists */
       document.queryCommandSupported('copy') &&
        <div>
          <button onClick={copyToClipboard}>Copy</button> 
          {copySuccess}
        </div>
      }
      <form>
        <textarea
          ref={textAreaRef}
          value='Some text to copy'
        />
      </form>
    </div>
  );
}

仅作记录:唯一的问题是,如果您尝试复制页面上某些文本元素中尚不存在的文本,则需要破解一组 DOM 元素,设置文本,复制它,并清理干净。对于非常小的东西,这是很多代码。通常我会同意不应该鼓励开发人员不断安装库。
对于这个特殊问题,文本已经在页面上的一个元素中。在什么情况下,您要复制的页面上的可见文本不在元素中?这是一个完全不同的问题,我很乐意展示解决方案。你不需要用 react 来破解任何东西,你只需在你的渲染函数中提供一个隐藏元素,它也包含文本。无需临时创建元素。
我收到此打字稿错误:Property 'select' does not exist on type 'never'
我得到 TypeError: textAreaRef.current.select is not a function
j
jerryurenaa

您可以在不需要外部库的情况下完成此操作,例如:在按钮内

<button 
  onClick={() =>  navigator.clipboard.writeText('Copy this text to clipboard')}
>
  Copy
</button>

对于 internet explorer 11 和更旧的浏览器,您可能需要稍微更改代码这里是一个示例:

<button 
  onClick={() =>  window.clipboardData.setData("Text", 'Copy this text to clipboard')}>
 Copy
</button>

希望这可以帮助。


顺便说一句最好的要求
我更新了答案以支持旧版浏览器!感谢您的评论。
我收到以下错误:TypeError: Cannot read property 'setData' of undefined
第二个示例仅适用于旧浏览器,例如:internet explorer 11。对于新浏览器,请使用第一个示例。
嗨@e-info128 这不是说window.navigator.clipboard 它说的是navigator.clipboard 所以你的问题。
D
Drew Schuster

您绝对应该考虑使用像上面的 @Shubham 这样的包,但我根据您的描述创建了一个工作代码笔: http://codepen.io/dtschust/pen/WGwdVN?editors=1111 。它可以在我的 chrome 浏览器中运行,也许您可以查看我在那里所做的某些事情您错过了,或者您的应用程序中是否存在一些扩展的复杂性阻止它工作。

// html
<html>
  <body>
    <div id="container">

    </div>
  </body>
</html>


// js
const Hello = React.createClass({
  copyToClipboard: () => {
    var textField = document.createElement('textarea')
    textField.innerText = 'foo bar baz'
    document.body.appendChild(textField)
    textField.select()
    document.execCommand('copy')
    textField.remove()
  },
  render: function () {
    return (
      <h1 onClick={this.copyToClipboard}>Click to copy some text</h1>
    )
  }
})

ReactDOM.render(
<Hello/>,
  document.getElementById('container'))

为什么软件包比您的解决方案更好?
可能更好的跨浏览器支持,如果需要修复错误,请更多地关注软件包
奇迹般有效。是的。我也想知道跨浏览器支持。
如果因为您使用的是 appendChild,这会导致屏幕闪烁,无论您之后以多快的速度将其删除?
这很好,但它不适用于 Android 上的 Chrome (72.0) 或 Android 上的 FF (63.0)。
S
Shubham Khatri

最简单的方法是使用 react-copy-to-clipboard npm 包。

您可以使用以下命令安装它

npm install --save react react-copy-to-clipboard

请按以下方式使用它。

const App = React.createClass({
  getInitialState() {
    return {value: '', copied: false};
  },


  onChange({target: {value}}) {
    this.setState({value, copied: false});
  },


  onCopy() {
    this.setState({copied: true});
  },


  render() {
    return (
      <div>

          <input value={this.state.value} size={10} onChange={this.onChange} />

        <CopyToClipboard text={this.state.value} onCopy={this.onCopy}>
          <button>Copy</button>
        </CopyToClipboard>

                <div>
        {this.state.copied ? <span >Copied.</span> : null}
                </div>
        <br />

        <input type="text" />

      </div>
    );
  }
});

ReactDOM.render(<App />, document.getElementById('container'));

以下链接提供了详细说明

https://www.npmjs.com/package/react-copy-to-clipboard

这是一个正在运行的 fiddle


如果我需要做反向,有什么解决方案吗?即作者将文本从电子邮件复制到 reactjs 应用程序的文本区域。我不需要保留 html 标签,但是,我只需要保留换行符。
您可能需要插入 onpaste 事件
如果我想将 html 表格的内容复制到剪贴板,我该如何使用这个包? @Shubham Khatri
J
Jaman-Dedy

带有反应钩子的最佳解决方案,不需要外部库

导入反应,{ useState } from 'react'; const MyComponent = () => { const [copySuccess, setCopySuccess] = useState(''); // 你要复制到这里的函数 const copyToClipBoard = async copyMe => { try { await navigator.clipboard.writeText(copyMe); setCopySuccess('已复制!'); } catch (err) { setCopySuccess('复制失败!'); } }; return (

// 复制后看这里的信息 {copySuccess}
) }

在这里查看有关 navigator.clip board 的更多文档, navigator.clipboard documentation 大量浏览器支持 navigotor.clipboard 看这里 supported browser


运行代码段会抛出错误 Uncaught SyntaxError: Cannot use import statement outside a module
G
Gass

剪贴板是 well supported by major browser in 2021。一种方法是首先构建复制到剪贴板函数,然后使用 onClick 事件处理程序调用它。

function copy(text){
  navigator.clipboard.writeText(text)
}

为了防止硬编码,假设 string 分配给名为 someText 的变量

<span onClick={() => copy(someText)}>
  {someText}
</span>

A
Abhinav

您可以使用事件剪贴板数据收集方法 e.clipboardData.setData(type, content)

在我看来,这是实现在剪贴板中推送内容的最直接方法,请检查一下(我在本机复制操作时使用它来修改数据):

...

handleCopy = (e) => {
    e.preventDefault();
    e.clipboardData.setData('text/plain', 'Hello, world!');
}

render = () =>
    <Component
        onCopy={this.handleCopy}
    />

我沿着这条路走:https://developer.mozilla.org/en-US/docs/Web/Events/copy

干杯!

编辑:出于测试目的,我添加了 codepen:https://codepen.io/dprzygodzki/pen/ZaJMKb


@KarlPokus 提问者只是在寻找 Chrome 解决方案
在 Chrome 版本 62.0.3202.94 上测试。这是工作。 codepen.io/dprzygodzki/pen/ZaJMKb
@OliverDixon 它是 React 事件的默认对象。 reactjs.org/docs/events.html
@DamianPrzygodzki 我讨厌这样的隐藏元素,这是迷惑开发人员的好方法。
@OliverDixon 我觉得你,但我认为它很好习惯,有时会有一些默认数据应用于方法,特别是在事件中。
t
tjgragg

我采取了与上述一些方法非常相似的方法,但我认为它更具体一些。在这里,父组件会将 url(或您想要的任何文本)作为道具传递。

import * as React from 'react'

export const CopyButton = ({ url }: any) => {
  const copyToClipboard = () => {
    const textField = document.createElement('textarea');
    textField.innerText = url;
    document.body.appendChild(textField);
    textField.select();
    document.execCommand('copy');
    textField.remove();
  };

  return (
    <button onClick={copyToClipboard}>
      Copy
    </button>
  );
};

这很有用,因为我想用段落标签代替 Textarea
谢谢!唯一的问题是隐藏文本字段
K
Kupi

您的代码应该可以完美运行,我以同样的方式使用它。仅确保如果单击事件是从弹出屏幕(如引导模式或其他内容)中触发的,则创建的元素必须在该模式中,否则不会复制。您始终可以在该模式中提供元素的 id(作为第二个参数)并使用 getElementById 检索它,然后将新创建的元素附加到该元素而不是文档。像这样的东西:

copyToClipboard = (text, elementId) => {
  const textField = document.createElement('textarea');
  textField.innerText = text;
  const parentElement = document.getElementById(elementId);
  parentElement.appendChild(textField);
  textField.select();
  document.execCommand('copy');
  parentElement.removeChild(textField);
}

j
jasonleonhard

这是另一个用例,如果您想将当前 url 复制到剪贴板:

定义一个方法

const copyToClipboard = e => {
  navigator.clipboard.writeText(window.location.toString())
}

调用那个方法

<button copyToClipboard={shareLink}>
   Click to copy current url to clipboard
</button>

A
Antonio Carlos Araújo

这对我有用:

const handleCopyLink = useCallback(() => {
    const textField = document.createElement('textarea')
    textField.innerText = url
    document.body.appendChild(textField)
    if (window.navigator.platform === 'iPhone') {
      textField.setSelectionRange(0, 99999)
    } else {
      textField.select()
    }
    document.execCommand('copy')
    textField.remove()
  }, [url])

最后的吐司很不错。可能应该添加一个 toastId,这样如果他们多次单击它,它就不会向 UI 发送垃圾邮件通知。并不是说这与这个问题超级相关。
Toast 在这里完全超出了范围,也超出了回调内部的上下文,因为 OP 不知道它在哪里以及如何定义..
修复:删除吐司
B
Bhuwan Panta

简单的答案将是

navigator.clipboard.writeText("值")


t
tomnyson

使用此命令将您的值传递给函数

var promise = navigator.clipboard.writeText(newClipText)

navigator.clipboard 未在 jsx 组件中定义。
c
connect2Coder

对于那些试图从 DIV 而不是文本字段中进行选择的人,这里是代码。该代码是不言自明的,但如果您想了解更多信息,请在此处评论:

     import React from 'react';
     ....

    //set ref to your div
          setRef = (ref) => {
            // debugger; //eslint-disable-line
            this.dialogRef = ref;
          };

          createMarkeup = content => ({
            __html: content,
          });

    //following function select and copy data to the clipboard from the selected Div. 
   //Please note that it is only tested in chrome but compatibility for other browsers can be easily done

          copyDataToClipboard = () => {
            try {
              const range = document.createRange();
              const selection = window.getSelection();
              range.selectNodeContents(this.dialogRef);
              selection.removeAllRanges();
              selection.addRange(range);
              document.execCommand('copy');
              this.showNotification('Macro copied successfully.', 'info');
              this.props.closeMacroWindow();
            } catch (err) {
              // console.log(err); //eslint-disable-line
              //alert('Macro copy failed.');
            }
          };

              render() {
                    return (
                        <div
                          id="macroDiv"
                          ref={(el) => {
                            this.dialogRef = el;
                          }}
                          // className={classes.paper}
                          dangerouslySetInnerHTML={this.createMarkeup(this.props.content)}
                        />
                    );
            }

U
Ugur Yilmaz

根据他们的文档,navigator.clipboard 不能通过 http 连接工作。因此,您可以检查它是否未定义并改用 document.execCommand('copy'),此解决方案应涵盖几乎所有浏览器

const defaultCopySuccessMessage = 'ID copied!'

const CopyItem = (props) => {
  const { copySuccessMessage = defaultCopySuccessMessage, value } = props

  const [showCopySuccess, setCopySuccess] = useState(false)


  function fallbackToCopy(text) {
    if (window.clipboardData && window.clipboardData.setData) {
      // IE specific code path to prevent textarea being shown while dialog is visible.
      return window.clipboardData.setData('Text', text)
    } else if (document.queryCommandSupported && document.queryCommandSupported('copy')) {
      const textarea = document.createElement('textarea')
      textarea.innerText = text
      // const parentElement=document.querySelector(".up-CopyItem-copy-button")
      const parentElement = document.getElementById('copy')
      if (!parentElement) {
        return
      }
      parentElement.appendChild(textarea)
      textarea.style.position = 'fixed' // Prevent scrolling to bottom of page in MS Edge.
      textarea.select()
      try {
        setCopySuccess(true)
        document.execCommand('copy') // Security exception may be thrown by some browsers.
      } catch (ex) {
        console.log('Copy to clipboard failed.', ex)
        return false
      } finally {
        parentElement.removeChild(textarea)
      }
    }
  }

  const copyID = () => {
    if (!navigator.clipboard) {
      fallbackToCopy(value)
      return
    }
    navigator.clipboard.writeText(value)
    setCopySuccess(true)
  }

  return showCopySuccess ? (
    <p>{copySuccessMessage}</p>
  ) : (
    <span id="copy">
      <button onClick={copyID}>Copy Item </button>
    </span>
  )
}

你可以在任何你想调用和重用组件

const Sample=()=>(
   <CopyItem value="item-to-copy"/>
)

Y
Yash Pokar
import React, { Component } from 'react';

export default class CopyTextOnClick extends Component {
    copyText = () => {
        this.refs.input.select();

        document.execCommand('copy');

        return false;
    }

    render () {
        const { text } = this.state;

        return (
            <button onClick={ this.copyText }>
                { text }

                <input
                    ref="input"
                    type="text"
                    defaultValue={ text }
                    style={{ position: 'fixed', top: '-1000px' }} />
            </button>
        )
    }
}

execCommand 已弃用
感谢@anshul 的关注,请您编辑替代方案。可能是developer.mozilla.org/en-US/docs/Web/API/Selection
F
Flavio Wuensche

使用 Material UI 的完整的 React 组件

为了更好地理解,我还准备了 CodeSandbox。希望有帮助。

import { useState } from "react";
import { IconButton, Snackbar } from "@mui/material";
import ShareIcon from "@mui/icons-material/Share";

const CopyToClipboardButton = () => {
  const [open, setOpen] = useState(false);

  const handleClick = () => {
    setOpen(true);
    navigator.clipboard.writeText(window.location.toString());
  };

  return (
    <>
      <IconButton onClick={handleClick} color="primary">
        <ShareIcon />
      </IconButton>
      <Snackbar
        message="Copied to clibboard"
        anchorOrigin={{ vertical: "top", horizontal: "center" }}
        autoHideDuration={20000}
        onClose={() => setOpen(false)}
        open={open}
      />
    </>
  );
};

export default CopyToClipboardButton;

这是按钮的样子:

https://i.stack.imgur.com/41M22.png

当你点击它时:

https://i.stack.imgur.com/1bAeP.png

来源:https://fwuensche.medium.com/react-button-to-copy-to-clipboard-75ef5ecdc708


J
Jobajuba

无需安装第三方软件包。我尽量保持简单。这对我来说效果很好。

import React, { useState } from "react"    
function MyApp() {
    const [copySuccess, setCopySuccess] = useState(null);
    const copyToClipBoard = async copyMe => {
       try {
           await navigator.clipboard.writeText(copyMe);
           setCopySuccess('Copied!');
       } 
       catch (err) {
           setCopySuccess('Failed to copy!');
       }
    };
     
    return (
        <button onClick={(e) => copyToClipBoard(what you want to copy goes here)} >
           My button
        </button>    
       )
    }

H
Haris George

如果您想从 DIV 而不是文本字段中进行选择,这里是代码。 “代码”是必须复制的值

import React from 'react'
class CopyToClipboard extends React.Component {

  copyToClipboard(code) {
    var textField = document.createElement('textarea')
    textField.innerText = code
    document.body.appendChild(textField)
    textField.select()
    document.execCommand('copy')
    textField.remove()
  }
  render() {
    return (
      <div onClick={this.copyToClipboard.bind(this, code)}>
        {code}
      </div>

    )
  }
}

export default CopyToClipboard

SO 的最佳实践是通过解释来完成您的代码。请,做吧。
I
Iago Barreto

找到了最好的方法。我的意思是最快的方法:w3school

https://www.w3schools.com/howto/howto_js_copy_clipboard.asp

在反应功能组件内部。创建一个名为 handleCopy 的函数:

function handleCopy() {
  // get the input Element ID. Save the reference into copyText
  var copyText = document.getElementById("mail")
  // select() will select all data from this input field filled  
  copyText.select()
  copyText.setSelectionRange(0, 99999)
  // execCommand() works just fine except IE 8. as w3schools mention
  document.execCommand("copy")
  // alert the copied value from text input
  alert(`Email copied: ${copyText.value} `)
}

<>
              <input
                readOnly
                type="text"
                value="exemple@email.com"
                id="mail"
              />
              <button onClick={handleCopy}>Copy email</button>

</>

如果不使用 React,w3schools 也有一种很酷的方法来做到这一点,其中包含工具提示:https://www.w3schools.com/howto/tryit.asp?filename=tryhow_js_copy_clipboard2

如果使用 React,一个很酷的想法是:使用 Toastify 来提醒消息。 https://github.com/fkhadra/react-toastify 这是一个非常容易使用的库。安装后,您可能可以更改此行:

 alert(`Email copied: ${copyText.value} `)

对于类似的东西:

toast.success(`Email Copied: ${copyText.value} `)

如果你想使用它,别忘了安装 toastify。导入 ToastContainer 和 toasts css:

import { ToastContainer, toast } from "react-toastify"
import "react-toastify/dist/ReactToastify.css"

并在返回中添加吐司容器。

import React from "react"

import { ToastContainer, toast } from "react-toastify"
import "react-toastify/dist/ReactToastify.css"


export default function Exemple() {
  function handleCopy() {
    var copyText = document.getElementById("mail")
    copyText.select()
    copyText.setSelectionRange(0, 99999)
    document.execCommand("copy")
    toast.success(`Hi! Now you can: ctrl+v: ${copyText.value} `)
  }

  return (
    <>
      <ToastContainer />
      <Container>
                <span>E-mail</span>
              <input
                readOnly
                type="text"
                value="myemail@exemple.com"
                id="mail"
              />
              <button onClick={handleCopy}>Copy Email</button>
      </Container>
    </>
  )
}

您的答案仅包含对其他资源的引用,但没有具体答案。如果 w3schools 链接是正确的解决方案,请在此处输入。
m
manoj patel
 copyclip = (item) => {
    var textField = document.createElement('textarea')
    textField.innerText = item
    document.body.appendChild(textField)
    textField.select()
    document.execCommand('copy')
    this.setState({'copy':"Copied"});
    textField.remove()
    setTimeout(() => {
      this.setState({'copy':""});
    }, 1000);
 }

 <span   className="cursor-pointer ml-1" onClick={()=> this.copyclip(passTextFromHere)} >Copy</span> <small>{this.state.copy}</small>

T
Thilanka
const handleCopy = async () => {
    let copyText = document.getElementById('input') as HTMLInputElement;
    copyText.select();
    document.execCommand('copy');
  };

return (
  <TextField
     variant="outlined"
     value={copyText}
     id="input" 
  />
);

这对我来说是工作。


A
Alan

这是我的代码:

import React from 'react'

class CopyToClipboard extends React.Component {

  textArea: any

  copyClipBoard = () => {
    this.textArea.select()
    document.execCommand('copy')
  }

  render() {
    return (
      <>
        <input style={{display: 'none'}} value="TEXT TO COPY!!" type="text" ref={(textarea) => this.textArea = textarea}  />
        <div onClick={this.copyClipBoard}>
        CLICK
        </div>
      </>

    )
  }
}

export default CopyToClipboard

c
camille
<input
value={get(data, "api_key")}
styleName="input-wrap"
title={get(data, "api_key")}
ref={apikeyObjRef}
/>
  <div
onClick={() => {
  apikeyObjRef.current.select();
  if (document.execCommand("copy")) {
    document.execCommand("copy");
  }
}}
styleName="copy"
>
  复制
</div>

请添加此代码如何解决问题的说明,而不仅仅是发布代码。
B
Blessing

您还可以使用以下代码将 react 钩子用于功能组件或无状态组件: PS:确保使用以下命令通过 npm/yarn 安装 useClippy:npm install use-clippy 或 yarn add use-clippy

import React from 'react';
import useClippy from 'use-clippy';

export default function YourComponent() {

// clipboard is the contents of the user's clipboard.
  // setClipboard('new value') wil set the contents of the user's clipboard.

  const [clipboard, setClipboard] = useClippy();

  return (
    <div>

      {/* Button that demonstrates reading the clipboard. */}
      <button
        onClick={() => {
          alert(`Your clipboard contains: ${clipboard}`);
        }}
      >
        Read my clipboard
      </button>

      {/* Button that demonstrates writing to the clipboard. */}
      <button
        onClick={() => {
          setClipboard(`Random number: ${Math.random()}`);
        }}
      >
        Copy something
      </button>
    </div>
  );
}

H
Hossam Marey

您可以使用 useRef 选择元素内的文本,然后将其复制到剪贴板

import React, { useRef } from "react";

const Comp = () => {
   const copyTxt = useRef();

   const handleCopyTxt = () => {
   let txtDiv = copyTxt.current;
      if (document.selection) {
        // IE
        var range = document.body.createTextRange();
        range.moveToElementText(txtDiv);
        range.select();
      } else if (window.getSelection) {
        // other browsers
        var range = document.createRange();
        range.selectNode(txtDiv);
        window.getSelection().removeAllRanges();
        window.getSelection().addRange(range);
      }
      document.execCommand("copy");
    }

    return ( <div ref={copyTxt} > some text to copied </div> )
}

D
Davey

受@nate 回答的启发,我创建了一个 withCopyText 反应钩子。并且,添加了 navigator.clipboard.writeText 支持和 execCommand 回退。

钩子意味着它可以在许多组件中重用,而无需重复代码。有关实施,请参阅示例组件 CopyText

import React, { useRef, useState } from 'react';

const withCopyText = (textElementRef) => {
  if (!textElementRef) throw 'withCopyText: ref is required';

  const [copyStatus, setCopyStatus] = useState('');
  const [support, setSupport] = useState({
    navigatorClipboard: !!navigator.clipboard,
    exec: !!document.queryCommandSupported('copy'),
  });

  const copyToClipboard = (e) => {
    if ('' !== copyStatus) {
      setCopyStatus('');
      await new Promise((resolve) => setTimeout(resolve, 200));
    }

    // clipboard.writeText has wide but not 100% support
    // https://caniuse.com/?search=writeText
    if (support.navigatorClipboard) {
      try {
        navigator.clipboard.writeText(textElementRef.current.value);
        return setCopyStatus('success');
      } catch (e) {
        setSupport({ ...support, navigatorClipboard: false });
      }
    }
    // execCommand has > 97% support but is deprecated, use it as a fallback
    // https://caniuse.com/?search=execCommand
    // https://developer.mozilla.org/en-US/docs/Web/API/Document/execCommand
    if (!support.navigatorClipboard) {
      try {
        textElementRef.current.select();
        document.execCommand('copy');
        e.target.focus();
        setCopyStatus('success');
      } catch (e) {
        setSupport({ ...support, exec: false });
        return setCopyStatus('fail');
      }
    }
  };

  return {
    copyStatus,
    copyToClipboard,
    support: Object.values(support).includes(true),
  };
};

const CopyText = ({ text }) => {
  const textElementRef = useRef(null);

  const { copyStatus, copyToClipboard, support } = withCopyText(textElementRef);

  return (
    <span>
      {support && <button onClick={copyToClipboard}>Copy</button>}
      {'success' === copyStatus && <span>Copied to clipboard!</span>}
      {'fail' === copyStatus && <span>Sorry, copy to clipboard failed</span>}
      <input type="text" ref={textElementRef} value={text} readOnly={true} />
    </span>
  );
};

export { CopyText, withCopyText };


S
Shahnad

对于 React 开发人员

 const preventCopyPasteBody = (state) => {
       document.addEventListener(state, (evt) => {
      if (evt.target.id === 'body') {
             evt.preventDefault();
           return false;
          }
        return false;
       }, false);
      }

 preventCopyPasteBody ("contextmenu")
 preventCopyPasteBody ("copy")
 preventCopyPasteBody ("paste")
 preventCopyPasteBody ("cut")

<Typography id="body" variant="body1"  component="div" className={classes.text} style={{ fontSize: fontSize }}>{story}</Typography>

M
Maverick
make a componant as follows :- 

//react functional componant 

import React, { useState } from "react";

function CopyToClipboard(props) {
  const [copied, setCopied] = useState("copy");
  return (
    <div
      className="font-medium mr-4 text-green-700 cursor-pointer"
      onClick={() => {
        navigator.clipboard.writeText(props.text);
        setCopied("copied");
      }}>
      {copied}
    </div>
  );
}

export default CopyToClipboard;

//then use this componant anywhere

<CopyToClipboard text={"text you want to copy"}></CopyToClipboard>

//it will give a text saying "copy"`enter code here` and after clicking on that text, text provided with props will get copied