JavaScript实战笔记(四) 选中文本高亮

以下代码可以实现用户选中文本之后点击高亮按钮,会高亮选中的文本

由于博主最近事情比较多,所以只是稍微写了个例子,有不足之处,请多多见谅

<!DOCTYPE html>
<html>
<head>
    <title>选中文本高亮</title>
    <style>
        span {
            word-wrap: break-word;
            word-break: break-all;
        }
    </style>
    <script>
        function createRandomNumber(start, end) {
            return (end >= start) ? Math.floor(Math.random() * (end - start) + start) : null
        }

        function createRandomString(length, source) {
            var length = length || 52
            var source = source || 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'
            var result = []
            for (let i = 1; i <= length; i += 1) result.push(source.charAt(createRandomNumber(0, source.length)))
            return result.join('')
        }

        function initDom() {
            let button = document.createElement('button')
            button.id = 'highlight'
            button.innerHTML = 'Highlight'
            document.body.appendChild(button)

            let div = document.createElement('div')
            div.id = 'article'
            document.body.appendChild(div)

            let fragment = document.createDocumentFragment()
            for (let i = 1; i <= 10; i += 1) {
                let span = document.createElement('span')
                span.id = 'highlightable-' + i.toString()
                span.innerHTML = createRandomString()
                fragment.appendChild(span)
            }
            document.getElementById('article').appendChild(fragment)
        }

        function initData() {
            let result = {}
            let collection = document.getElementById('article').getElementsByTagName('span')
            Array.prototype.forEach.call(collection, (item) => {
                result[item.id] = new Object()
                result[item.id]['htmlString'] = item.innerHTML
                result[item.id]['infoArray'] = []
            })
            return result
        }

        function updateInfo(infoArray, newInfo) {
            let result = []
            let [newStartIdx, newEndIdx, newColor] = newInfo
            for (let orgInfo of infoArray) {
                let [orgStartIdx, orgEndIdx, orgColor] = orgInfo
                if (orgStartIdx >= newStartIdx && orgStartIdx <= newEndIdx) {
                    if (orgEndIdx >= newStartIdx && orgEndIdx <= newEndIdx) continue
                    else result.push([newEndIdx, orgEndIdx, orgColor])
                }
                else if (orgEndIdx >= newStartIdx && orgEndIdx <= newEndIdx) {
                    if (orgStartIdx >= newStartIdx && orgStartIdx <= newEndIdx) continue
                    else result.push([orgStartIdx, newStartIdx, orgColor])
                }
                else {
                    result.push([orgStartIdx, orgEndIdx, orgColor])
                }
            }
            result.push(newInfo)
            result.sort((info1, info2) => {
                if (info1[0] < info2[0]) return 1
                else if (info1[0] > info2[0]) return -1
                else return 0
            })
            return result
        }

        function highlightHelper(data, id) {
            let item = data[id]
            if (item == null) return null
            let elem = document.getElementById(id)
            if (elem == null) return null
            let htmlString = item['htmlString']
            let infoArray = item['infoArray']
            let result = htmlString
            for (let info of infoArray) {
                let [startIdx, endIdx, color] = info
                let startHtml = result.substring(0, startIdx)
                let middleHtml = result.substring(startIdx, endIdx)
                let endHtml = result.substring(endIdx)
                result = startHtml + `<span style="color:${color}">` + middleHtml + '</span>' + endHtml
            }
            return result
        }

        function highlightSelection(data, color) {
            let selection = document.getSelection()
            if (selection.type !== 'Range') return
            let range = selection.getRangeAt(0)
            if (range.length === 0) return
            let startContainer = range.startContainer
            let endContainer = range.endContainer
            let startOffset = range.startOffset
            let endOffset = range.endOffset
            let startNode = startContainer.parentElement
            while (startNode.id.search(/highlightable-[0-9]+/) === -1) startNode = startNode.parentElement
            let endNode = endContainer.parentElement
            while (endNode.id.search(/highlightable-[0-9]+/) === -1) endNode = endNode.parentElement
            let currNode = startNode
            while (true) {
                let id = currNode.id
                let startIdx = 0
                let endIdx = 0
                let isStartNode = (currNode === startNode)
                let isEndNode = (currNode === endNode)
                if (isStartNode && isEndNode) {
                    let isFinishStart = false
                    let isFinishEnd = false
                    for (let child of currNode.childNodes) {
                        let isTextNode = (child.tagName == null)
                        let isStartContainer = (child === startContainer || child === startContainer.parentElement)
                        let isEndContainer = (child === endContainer || child === endContainer.parentElement)
                        let childLength = isTextNode ? child.length : child.innerHTML.length
                        if (!isFinishStart && !isStartContainer) {
                            startIdx += childLength
                            endIdx += childLength
                        } else if (!isFinishStart && isStartContainer && !isEndContainer) {
                            startIdx += startOffset
                            endIdx += childLength
                            isFinishStart = true
                        } else if (!isFinishStart && isStartContainer && isEndContainer) {
                            startIdx += startOffset
                            endIdx += endOffset
                            isFinishStart = true
                            isFinishEnd = true
                        } else if (isFinishStart && !isFinishEnd && !isEndContainer) {
                            endIdx += childLength
                        } else if (isFinishStart && !isFinishEnd && isEndContainer) {
                            endIdx += endOffset
                            isFinishEnd = true
                        } else {

                        }
                    }
                } else {
                    if (isStartNode) {
                        let isFinishStart = false
                        for (let child of currNode.childNodes) {
                            let isTextNode = (child.tagName == null)
                            let childLength = isTextNode ? child.length : child.innerHTML.length
                            let isStartContainer = (child === startContainer || child === startContainer.parentElement)
                            if (!isFinishStart && !isStartContainer) {
                                startIdx += childLength
                                endIdx += childLength
                            } else if (!isFinishStart && isStartContainer) {
                                startIdx += startOffset
                                endIdx += childLength
                                isFinishStart = true
                            } else if (isFinishStart) {
                                endIdx += childLength
                            }
                        }
                    } else if (isEndNode) {
                        let isFinishEnd = false
                        for (let child of currNode.childNodes) {
                            let isTextNode = (child.tagName == null)
                            let childLength = isTextNode ? child.length : child.innerHTML.length
                            let isEndContainer = (child === endContainer || child === endContainer.parentElement)
                            if (!isFinishEnd && !isEndContainer) {
                                endIdx += childLength
                            } else if (!isFinishEnd && isEndContainer) {
                                endIdx += endOffset
                                isFinishEnd = true
                            } else if (isFinishEnd) {
                                
                            }
                        }
                    } else {
                        for (let child of currNode.childNodes) {
                            let isTextNode = (child.tagName == null)
                            let childLength = isTextNode ? child.length : child.innerHTML.length
                            endIdx += childLength
                        }
                    }
                }
                data[id]['infoArray'] = updateInfo(data[id]['infoArray'], [startIdx, endIdx, color])
                currNode.innerHTML = highlightHelper(data, id)
                if (currNode === endNode) break
                currNode = currNode.nextElementSibling
            }
            document.getSelection().empty()
        }

        window.onload = function() {
            initDom()
            let globalData = initData()
            document.getElementById('highlight').addEventListener('click', () => {
                highlightSelection(globalData, 'red')
            })
        }
    </script>
</head>
<body>

</body>
</html>

【 阅读更多 JavaScript 系列文章,请看 JavaScript学习笔记

猜你喜欢

转载自www.cnblogs.com/wsmrzx/p/12439530.html