问题描述
在使用Vue实现一个纠错功能页,需求是展示一段文本,同时根据一个错误词列表(包含错误词位置、错误词替换建议等,从后端API获取)展示其中有错误的词语。
我已经有了自己的一部分实现,但是觉得存在一些问题,希望能得到大家的建议
希望达到的效果是:
- 左侧展示原文,令这些错误词在原文中突出显示(如下划线)
- 右侧展示错误词列表
- 点击原文中的错误词能展开右侧的表项
- 点击右侧表项能高亮原文中的对应词
类似效果图如下(以Grammaly为参照)
尝试过的方法
目前实现需求1.的办法是,利用v-html展示一段parse过的内容,该内容在获取的原文的基础上(即:是一个依赖于原文的computed属性),在需要突出显示的词语两侧插入一个<span class="highlight">
标签
但是该方法可能有以下问题,所以希望知道大家有没有更推荐的解决方案
- Vue明确指出不要使用v-html以避免XSS攻击,但我不清楚如何不用v-html实现上述需求(动态根据错误词改变原文展示的样式)
- parse原文并插入标签的办法完全基于字符串拼接,但感觉字符串拼接很低效且容易出错
实现需求3.的方法是,在上一步中为每个<span>
多插入一个唯一对应右边表项的id
,捕获文本点击事件中的该id
以找到右侧表项并展开之
实现需求4.的方法是,根据上述id
找到parse过的原文的该标签,在这个标签两侧再插入一对<span class="selected">
标签以高亮之
有没有更加优雅的实现高亮选中词语的方法呢?
有没有更好的实现文中词语于右侧表项对应的方法呢?
涉及的代码主要是字符串拼接,因此就不放了,先行感谢各位的解答!
###仅说说需求 1
XSS
攻击仅在用户输入的内容需要在其他用户或管理后台渲染的时候才会生效,比如用户个性签名,在用户自己的界面触发完全没用,所以如果不考虑多人联机、中台后台查询汇总、文档分享的话,v-html
没啥问题。
或者你也可以这样:把所有内容切分成段,每一段用一个 span 标签占位,用 v-html
渲染出来之后,用 DOM
接口获取对应元素,然后修改其 .innerText
,这样就可以有效防止 XSS
。例如:
'李彦宏是百度总栽'里,需要高亮“李彦宏”、标错“总栽”,那么整句话切分之后就成了数组:
const textArray = [
{
token: 0,
text: '李彦宏',
type: 'high-light'
},
{
token: 1,
text: '是百度'
},
{
token:
2,
text: '总栽',
type: 'error',
suggestion: '总裁'
}
]
用 span
标签占位渲染出 html:
'<span data-token="0" type="high-light" class="high-light"></span>\
<span data-token="1" ></span>\
<span data-token="2" type="error" class="error"></span>'
获取各 span,替换 innerText
:
[].forEach.bind(wapper.querySelector('span'))((item, index) => {
const { [index]: {text, suggestion}} = textArray;
item.innerText = text;
if(item.getAttribute('type') === 'error'){
item.setAttribute('data-suggestion', suggestion);
// 这里假设使用伪元素来显示建议: content: attr('data-suggestion')
}
});
这些操作也可以在插入 DOM 前完成,减少内容更改导致的渲染回流。
另外,有了 token
,其他两个问题也都可以解决。
有解决吗?我最近也遇到了相同的需求