实现效果:
标注功能实现思路一般有两种:
一、后端会把数据分两部分存储,①文章区纯文字②包含HTML结构的字符串
前端请求数据时直接返给前台,前端直接展示。
我们目前采用该思路,实现的还相对容易些
二、后端存储大的集合,包含文章源文字与标注信息集合(多标注点的起始点、结束点),前端取到该信息进行再进行处理回显与操作,该思路下也会衍生出很多问题,例如一旦插入span标签,会改变源文字长度,标注所记录的起始点、结束点信息会发生错误等
页面上文字标注过程中遇到几个问题:
一、添加标注(一个滑动选区的标注)
①当鼠标在文章中滑动选择时,选择区可用window.getSelection()获取,得到一个选区对象selObj
②selObj.toString()可得到鼠标选择的哪些文字
③selObj.getRangeAt(0)可得到range对象
④range.surroundContents(ele)即可把选择的包裹
二、移除
移除一个标注(title放入了要标注文字,然后用之直接替代所在DOM)
三、不能在文章区域外标注,只能在文章区域标注
四、标注同类高亮
选择文档区所有子元素,进行遍历,对未标注的同类进行替换操作,对已经标注的获取outerHTML,拼接成总HTML字符串,替换掉文章区DOM
五、标注源取消标注,同类高亮也跟随取消
(1)单独实现一、二功能时,添加移除是正常的,但经过四功能替换文章区DOM,移除会有问题
①把移除函数放在最外层DOM树上,点击某个按钮时,获取该按钮区域,再进行相关操作
(2)点击某一个标注的删除按钮时,其他相同标注也随之删除
①获取点击点目标,获取到tite。
let pText=e.target.parentElement.title
②获取容器下所有的子节点
let dom=document.getElementById('docText').childNodes
③对子节点集合进行遍历,经筛选过滤,判断title相等的,对该节点用title文字进行原地替换,以实现删除标注后的标签
for(let i=0;i<dom.length;i++){
//只对标注的节点操作
if(dom[i].textContent.indexOf('*]x') > -1){
if(dom[i].title === pText){
dom[i].replaceWith(pText)
}
}
}
六、标注回显
后台会把数据分两部分存储,①文章区纯文字②包含HTML结构的字符串
前台请求数据时直接返给前台
关键代码:
methods: {
toTag(value,index){
let that = this
let domNode = document.getElementById('docText')
//判断选择区域是否在docText中
let has=window.getSelection().containsNode(domNode, true)
if(has){//判断鼠标滑动区域是否在文档区域内
let str = value.proxy
let selObj=window.getSelection()
let txtString=selObj.toString()
let spanTxt = str.slice(0,2) + txtString + str.slice(2)
// console.log(spanTxt)
if(txtString){
let range=selObj.getRangeAt(0)
// console.log(range)
let ele=document.createElement('span')
let eleDel=document.createElement('span')
ele.style.backgroundColor=value.btnBgColor
ele.className='customTag'
ele.title=txtString
eleDel.className='del_bt'
eleDel.textContent='x'
// eleDel.onclick=()=>that.toDel(ele)
range.surroundContents(ele)
let s='<span class="tagText">'+ spanTxt +'</span>'
ele.innerHTML=s
ele.appendChild(eleDel)
//文章标注(所标选文字同类高亮)
let dom=document.getElementById('docText').childNodes
console.log(dom)
let pingStr=''
for(let i=0;i<dom.length;i++){
//同类高亮
//已经标注了的,排除掉。只对未标注的操作
if(dom[i].textContent.indexOf('*]x') === -1){
let paragraph=dom[i].textContent
let reg=new RegExp(txtString,'g')
let t=`<span class="customTag" title="${txtString}" style="background-color: rgb(167,173,177);"><span class="tagText">${spanTxt}</span><span class="del_bt">x</span></span>`
let replacedTxt=paragraph.replace(reg,t)
pingStr+=replacedTxt
// dom[i].replaceWith(replacedTxt)
// console.log(dom[i].textContent)
}else{
pingStr+=dom[i].outerHTML
// console.log(dom[i].outerHTML)
}
}
// console.log(pingStr)
document.getElementById('docText').innerHTML=pingStr
window.getSelection().removeAllRanges()
}
}else{
this.$modal.msgError("请在文档区域进行标记")
}
},
//点击删除按钮时 删除全部同类
toDel(e){
if(e.target.className==='del_bt'){
console.log(e.target.parentElement.title)
let pText=e.target.parentElement.title
console.log(document.getElementById('docText').childNodes)
let dom=document.getElementById('docText').childNodes
for(let i=0;i<dom.length;i++){
//只对标注的操作
if(dom[i].textContent.indexOf('*]x') > -1){
if(dom[i].title === pText){
dom[i].replaceWith(pText)
}
}
}
}
}
}