关于clipboard:我从Typora中学到的Clipboard妙用md

12次阅读

共计 3056 个字符,预计需要花费 8 分钟才能阅读完成。

Typora 是我常常应用的一款软件,用来写 MarkDown 很舒服,有着十分优良的应用体验:

  • 实时预览
  • 自定义图片上传服务
  • 文档转换
  • 主题自定义

起因

不过我遇到一个十分好玩的事件,当我复制 Typora 内容粘贴到文本编辑器时,会失去 MarkDown 格局的内容;复制到富文本编辑器时,能够渲染出富文本成果:

复制到 VS Code:

复制到其余富文本编辑器:

我很好奇为什么会呈现两种不同的后果,Typora 应该是应用 Electron(或相似技术)开发的,我尝试用 Clipboard API 来进行测试:

// 为什么应用 setTimeout:我是在 Chrome 控制台进行的测试,clipboard 依靠于页面,所以我须要设置 1s 延时,以便能够点击页面聚焦
setTimeout(async()=>{const clipboardItems = await navigator.clipboard.read();
    console.log(clipboardItems)
},1000)

而后看到了剪切板中有两种不同类型的内容:纯文本 text/plain 和富文本text/html。所以不同的内容接收者抉择了不同的内容作为数据,文本编辑器拿到的是纯文本,富文本编辑器获取的是富文本格式数据。

再来看看获取到的具体内容吧:

setTimeout(async()=>{const clipboardItems = await navigator.clipboard.read();
    console.log(clipboardItems)
    for (const clipboardItem of clipboardItems) {for (const type of clipboardItem.types) {const contentBlob = await clipboardItem.getType(type)
        const text = await contentBlob.text()
        console.log(text)
      }
    }
},1000)

Clipboard 塞入数据试一下:

setTimeout(async ()=>{
await navigator.clipboard.write([
      new ClipboardItem({["text/plain"]: new Blob(['# 纯文本和富文本'],{type:'text/plain'}),
        ["text/html"]: new Blob(['<h1 cid="n21"mdtype="heading"class="md-end-block md-heading md-focus"style="box-sizing: border-box; break-after: avoid-page; break-inside: avoid; orphans: 4; font-size: 2.25em; margin-top: 1rem; margin-bottom: 1rem; position: relative; font-weight: bold; line-height: 1.2; cursor: text; border-bottom-width: 1px; border-bottom-style: solid; border-bottom-color: rgb(238, 238, 238); white-space: pre-wrap; caret-color: rgb(51, 51, 51); color: rgb(51, 51, 51); font-family: &quot;Open Sans&quot;, &quot;Clear Sans&quot;, &quot;Helvetica Neue&quot;, Helvetica, Arial, &quot;Segoe UI Emoji&quot;, sans-serif; font-style: normal; font-variant-caps: normal; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; word-spacing: 0px; -webkit-text-stroke-width: 0px; background-color: rgb(255, 255, 255); text-decoration: none;"><span md-inline="plain"class="md-plain md-expand"style="box-sizing: border-box;"> 纯文本和富文本 </span></h1>'],{type:'text/html'}),
      })
    ]);
},[1000])

尝试了几个富文本编辑器失去的后果(不同富文本编辑器的具体实现可能存在差别):

  • 如果只存在纯文本(仅保留上段代码中的纯文本局部), 会读取剪切板中纯文本内容
  • 如果存在纯文本和富文本,会读取剪切板中富文本内容

那这个成果是 Typora 帮咱们实现的吗?

咱们先来看一下复制富文本的默认行为,关上一个网页,复制网页文本,而后应用方才的代码尝试一下,看看读取到的剪切板内容。

咱们能够看到,在复制富文本的时候,Chrome 实现的 clipboard API 都会生成两份后果,一份是纯文本格式text/plain,一份是富文本格式text/html

不同的是:当咱们在 Typora 复制时,失去的是 Markdown 格局的纯文本和富文本,是 Typora 帮咱们进行了解决。

监听复制,写入剪切板

监听复制咱们能够应用 HTMLElement.oncopy 实现:

关上任意一个网页,切换到控制台:

document.body.oncopy = function(e){console.log(e)
    var text = e.clipboardData.getData("text");
    console.log(text)
}

复制页面中内容,咱们就能够的看到打印的后果了:

原本为数据会在 clipboardData 中,然而尝试了一下并没有获取到内容,看来只能另辟蹊径了,咱们能够通过 Range API 来获取选中的内容。

document.body.oncopy = function(e){const selectionObj = window.getSelection()
        const rangeObj = selectionObj.getRangeAt(0)
    const fragment = rangeObj.cloneContents() // 获取 Range 蕴含的文档片段
    const wrapper = document.createElement('div')
    wrapper.append(fragment)
    navigator.clipboard.write([
      new ClipboardItem({["text/plain"]: new Blob([wrapper.innerText,'额定的文本'],{type:'text/plain'}),
        ["text/html"]: new Blob([wrapper.innerHTML,'<h1> 额定的富文本 </h1>'],{type:'text/html'}),
      })
    ])
}

监听复制还能够用来增加版权信息,比方下面代码中的 额定信息 就会呈现在复制的文本中。

对于复制和粘贴内容也能够通过 document.execCommand,不过目前属于曾经被弃用的 API,不倡议应用

参考文档:

ClipboardItem

Clipboard-write

element.oncopy

Selection

Range

正文完
 0