专业编程基础技术教程

网站首页 > 基础教程 正文

简单的撸一个一键复制

ccvgpt 2024-08-29 13:16:36 基础教程 68 ℃

简单的撸一个一键复制

相信做前端的小伙伴们,无论是PC端还是H5, 都或多或少会接触到'一键复制'这样的需求。今天就针对H5,来撸一个简单的Clipboard。

简单的撸一个一键复制


知识准备

  • document.execCommand: 执行一个相对当前文档的命令。
document.execCommand(commandName, showDefaultUi, defaultValue)
/*
 * commandName: 命令名称,如: copy, backColor, ClearAuthenticationCache等。
 * showDefaultUi: 是否展示用户界面,默认值为false。
 * defaultValue: 一些命令需要的默认参数,比如insetImage 的 src。
*/

兼容性:

mdn doc: https://developer.mozilla.org/zh-CN/docs/Web/API/Document/execCommand

  • command: copy: 拷贝当前选中内容到剪贴板(划重点)

mdn doc: https://developer.mozilla.org/zh-CN/docs/Web/Events/copy

  • window.getSelection: 返回一个selection对象,表示用户选择的文本范围或光标的当前位置。一般我们使用toString()方法来获取当前选中的字符串。
  • 兼容性:

mdn doc: https://developer.mozilla.org/zh-CN/docs/Web/API/Window/getSelection

  • setSelectionRange(for inputElement): 可以从一个focus的input元素中选定指定起始位置的内容。
inpurElement.setSelectionRange(selectionStart, selectionEnd, selectionDirection)
/*
 * selectionStart: 被选中的第一个字符的位置
 * selectionEnd: 被选中的最后一个字符的下一个位置
 * selectionDirection: 选中方向
*/

兼容性:

mdn doc: https://developer.mozilla.org/zh-CN/docs/Web/API/HTMLInputElement/setSelectionRange


思考

我们主要使用的是浏览器给我们提供的copy命令。而copy命令通过复制被选中区域到系统剪贴板。这里我们可以联想到我们的setSelectionRange方法可以将一个聚焦状态下的input元素中的内容按照自己指定的起始位置进行选中效果。嘛~这里我们整个clipboard的思路就已经讲完了。下面我们看看代码具体怎么实现。


code

step 1

监听copy命令: 原因是不止是我们使用document.execCommand('copy')命令来触发复制命令,使用键盘的ctrl + c也是可以触发的。所以要面面俱到。

/**
 * 1. 全局监听copy方法
 * 2. 将获取到copy的字符串存储到本地存储中,确保数据不会丢失
 */
document.addEventListener('copy', () => {
 const value = window.getSelection()?.toString()
 FACKSETSTRONGE({
 key: CLIPBOARDNAME,
 value
 }).catch(error => {})
})

step2

这个过程中我们需要动态的创建input的元素来为我们达到选中这个条件,所以,我们单独的将生成input的方法封装出来。

/**
 * createInput for fack selection
 * @params value<String>
 */
fackInput(value = '') {
 const FACKINPUT = document.createElement('input')
 FACKINPUT.setAttribute('readonly', 'readonly')
 FACKINPUT.setAttribute('value', value)
 FACKINPUT.style.cssText = `
 position: fixed;
 top: -200000px;
 left: -200000px;
 `
 document.body.appendChild(FACKINPUT)
 FACKINPUT.focus()
 this.FACKINPUT = FACKINPUT
}

step3

动态创建也要动态销毁,避免内存泄漏。

/**
 * removeFackInput
 * @params fackInput<HTMLELEMENT>
 */
removeFackInput(fackInput = null) {
 if (fackInput) {
 document.body.removeChild(fackInput)
 }
}

step4

设置剪贴板内容,大概逻辑过程为: 首先判断是否有设置内容,若无抛出错误。若存在设置内容,首先存储到本地存储,之后通过document.execCommand('copy')来判断是否可以使用copy命令。并按照上面我们的思路将内容设置到剪贴板。

/**
 * 设置系统clipboard
 * @params options<Object> { data<String> }
 */
_set({ data = '' }) {
 return new Promise((resolve, reject) => {
 /* 若无设置内容抛出异常 */
 if (!data) {
 reject(GENERATIONMSG({ code: COMMONERROR, data: 'the action of setclipboard need a value' }))
 }
 /* 首先设置本地存储防止数据丢失 */
 FACKSETSTRONGE({
 key: CLIPBOARDNAME,
 value: data
 }).then(() => {
 if (document.execCommand('copy')) {
 this.fackInput(data)
 if (this.FACKINPUT.setSelectionRange) {
 this.FACKINPUT.setSelectionRange(0, this.FACKINPUT.value.length)
 document.execCommand('copy')
 this.removeFackInput()
 resolve(GENERATIONMSG({ code: SUCCESSCODE, data }))
 }
 } else {
 reject(GENERATIONMSG({ code: COMMONERROR, data: 'the systerm do not have a command copy' }))
 }
 }).catch(error => {
 reject(GENERATIONMSG({ code: COMMONERROR, data: error }))
 })
 })
}

step5

获取剪贴板内容, 当然你可以直接ctrl + v, 或者在手机上长按呼出黏贴操作。若主动调用则需使用此方法。其实就是简单的从本地存储中取出来。

/**
 * 获取系统clipboard
 */
_get() {
 return new Promise((resolve, reject) => {
 FACKGETSTRONGE({
 key: CLIPBOARDNAME
 }).then(({ data = '' }) => {
 resolve(GENERATIONMSG({ code: SUCCESSCODE, data }))
 }).catch(error => {
 reject(GENERATIONMSG({ code: COMMONERROR, data: error }))
 })
 })
}

step6

使用方法。

<script src='path/clipboard.min.js'></script>
<script>
 // _clipboard 已经默认挂载到window上了,可以直接使用
 // set
 _clipboard._set({ data: 'your clipboard data' }).then(res => successHandler).catch(error => errorHandler)
 // get
 _clipboard._get().then(res => console.log(res.data)).catch(error => errorHandler)
</script>

至此,一个简单的clipboard api编写完毕了。可以满足我们日常的一键复制需求。希望大家从中可以学到新的知识点。yeah~


完整代码如下

当中部分方法可以移步github地址来查看: https://github.com/mobile-plugin/ClipBoardForH5

/**
 * clipboard
 */
class Clipboard {
 constructor() {
 /**
 * 1. 全局监听copy方法
 * 2. 将获取到copy的字符串存储到本地存储中,确保数据不会丢失
 */
 document.addEventListener('copy', () => {
 const value = window.getSelection()?.toString()
 FACKSETSTRONGE({
 key: CLIPBOARDNAME,
 value
 }).catch(error => {})
 })
 }
 /**
 * 设置系统clipboard
 * @params options<Object> { data<String> }
 */
 _set({ data = '' }) {
 return new Promise((resolve, reject) => {
 /* 若无设置内容抛出异常 */
 if (!data) {
 reject(GENERATIONMSG({ code: COMMONERROR, data: 'the action of setclipboard need a value' }))
 }
 /* 首先设置本地存储防止数据丢失 */
 FACKSETSTRONGE({
 key: CLIPBOARDNAME,
 value: data
 }).then(() => {
 if (document.execCommand('copy')) {
 this.fackInput(data)
 if (this.FACKINPUT.setSelectionRange) {
 this.FACKINPUT.setSelectionRange(0, this.FACKINPUT.value.length)
 document.execCommand('copy')
 this.removeFackInput()
 resolve(GENERATIONMSG({ code: SUCCESSCODE, data }))
 }
 } else {
 reject(GENERATIONMSG({ code: COMMONERROR, data: 'the systerm do not have a command copy' }))
 }
 }).catch(error => {
 reject(GENERATIONMSG({ code: COMMONERROR, data: error }))
 })
 })
 }
 /**
 * 获取系统clipboard
 */
 _get() {
 return new Promise((resolve, reject) => {
 FACKGETSTRONGE({
 key: CLIPBOARDNAME
 }).then(({ data = '' }) => {
 resolve(GENERATIONMSG({ code: SUCCESSCODE, data }))
 }).catch(error => {
 reject(GENERATIONMSG({ code: COMMONERROR, data: error }))
 })
 })
 }
 /**
 * createInput for fack selection
 * @params value<String>
 */
 fackInput(value = '') {
 const FACKINPUT = document.createElement('input')
 FACKINPUT.setAttribute('readonly', 'readonly')
 FACKINPUT.setAttribute('value', value)
 FACKINPUT.style.cssText = `
 position: fixed;
 top: -200000px;
 left: -200000px;
 `
 document.body.appendChild(FACKINPUT)
 FACKINPUT.focus()
 this.FACKINPUT = FACKINPUT
 }
 /**
 * removeFackInput
 * @params fackInput<HTMLELEMENT>
 */
 removeFackInput(fackInput = null) {
 if (fackInput) {
 document.body.removeChild(fackInput)
 }
 }
}

你也可以关注我的公众号

最近发表
标签列表