整合營(yíng)銷(xiāo)服務(wù)商

          電腦端+手機(jī)端+微信端=數(shù)據(jù)同步管理

          免費(fèi)咨詢(xún)熱線(xiàn):

          HTML高亮關(guān)鍵字的完美解決方案

          近項(xiàng)目做暈頭,一個(gè)接一個(gè),其中遇到這樣的一個(gè)功能,在網(wǎng)頁(yè)中高亮關(guān)鍵字的實(shí)現(xiàn)方法,下面小編把實(shí)現(xiàn)代碼及解決方案分享給大家,感興趣的的朋友跟隨小編一起看看吧

          最近做項(xiàng)目遇到這樣的一個(gè)功能:在網(wǎng)頁(yè)中高亮關(guān)鍵字。

          本以為一個(gè) innerHTML replace 就能實(shí)現(xiàn)的簡(jiǎn)單操作,卻遇到了許多的問(wèn)題。本文就記錄這些問(wèn)題和最終的完美解決辦法, 希望能對(duì)有同樣遭遇的小伙伴有所幫助。只對(duì)結(jié)果感興趣的,忽略過(guò)程,直接跳過(guò)看結(jié)果吧~

          常用做法:正則替換

          思路:要想高亮元素,那么需要將關(guān)鍵字提取出來(lái)用標(biāo)簽包裹,然后對(duì)標(biāo)簽進(jìn)行樣式調(diào)整。使用 innerHTML,或 outHTML, 而不能使用 innerText,outText。

          const regex = new RegExp(keyword,"g")
          element.innerHTML = element.innerHTML.replace(regex,"<b class="a">"+keyword+"</b>")
          element.classList.add("highlight")
          

          這樣做存在的隱患有如下:

          ()\
          div
          <div id="parent">
           <div class="test">test</div>
           </div>
          

          關(guān)鍵字父節(jié)點(diǎn) element 通過(guò) class 來(lái)進(jìn)行背景染色處理,對(duì)原始DOM有一定程度污染,可能對(duì) element 再次定位造成影響。(作為插件希望盡可能少改變?cè)糄OM)

          正則優(yōu)化一:僅處理位于標(biāo)簽內(nèi)的元素

          var formatKeyword = text.replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&') // 轉(zhuǎn)義處理keyword包含的特殊字符,如 /.
          var finder = new RegExp(">.*?"++".*?<") // 提取位于標(biāo)簽內(nèi)的文本,避免誤操作 class、id 等
           
          element.innerHTML = element.innerHTML.replace(finder,function(matched){
           return matched.replace(text,"<br>"+text+</br>)
          })// 對(duì)提取的標(biāo)簽內(nèi)文本進(jìn)行關(guān)鍵字替換
          

          以能解決大多數(shù)問(wèn)題,但依舊存在的問(wèn)題是,只要標(biāo)簽屬性存在類(lèi)似 < 符號(hào),將會(huì)打破匹配規(guī)則導(dǎo)致正則提取內(nèi)容錯(cuò)誤, HTML5 dataset 可以自定義任意內(nèi)容,故這些特殊字符是無(wú)法避免的。

          <div dataset="p>d">替換</div>
          

          正則優(yōu)化二:清除可能影響的標(biāo)簽

          <div id="keyword">keyword</div>
           =》將閉合標(biāo)簽用變量替換
           [replaced1]keyword[replaced2]//閉合標(biāo)簽內(nèi) id="keyword" 不會(huì)被處理
           =》
           [replaced1]<b>keyword</b>[replaced2]
           =》將暫存變量 replaced 替換為原先標(biāo)簽
           <div id="keyword"><b>keyword</b></div>
          
          • 這種思路及源碼從這里來(lái), 但存在問(wèn)題是:
          • 如果 [replaced1] 包含 keyword, 那么替換時(shí)將發(fā)生異常

          最重要的,當(dāng)標(biāo)簽值中包含 <> 符號(hào)時(shí),此方法也不能正確的提取標(biāo)簽

          總之在經(jīng)過(guò)了N多嘗試之后,通過(guò)正則都沒(méi)能有效的處理各種情況。然后換了個(gè)思路,不通過(guò)字符串的方式,通過(guò)節(jié)點(diǎn)處理。element.childNodes 可以最有效的清理標(biāo)簽內(nèi)的干擾信息。

          [完美解決方案]通過(guò) DOM 節(jié)點(diǎn)處理

          <div id="parent">
           keyword 1
           <span id="child">
           keyword 2
           </span>
           </div>
          

          通過(guò) parent.childNodes 得到所有子節(jié)點(diǎn)。child 節(jié)點(diǎn)可以通過(guò) innerText.replce(keyword,result) 的方式替換得到想要的高亮效果,如下: <span id="child"><b>keyword</b> 2</span> (遞歸處理:當(dāng)child節(jié)點(diǎn)不含子節(jié)點(diǎn)時(shí)進(jìn)行replace操作)。

          但是 keyword 1 是屬于文本節(jié)點(diǎn),只能修改文本內(nèi)容,無(wú)法增加 HTML,更無(wú)法單獨(dú)控制其樣式。而文本節(jié)點(diǎn)也不能轉(zhuǎn)換為普通節(jié)點(diǎn),這也是最苦惱的事情。

          最后~,本文的重點(diǎn)來(lái)了,因?yàn)檫@個(gè)功能,讓我第一次認(rèn)真接觸到了文本節(jié)點(diǎn)這個(gè)東西。從這里發(fā)現(xiàn)了Text,使用切割文本節(jié)點(diǎn)并替換的方式實(shí)現(xiàn)高亮。

          源碼以及還原高亮見(jiàn)源碼

          const reg = new RegExp(keyword.replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&'))
          highlight = function (node,reg){
           if (node.nodeType == 3) { //只處理文本節(jié)點(diǎn)
           const match = node.data.match(new RegExp(reg));
           if (match) {
           const highlightEl = document.createElement("b");
           highlightEl.dataset.highlight="y"
           const wordNode = node.splitText(match.index)
           wordNode.splitText(match[0].length); // 切割成前 關(guān)鍵詞 后三個(gè)Text 節(jié)點(diǎn)
           const wordNew = document.createTextNode(wordNode.data);
           highlightEl.appendChild(wordNew);//highlight 節(jié)點(diǎn)構(gòu)建成功
           wordNode.parentNode.replaceChild(highlightEl, wordNode);// 替換該文本節(jié)點(diǎn)
           }
           } else if (node.nodeType == 1 && node.dataset.highlight!="y"
           ) {
           for (var i = 0; i < node.childNodes.length; i++) {
           highlight(node.childNodes[i], reg);
           i++
           }
           } 
          }
          

          總結(jié)

          以上所述是小編給大家介紹的HTML高亮關(guān)鍵字的完美解決方案,希望對(duì)大家有所幫助,

          學(xué)習(xí)從來(lái)不是一個(gè)人的事情,要有個(gè)相互監(jiān)督的伙伴,想要學(xué)習(xí)或交流前端問(wèn)題的小伙伴可以私信“學(xué)習(xí)”小明加群獲取2019web前端最新入門(mén)資料,一起學(xué)習(xí),一起成長(zhǎng)!

          辛萬(wàn)苦寫(xiě)了篇技術(shù)分享,貼了一堆代碼,興高采烈地發(fā)到了自己的博客網(wǎng)站上。結(jié)果卻發(fā)現(xiàn)代碼全是白底黑字,字體還難看得很,你瞬間就沒(méi)了興致。能不能讓網(wǎng)頁(yè)也能像 IDE 那樣,做帶語(yǔ)法高亮的炫酷顯示呢?來(lái)看一看 Highlight.js 吧,看這個(gè)語(yǔ)法高亮庫(kù)如何點(diǎn)亮你的代碼。

          Highlight.js

          簡(jiǎn)介

          Highlight.js,是在 Github 上由 highlight.js 組織開(kāi)源的前端代碼語(yǔ)法高亮庫(kù),代碼倉(cāng)庫(kù)在 https://github.com/highlightjs/highlight.js,目前版本為 10.1.0。其不依賴(lài)于任何框架,自帶對(duì)于大量編程語(yǔ)言和標(biāo)記語(yǔ)言的語(yǔ)法高亮規(guī)則,和主流的高亮色彩方案,且可以自由擴(kuò)展。其支持自動(dòng)語(yǔ)言檢測(cè),使用極為方便,是在網(wǎng)頁(yè)上進(jìn)行語(yǔ)法高亮的不二之選。

          highlight.js語(yǔ)法高亮庫(kù)

          安裝

          Highlight.js 的 CSS 文件的選擇決定高亮配色方案,默認(rèn)為 Default,另外還有如 Monokai Sublime、Ocean、Solarized Dark、Tomorrow 等經(jīng)典的主流配色方案。

          而 JS 文件的選擇決定可以支持的語(yǔ)言。主要的 highlight.min.js 包含了一些主流的語(yǔ)言,包括 C++、XML、Markdown、Java 等。如果需要一些其他的語(yǔ)言,則要另外引用該語(yǔ)言對(duì)應(yīng)JS文件。

          Highlight.js 在瀏覽器中可以簡(jiǎn)單的引用 CDN 來(lái)使用:

          <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/10.1.0/styles/default.min.css">
          <script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/10.1.0/highlight.min.js"></script>

          示例

          Highlight.js 使用十分簡(jiǎn)單,在引用了 CSS 和 JS 后,執(zhí)行

          hljs.initHighlightingOnLoad();

          Highlight.js就會(huì)自動(dòng)查找網(wǎng)頁(yè)中以標(biāo)簽 pre 和 code 所包裹的代碼

          <pre><code>...</code></pre>

          并自動(dòng)檢測(cè)代碼語(yǔ)言,進(jìn)行高亮渲染。我們也可以為 code 標(biāo)簽添加語(yǔ)言名稱(chēng)的 class,來(lái)顯式地標(biāo)明代碼語(yǔ)言。我們可以看一個(gè)使用示例,注意實(shí)際代碼中尖括號(hào)等 HTML 轉(zhuǎn)義字符需要進(jìn)行轉(zhuǎn)義處理:

          <html>
          <head>
            <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/10.1.0/styles/monokai-sublime.min.css">
            <script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/10.1.0/highlight.min.js"></script>
          </head>
          <body>
            <pre><code class="cpp">#include <iostream>
          
          int main(int argc, char *argv[]) {
          
              /* An annoying "Hello World" example */
              for (auto i = 0; i < 0xFFFF; i++)
                  cout << "Hello, World!" << endl;
          
              char c = '\n';
              unordered_map <string, vector<string> > m;
              m["key"] = "\\\\"; // this is an error
          
              return -2e3 + 12l;
          }
            </code></pre>
            <script>
              hljs.initHighlightingOnLoad();
            </script>
          </body>
          </html>

          該網(wǎng)頁(yè)對(duì)于 C++ 語(yǔ)言片段使用了 Monokai Sublime 主題進(jìn)行了語(yǔ)法高亮渲染:

          使用Highlight.js渲染C++代碼

          可以看到,包括關(guān)鍵字、注釋和字面值等都有了不同顏色的渲染,輸出十分美觀(guān)。以下則是使 Dracula 主題對(duì) Javascript 代碼渲染的例子:

          使用Highlight.js渲染Javascript代碼

          我們也可以不使用 pre 和 code 標(biāo)簽來(lái)包裹代碼,改為使用自定義的容器,使用時(shí)需要注意換行和等寬字體的問(wèn)題。

          document.querySelectorAll('div.code').forEach((block) => {
            hljs.highlightBlock(block);
          });

          在渲染大量代碼時(shí),為避免瀏覽器卡死,可以使用 Web Worker 來(lái)在后臺(tái)進(jìn)行渲染:

          // index.html
          addEventListener('load', () => {
            const code = document.querySelector('#code');
            const worker = new Worker('worker.js');    // 新建Worker
            worker.onmessage = (event) => { code.innerHTML = event.data; }    // 接受渲染后的HTML
            worker.postMessage(code.textContent);    // 傳遞代碼
          });
          // worker.js
          onmessage = (event) => {
            importScripts('<path>/highlight.min.js');
            const result = self.hljs.highlightAuto(event.data);    // 高亮渲染
            postMessage(result.value);    // 返回HTML
          };

          總結(jié)

          Highlight.js 使得在前端頁(yè)面進(jìn)行語(yǔ)法高亮變得十分方便,為在網(wǎng)頁(yè)顯示的代碼增添了顏色和生機(jī)。

          Highlight.js 文檔詳盡,設(shè)計(jì)簡(jiǎn)潔,為編寫(xiě)新的語(yǔ)言支持和配色方案提供了很大支持,定制化能力和可擴(kuò)展性極強(qiáng)。Highlight.js 的代碼包含了對(duì)于各種語(yǔ)言的語(yǔ)法解析,和不同配色方案的設(shè)計(jì),對(duì)于對(duì)編程語(yǔ)言和語(yǔ)法高亮領(lǐng)域感興趣的開(kāi)發(fā)者是一座珍貴的寶庫(kù)。

          行代碼就能讓我的網(wǎng)站支持代碼高亮的工具庫(kù),也支持在 Vue 中使用,強(qiáng)烈推薦給大家。

          關(guān)于 highlight.js

          highlight.js 是一款使用 javascript 開(kāi)發(fā)代碼高亮工具庫(kù),能夠讓網(wǎng)頁(yè)上的代碼顯示接近我們使用的代碼編輯器的高亮樣式,從而看起來(lái)更舒服,增強(qiáng)閱讀體驗(yàn)。

          highlight.js 官網(wǎng)截圖

          highlight.js 的技術(shù)特性

          • 支持 197 種開(kāi)發(fā)語(yǔ)言和 246 種代碼高亮風(fēng)格主題
          • 自動(dòng)開(kāi)發(fā)語(yǔ)言檢測(cè)
          • 支持多種語(yǔ)言混合代碼同時(shí)高亮
          • 支持任何 HTML 標(biāo)簽,不僅僅是<code></code>
          • 支持 npm 安裝,可以在 Vue.js 中使用,也可以在 node.js 中使用
          • 無(wú)依賴(lài),與任何 js 框架兼容

          為什么要用 highlight.js

          常來(lái)我網(wǎng)站的小伙伴都知道,我的文章有一個(gè)欄目是“前端”,主要推薦一下實(shí)用的前端開(kāi)源項(xiàng)目或者組件庫(kù),寫(xiě)技術(shù)類(lèi)文章免不了要貼代碼,我的網(wǎng)站基于 wordpress 搭建,此前我一直為找一款代碼高亮插件煩惱,但大部分 wordpress 的代碼高亮插件實(shí)在太臃腫,出來(lái)的樣式又不美觀(guān)。大多時(shí)候是截圖 VsCode 的代碼界面,甚至還用過(guò) codepng 這個(gè)工具把代碼變成圖片貼在文章中,但這樣做是美觀(guān)了,但也存在2個(gè)問(wèn)題:

          • 長(zhǎng)代碼圖片會(huì)縮放,閱讀體驗(yàn)不佳
          • 搜索引擎不識(shí)別,對(duì) SEO 不友好

          最終還是找到了 highlight.js,完美解決了上面兩個(gè)問(wèn)題,而且配置簡(jiǎn)單,演示漂亮,定制化簡(jiǎn)單。不禁感嘆:用純前端的方式解決,才能精準(zhǔn)控制,實(shí)現(xiàn)想要的效果。

          使用教程:為我的網(wǎng)站添加代碼高亮功能

          下面以我的網(wǎng)站為例,展示將 highlight.js 用在我們的項(xiàng)目上的方法。首先 highlight.js 支持 cdn 直接引入和 npm 安裝,我的網(wǎng)站基于 wordpress 開(kāi)發(fā),主題是自己寫(xiě)的,最簡(jiǎn)單的方式就是在文章詳情頁(yè)引入 highlight.js 和主題樣式。

          雖然 highlight.js 支持幾百種開(kāi)發(fā)語(yǔ)言,但為了將文件體積控制到最小,我們可以點(diǎn)擊“get version”按鈕進(jìn)入下載頁(yè),通過(guò)勾選我們需要的開(kāi)發(fā)語(yǔ)言,來(lái)構(gòu)建最輕量的庫(kù)。

          下載解壓后得到的 highlight.min.js 就是我們需要引入的 js 文件,主題樣式都在 style 文件夾里,我選擇了一個(gè)比較喜歡的 monokai-sublime 主題,只需要一個(gè) css 文件,然后初始化:

          <link href="/js/monokai-sublime.min.css" rel="stylesheet" type="text/css">
          <script src="/js/highlight.min.js"></script>
          <script>
             hljs.highlightAll();
          </script>

          就是這么簡(jiǎn)單,highlight.js 會(huì)自動(dòng)將文章中的 <pre><code></code></pre> 代碼進(jìn)行識(shí)別語(yǔ)言并且高亮,一切就是這么簡(jiǎn)單。為了讓代碼顯示更協(xié)調(diào),我用幾行 css 控制了包裹層的圓角以及背景顏色、字體大小等,大功告成。

          .post-content .wp-block-code {
             background-color: #F6F8FF;
             border-radius: 16px;
             font-size: 16px;
             padding: 22px 22px 22px 38px;
             margin-top: 22px;
             margin-bottom: 22px;
          }
          .post-content .wp-block-code {
             line-height: 1.2;
             font-size: 15px;
             padding: 10px;
             overflow-x: auto;
          }
          .post-content .wp-block-code code {
             position: relative;
             background-color: unset !important;
          }

          當(dāng)然 highlight.js 也能在 vue 項(xiàng)目中使用,安裝:

          npm install highlight.js

          在 Vue 文件中使用 (通過(guò) highlight.js for Vue ) :

          <div id="app">
            <!-- bind to a data property named `code` -->
            <highlightjs autodetect :code="code" />
            <!-- or literal code works as well -->
            <highlightjs language='javascript' code="var x = 5;" />
          </div>

          需要注意的是,自動(dòng)識(shí)別模式不能100%識(shí)別出代碼所屬的開(kāi)發(fā)語(yǔ)言,識(shí)別錯(cuò)誤會(huì)導(dǎo)致高亮樣式是別的語(yǔ)言的,這種情況下可以手動(dòng)設(shè)置一個(gè) class 來(lái)精準(zhǔn)控制:

          <pre><code class="language-javascript">...</code></pre>

          官網(wǎng)提供了詳盡的使用文檔,有更多代碼高亮的控制,但不足的就是 highlight.js 沒(méi)有顯示行號(hào)的支持,需要通過(guò)再引入一個(gè)庫(kù) (highlightjs-line-numbers.js) 或者自行實(shí)現(xiàn)。

          免費(fèi)開(kāi)源說(shuō)明

          highlight.js 是一款基于 BSD 許可證開(kāi)源的 javascript 工具庫(kù),任何個(gè)人和公司都可以免費(fèi)下載用于自己的項(xiàng)目,包括商用項(xiàng)目。

          關(guān)注我,持續(xù)分享高質(zhì)量的免費(fèi)開(kāi)源、免費(fèi)商用的資源。

          ↓↓點(diǎn)擊查看本次分享的網(wǎng)址以及代碼高亮效果

          highlight.js - 讓網(wǎng)頁(yè)上的代碼高亮美化的免費(fèi)開(kāi)源工具庫(kù)|那些免費(fèi)的磚


          主站蜘蛛池模板: 日韩内射美女人妻一区二区三区| 亚洲一区二区视频在线观看| 无码精品人妻一区二区三区人妻斩| 一区二区三区国模大胆| 日韩精品一区二区三区不卡 | 精品人妻一区二区三区毛片| 亚洲日韩中文字幕一区| 福利片免费一区二区三区| 国产福利电影一区二区三区,亚洲国模精品一区 | 亚洲国产AV一区二区三区四区| 亚洲一区二区观看播放| 国产激情精品一区二区三区| 国产一区二区三区夜色 | 香蕉一区二区三区观| 精品少妇ay一区二区三区| 免费视频精品一区二区| 亚洲一区二区无码偷拍| 红桃AV一区二区三区在线无码AV| 美女视频一区三区网站在线观看| 国产亚洲福利精品一区二区 | 春暖花开亚洲性无区一区二区| 国产一区三区二区中文在线| 精品国产一区二区三区www| 精品国产亚洲一区二区三区| 在线观看国产一区二区三区| 日韩欧国产精品一区综合无码| 无码人妻精品一区二区蜜桃百度| 波多野结衣一区二区| 亚洲视频一区二区三区| 日韩精品在线一区二区| 在线观看国产一区| 久久AAAA片一区二区| 国产一区二区四区在线观看| 精品天海翼一区二区| 国产成人精品一区二区三在线观看| 日韩毛片基地一区二区三区| 免费无码毛片一区二区APP| 日韩好片一区二区在线看| 88国产精品视频一区二区三区| 熟女精品视频一区二区三区| 亚洲av不卡一区二区三区|