公众号图文编辑器开发必备技能:样式内联化和富文本粘贴攻略!


theme: cyanosis

图文编辑器是很多内容创作者和运营人员日常使用的工具,对于产品体验和使用效率的提升有着重要意义。在公众号编辑器开发中,有两个常见的难点需要解决:样式内联化和富文本粘贴。这里我们分别探讨一下这两个问题及其解决方案。

难点一:样式内联化

在网页开发中,我们通常使用外链CSS文件或内嵌标签来编写样式,利用选择器对页面元素进行渲染。然而,微信公众号编辑器并不支持单独配置CSS,而要求将样式直接内联到每个HTML元素的style属性中。这给样式的处理带来了挑战。

我们需要一种方式,能够从页面或特定区域中提取出CSS规则,并将其转化为每个元素的行内样式。幸运的是,开源库Juice提供了这样的解决方案。

Juice能够解析HTML文档,识别出标签中的CSS规则以及元素的选择器关系,进而将这些规则转化为对应元素的style属性。使用Juice的核心接口juice(html[, options])即可完成此操作。

以下是一个使用Juice内联化样式的示例:

const juice = require('juice');

const html = `

h1 { color: red; } p { font-size: 16px; }

Hello

This is a paragraph

`;

const inlinedHTML = juice(html);
console.log(inlinedHTML);

输出结果:

Hello

This is a paragraph

可以看到,原本在标签中的CSS规则,已经被转化为各个元素的style属性了。Juice还支持处理伪元素、媒体查询等高级CSS特性,并提供了丰富的配置选项,可以根据需要进行定制。

难点二:富文本粘贴

解决了样式内联化后,我们可以将处理后的HTML代码复制到公众号编辑器中。但是在尝试时,会发现编辑器并没有正确渲染出所期望的效果,而是直接显示了HTML代码。

这是因为,默认情况下,我们从其他地方复制的HTML代码会被识别为纯文本格式,编辑器无法将其渲染为富文本内容。要解决这个问题,我们需要在复制操作时,将数据设置为特定的HTML格式。

在Web平台中,我们可以使用clipboardAPI实现这一点。以下是一个示例:

export const copyHtml = (text) => {  
// 获取 input  
let input = document.getElementById('copy-placeholder')  
if (!input) {  
// input 不能用 CSS 隐藏,必须在页面内存在。  
input = document.createElement('input')  
input.id = 'copy-placeholder'  
input.style.position = 'absolute'  
input.style.left = '-1000px'  
input.style.zIndex = '-1000'  
document.body.appendChild(input)  
}  
// 让 input 选中一个字符,无所谓那个字符  
input.value = '开源地带'  
input.setSelectionRange(0, 1)  
input.focus()

// 复制触发
document.addEventListener(‘copy’, function copyCall(e) {
e.preventDefault()
e.clipboardData.setData(‘text/html’, text)
e.clipboardData.setData(‘text/plain’, text)
document.removeEventListener(‘copy’, copyCall)
})
document.execCommand(‘copy’)
}

在上面的代码中,我们是这样实现一键复制的:

  1. 首先,通过 document.getElementById('copy-placeholder') 获取 id 为 'copy-placeholder 的元素,这是一个 input 元素用于复制文本至剪贴板。如果不存在这个元素,则创建一个新的 input 元素,并设置其属性和样式,然后将其添加到页面的 body 元素中。

  2. 接下来,将一个无关紧要的字符('开源地带')赋值给 input 的 value 属性,并通过 input.setSelectionRange(0, 4) 将光标选中第一个字符。最后,调用 input.focus() 将焦点设置在 input 元素上。

  3. 为了触发复制操作,使用 document.addEventListener('copy', function copyCall(e) { ... }) 监听 copy 事件。当发生 copy 事件时,执行回调函数并传入事件对象作为参数。

  4. 在回调函数中,通过 e.clipboardData.setData('text/html', text) 和 e.clipboardData.setData('text/plain', text) 在剪贴板保存数据,设置两次剪贴板数据是为了兼容不同的剪贴板操作和目标应用程序的需求。

在剪贴板操作中,有两种常见的数据格式:HTML 格式和纯文本格式。不同的应用程序可能会优先选择其中一种格式进行粘贴操作。通过设置两种格式的剪贴板数据,可以增加在不同应用程序中成功粘贴的可能性。

e.clipboardData.setData('text/html', text) 将指定的文本设置为剪贴板的 HTML 格式数据。这种格式适用于支持粘贴 HTML 内容的应用程序,例如富文本编辑器或电子邮件客户端。如果目标应用程序支持 HTML 格式的剪贴板数据,并且用户选择粘贴 HTML 内容,那么设置了 HTML 格式的数据将被使用。

e.clipboardData.setData('text/plain', text) 将指定的文本设置为剪贴板的纯文本格式数据。这种格式适用于大多数应用程序,包括文本编辑器、文本框和终端等。如果目标应用程序不支持或不选择粘贴 HTML 内容,那么设置了纯文本格式的数据将被使用。

通过设置两种格式的剪贴板数据,可以提供更好的兼容性,以确保在不同的应用程序和粘贴场景中都能够成功地粘贴文本内容。

  1. 最后,使用 document.execCommand('copy') 执行复制操作,将选定的数据复制到剪贴板中。

这样我们粘贴到编辑器时,就能正确渲染出富文本效果。

总的来说,使用Juice可以解决公众号编辑器中的样式内联化问题,而利用clipboard API则可以实现富文本粘贴。两者的结合为编写高效、体验良好的公众号图文编辑器提供了可行的技术方案。当然,在实际开发中还需要考虑更多的细节,如编辑器排版、性能优化、错误处理和兼容性等,但掌握了上述核心思路,就能更好地架构和实现一个公众号图文编辑器产品。


这是一个从 https://juejin.cn/post/7368777511953809434 下的原始话题分离的讨论话题