富文本内容高亮搜索的内容

概要

在后台管理系统中有的数据是用富文本编辑器编写的,然后在前台页面渲染出来,这时会有搜索高亮富文本内容的相应功能,以及点击查找下一个类似的。

例如:网站自带这种搜索关键字功能

在这里插入图片描述

整体架构流程

该功能使用mask.js实现富文本高亮,简易的使用了下mark的标记方法!

技术细节

该功能使用简单的html的demo来演示,首先引入mark.js,可以去下载或者直接通过bootcdn搜索引入库

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>富文本搜索高亮</title>
    <script src="https://cdn.bootcdn.net/ajax/libs/mark.js/8.11.1/mark.min.js"></script>
</head>

编写一个测试富文本html内容

<div id="editor">
        <span>我的亚<span>索很6</span></span>
        <p>我的瞎子也不赖啊88一起啊</p>
        <span>89我开了</span>
        <span>8我开了9</span>
        <span>8.9</span>
        <span>8</span>
        <span>9</span>
    </div>

获取editor节点,使用Mark实例节点,然后使用mark方法标记文本内容,这样就能标记相应的文本信息

        const searchValue = '8.9'
        const editor = document.getElementById('editor')
        const mark = new Mark(editor)
        const searchList = searchValue.split('')
        // 标记文本  先按照8和9标记,保证相关文本都标记为mark标签,标记完后默认是黄色背景
        searchList.forEach(value => {
            mark.mark(value)
        })

这边为什么把标记的内容拆开然后在多次分别标记?

  • 一些富文本内容可能由多个标签组成,例如如下89分开,但是如果直接调用mark方法高亮89就会不生效,所以分开高亮内容保证所有文本都能被选取到然后再做处理
    在这里插入图片描述

调用mark方法后,会把高亮的内容嵌套一个mark标签,并且给了相应的默认黄色背景高亮色
在这里插入图片描述

接下来就是获取所有的mark标签,然后先暂时将这些的mark标签高亮背景色去掉,在去处理真正高亮的mark标签,循环获取的mark节点,每次增加数为高亮文本的长度,然后获取该长度之间每每首尾之间节点的文本内容,然后对比和高亮的文本内容是否相等,相等就给这个区间的mark节点高亮!

const marks = document.querySelectorAll('mark')
        // 先将选中的mark背景色去掉
        marks.forEach(markDom =>  markDom.style.background = 'transparent')
        const len = searchList.length 
        for(let i = 0;i<marks.length;i += len) {
            const startNode = marks[i]
            const endNode = marks[i+len-1]
            const betweenText = getDodeBetweenText(editor,startNode,endNode)
            // 两个mark之间的文本信息和搜索的文本信息一致在给这之间的所有mark标记
            if(betweenText === searchValue) {
                for(let j=i;j<i+len;j++) {
                    const markDom = marks[j]
                    markDom && (markDom.style.background = 'yellow')
                }
            }
        }
        /**
         * @description: 获取两元素之间的文本信息,包含头尾
         * @param {*} rootNode 父节点
         * @param {*} startNode 开始节点
         * @param {*} endNode 结束节点
         * @return {*}
         */        
        function getDodeBetweenText(rootNode,startNode,endNode) {
            let pastStartNode = false, reachedEndNode = false, textNodes = []
            function getTextNodes(node) {
                if(node == startNode) {
                    pastStartNode = true
                    textNodes.push(node)
                }else if(node == endNode) {
                    reachedEndNode = true
                    textNodes.push(node)
                }else if(node.nodeType == 3) {
                    if(pastStartNode && !reachedEndNode && !/^\s*$/.test(node.nodeValue)) {
                        textNodes.push(node)
                    }
                }else {
                    const len = [...node.childNodes].length
                    for(let i = 0;!reachedEndNode && i < len;i++) {
                        getTextNodes(node.childNodes[i])
                    }
                }
            }
            if(startNode == endNode) {
                return startNode.innerText
            }else {
                getTextNodes(rootNode)
                return textNodes.map(i => i.textContent).join('')
            }
        }

整体代码


<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>富文本搜索高亮</title>
    <script src="https://cdn.bootcdn.net/ajax/libs/mark.js/8.11.1/mark.min.js"></script>
</head>
<body>
    <div id="editor">
        <span>我的亚<span>索很6</span></span>
        <p>我的瞎子也不赖啊88一起啊</p>
        <span>89我开了</span>
        <span>8我开了9</span>
        <span>8.9</span>
        <span>8</span>
        <span>9</span>
    </div>
    <script>
        const searchValue = '8.9'
        const editor = document.getElementById('editor')
        const mark = new Mark(editor)
        const searchList = searchValue.split('')
        // 标记文本  先按照8和9标记,保证相关文本都标记为mark标签,标记完后默认是黄色背景
        searchList.forEach(value => {
            mark.mark(value)
        })
        const marks = document.querySelectorAll('mark')
        // 先将选中的mark背景色去掉
        marks.forEach(markDom =>  markDom.style.background = 'transparent')
        const len = searchList.length 
        for(let i = 0;i<marks.length;i += len) {
            const startNode = marks[i]
            const endNode = marks[i+len-1]
            const betweenText = getDodeBetweenText(editor,startNode,endNode)
            // 两个mark之间的文本信息和搜索的文本信息一致在给这之间的所有mark标记
            if(betweenText === searchValue) {
                for(let j=i;j<i+len;j++) {
                    const markDom = marks[j]
                    markDom && (markDom.style.background = 'yellow')
                }
            }
        }
        /**
         * @description: 获取两元素之间的文本信息,包含头尾
         * @param {*} rootNode 父节点
         * @param {*} startNode 开始节点
         * @param {*} endNode 结束节点
         * @return {*}
         */        
        function getDodeBetweenText(rootNode,startNode,endNode) {
            let pastStartNode = false, reachedEndNode = false, textNodes = []
            function getTextNodes(node) {
                if(node == startNode) {
                    pastStartNode = true
                    textNodes.push(node)
                }else if(node == endNode) {
                    reachedEndNode = true
                    textNodes.push(node)
                }else if(node.nodeType == 3) {
                    if(pastStartNode && !reachedEndNode && !/^\s*$/.test(node.nodeValue)) {
                        textNodes.push(node)
                    }
                }else {
                    const len = [...node.childNodes].length
                    for(let i = 0;!reachedEndNode && i < len;i++) {
                        getTextNodes(node.childNodes[i])
                    }
                }
            }
            if(startNode == endNode) {
                return startNode.innerText
            }else {
                getTextNodes(rootNode)
                return textNodes.map(i => i.textContent).join('')
            }
        }
    </script>
</body>
</html>

小结

富文本内容存在多种多样,以上处理并不完善,遇到特殊情况可以特殊处理。同时可以在该功能上实现查找下一个上一个功能。菜鸟一枚,感谢观看!

  • 47
    点赞
  • 35
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值