整合營銷服務商

          電腦端+手機端+微信端=數據同步管理

          免費咨詢熱線:

          HTML高亮關鍵字的完美解決方案

          HTML高亮關鍵字的完美解決方案

          近項目做暈頭,一個接一個,其中遇到這樣的一個功能,在網頁中高亮關鍵字的實現方法,下面小編把實現代碼及解決方案分享給大家,感興趣的的朋友跟隨小編一起看看吧

          最近做項目遇到這樣的一個功能:在網頁中高亮關鍵字。

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

          常用做法:正則替換

          思路:要想高亮元素,那么需要將關鍵字提取出來用標簽包裹,然后對標簽進行樣式調整。使用 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>
          

          關鍵字父節點 element 通過 class 來進行背景染色處理,對原始DOM有一定程度污染,可能對 element 再次定位造成影響。(作為插件希望盡可能少改變原始DOM)

          正則優化一:僅處理位于標簽內的元素

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

          以能解決大多數問題,但依舊存在的問題是,只要標簽屬性存在類似 < 符號,將會打破匹配規則導致正則提取內容錯誤, HTML5 dataset 可以自定義任意內容,故這些特殊字符是無法避免的。

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

          正則優化二:清除可能影響的標簽

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

          最重要的,當標簽值中包含 <> 符號時,此方法也不能正確的提取標簽

          總之在經過了N多嘗試之后,通過正則都沒能有效的處理各種情況。然后換了個思路,不通過字符串的方式,通過節點處理。element.childNodes 可以最有效的清理標簽內的干擾信息。

          [完美解決方案]通過 DOM 節點處理

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

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

          但是 keyword 1 是屬于文本節點,只能修改文本內容,無法增加 HTML,更無法單獨控制其樣式。而文本節點也不能轉換為普通節點,這也是最苦惱的事情。

          最后~,本文的重點來了,因為這個功能,讓我第一次認真接觸到了文本節點這個東西。從這里發現了Text,使用切割文本節點并替換的方式實現高亮。

          源碼以及還原高亮見源碼

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

          總結

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

          學習從來不是一個人的事情,要有個相互監督的伙伴,想要學習或交流前端問題的小伙伴可以私信“學習”小明加群獲取2019web前端最新入門資料,一起學習,一起成長!

          行代碼就能讓我的網站支持代碼高亮的工具庫,也支持在 Vue 中使用,強烈推薦給大家。

          關于 highlight.js

          highlight.js 是一款使用 javascript 開發代碼高亮工具庫,能夠讓網頁上的代碼顯示接近我們使用的代碼編輯器的高亮樣式,從而看起來更舒服,增強閱讀體驗。

          highlight.js 官網截圖

          highlight.js 的技術特性

          • 支持 197 種開發語言和 246 種代碼高亮風格主題
          • 自動開發語言檢測
          • 支持多種語言混合代碼同時高亮
          • 支持任何 HTML 標簽,不僅僅是<code></code>
          • 支持 npm 安裝,可以在 Vue.js 中使用,也可以在 node.js 中使用
          • 無依賴,與任何 js 框架兼容

          為什么要用 highlight.js

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

          • 長代碼圖片會縮放,閱讀體驗不佳
          • 搜索引擎不識別,對 SEO 不友好

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

          使用教程:為我的網站添加代碼高亮功能

          下面以我的網站為例,展示將 highlight.js 用在我們的項目上的方法。首先 highlight.js 支持 cdn 直接引入和 npm 安裝,我的網站基于 wordpress 開發,主題是自己寫的,最簡單的方式就是在文章詳情頁引入 highlight.js 和主題樣式。

          雖然 highlight.js 支持幾百種開發語言,但為了將文件體積控制到最小,我們可以點擊“get version”按鈕進入下載頁,通過勾選我們需要的開發語言,來構建最輕量的庫。

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

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

          就是這么簡單,highlight.js 會自動將文章中的 <pre><code></code></pre> 代碼進行識別語言并且高亮,一切就是這么簡單。為了讓代碼顯示更協調,我用幾行 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;
          }

          當然 highlight.js 也能在 vue 項目中使用,安裝:

          npm install highlight.js

          在 Vue 文件中使用 (通過 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>

          需要注意的是,自動識別模式不能100%識別出代碼所屬的開發語言,識別錯誤會導致高亮樣式是別的語言的,這種情況下可以手動設置一個 class 來精準控制:

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

          官網提供了詳盡的使用文檔,有更多代碼高亮的控制,但不足的就是 highlight.js 沒有顯示行號的支持,需要通過再引入一個庫 (highlightjs-line-numbers.js) 或者自行實現。

          免費開源說明

          highlight.js 是一款基于 BSD 許可證開源的 javascript 工具庫,任何個人和公司都可以免費下載用于自己的項目,包括商用項目。

          關注我,持續分享高質量的免費開源、免費商用的資源。

          ↓↓點擊查看本次分享的網址以及代碼高亮效果

          highlight.js - 讓網頁上的代碼高亮美化的免費開源工具庫|那些免費的磚

          些在線圖文編輯器不支持直接插入代碼塊,但可以直接粘貼 HTML 格式的高亮代碼塊。

          花了一點時間研究了一下各家的編輯器,規則卻各不相同。有的要求代碼塊被包含于 <code> ... </code> 或者 <pre> <code> ... </code> </pre> , 有些要求 class 屬性里包含 "code" 關鍵詞,或者要求代碼塊里必須包含至少一個 <br> 。如果不符合這些要求,不是變成普通文本,就是丟失換行縮進,或者丟失顏色樣式。

          所以,這就難了。先得找個支持代碼高亮的編輯器,仔細地選擇并復制代碼塊,復制完還得編輯剪貼板里的 HTML 。這就不如干脆寫個轉換工具了。

          因為瀏覽器操作系統剪貼板可能不太方便,下面用 aardio 寫一個工具軟件。

          先看軟件成品演示:

          軟件用法:

          1、輸入編程語言名稱(支持自動完成)。

          2、然后在輸入框中粘貼要轉換的編程代碼。

          3、點擊「復制高亮代碼塊」按鈕。

          然后我們就可以打開在線圖文編輯器直接粘貼生成的高亮代碼塊了。

          下面是這個軟件的 aardio 源代碼:

          import win.ui;
          /*DSG{{*/
          var winform=win.form(text="HTML 代碼塊生成工具 - 本工具使用 aardio 語言編寫";right=1055;bottom=674;bgcolor=16777215)
          winform.add(
          button={cls="button";text="復制高亮代碼塊";left=633;top=609;right=1000;bottom=665;bgcolor=16777215;color=14120960;db=1;dr=1;font=LOGFONT(h=-14);note="可在網頁編輯器直接粘貼";z=4};
          cmbLangs={cls="combobox";left=262;top=625;right=446;bottom=651;db=1;dl=1;edge=1;items={"javascript"};mode="dropdown";z=2};
          editCode={cls="edit";left=1;top=4;right=1052;bottom=599;db=1;dl=1;dr=1;dt=1;edge=1;hscroll=1;multiline=1;vscroll=1;z=5};
          static={cls="static";text="請選擇語言:";left=70;top=629;right=248;bottom=649;align="right";db=1;dl=1;transparent=1;z=3};
          webCtrl={cls="custom";text="自定義控件";left=8;top=10;right=1048;bottom=604;db=1;dl=1;dr=1;dt=1;hide=1;z=1}
          )
          /*}}*/
          
          import web.view;
          var wb=web.view(winform.webCtrl);
          
          import win.clip.html;
          wb.export({ 
              onHighlight=function(html,background,foreground){
                  html=`<pre class="code" style="overflow-x:auto;text-align:left;box-shadow: rgba(216, 216, 216, 0.5) 0px 0px 0px 1px inset;padding:10px;border-radius:3px;background-color:`+background+`;color:`+foreground+`;white-space:pre;word-break:break-all;display:block;font-size:14px;font-style:normal;font-variant-ligatures:normal;font-variant-caps: normal;font-family: "Consolas", Consolas, "Liberation Mono", Menlo, Courier, monospace"><code>`
                      + html + `</code></pre>`;
          
                  html,count=string.replace(html,'\n',"<br>");
                  if(!count){
                      html=string.replace(html,`\</code\>\</pre\>$`,`<br></code></pre>`);
                  }
                  var cb=win.clip.html();
                  cb.write(html); 
          
                  winform.setTimeout( 
                      function(){
                          winform.editCode.show(true);
                          winform.webCtrl.show(false);
                          winform.text="HTML 代碼塊生成工具 - 已復制高亮代碼塊到剪貼板,可在網頁直接粘貼";
                      },1000); 
              };
              setLanguages=function(langs){
                  winform.languages=langs;
              }  
          })
          
          
          winform.cmbLangs.onEditChange=function(){ 
          
              var text=string.lower(winform.cmbLangs.text);
              var items=table.filter( winform.languages : {}, lambda(v) string.startWith(v,text) ); 
              winform.cmbLangs.autoComplete(items);  
          }
          winform.cmbLangs.editBox.disableInputMethod();
          
          import web.prism;
          import wsock.tcp.asynHttpServer;
          var httpServer=wsock.tcp.asynHttpServer(); 
          httpServer.run(web.prism,{
              ["/index.html"]=/*****
          <!DOCTYPE html>
          <html>
            <head>
              <meta charset="UTF-8" /> 
              <link href="prism.css" rel="stylesheet" />
            </head>
            <body>
              <pre id="code-pre"><code id="code" class="lang-javascript"></code></pre>
              <script src="prism.js"></script>
              <script>
             function computedColorStyle(element, options={}) {
          
                  Array.prototype.forEach.call(element.children,child=> {
                      computedColorStyle(child, options);
                  });
          
                  const computedStyle=getComputedStyle(element);
                  element.style["color"]=computedStyle.getPropertyValue("color");  
              }
          
              highlight=function(code,language){
                  var html=Prism.highlight(code, Prism.languages[language], language);
          
                  var codeEle=document.getElementById("code");
                  codeEle.innerHTML=html;
                  computedColorStyle(codeEle);
          
                  const computedStyle=getComputedStyle(codeEle);  
                  onHighlight(codeEle.innerHTML
                      ,getComputedStyle(document.getElementById("code-pre")).getPropertyValue("background-color")
                      ,computedStyle.getPropertyValue("color"));
              }
          
              setLanguages( Object.keys(Prism.languages) );
              </script>
            </body> 
          </html> 
              *****/
          });
          
          wb.go( httpServer.getUrl("/index.html"));
          
          winform.button.oncommand=function(id,event){
              winform.text="HTML 代碼塊生成工具 - 本工具使用 aardio 語言編寫"
              winform.editCode.show(false);
              winform.webCtrl.show(true);
          
              wb.xcall("highlight",winform.editCode.text,winform.cmbLangs.text);
          }
          
          
          winform.show();
          win.loopMessage();

          打開 aardio 創建工程,然后復制粘貼上面的代碼到 main.aardio 里面就可以直接運行,或生成獨立 EXE 文件:

          這個軟件的原理:

          1、首先通過 WebView2 調用 Prism.js 高亮代碼。為了可以內存加載 Prism.js ( 支持生成獨立 EXE ),我寫了一個 aardio 擴展庫 web.prism 。關于 WebView2 請參考:放棄 Electron,擁抱 WebView2!JavaScript 快速開發獨立 EXE 程序

          2、因為 Prism.js 生成的 HTML 代碼塊都是使用 class 屬性指定樣式,所以我們需要調用 getComputedStyle 獲取最終渲染的字體顏色屬性。

          3、最后在 JavaScript 里調用 aardio 函數處理生成的 HTML 代碼塊,aardio 的任務是將 HTML 修改為更合適直接粘貼的格式,并盡可能地處理各圖文編輯器的兼容問題。然后調用 win.clip.html 將處理好的 HTML 復制到系統剪貼板:

          import win.clip.html;
          
          var cb=win.clip.html();
          cb.write(html); 

          然后只要愉快地粘貼代碼塊就可以。

          如果是 aardio 代碼不需要用這個工具,在 aardio 編輯器里右鍵直接點『 復制全部到 HTML 代碼塊 』就可以了:


          主站蜘蛛池模板: 在线|一区二区三区| 在线观看视频一区二区| 亚洲av无码不卡一区二区三区| 果冻传媒一区二区天美传媒| 国产一区二区在线观看app| 中文字幕日韩人妻不卡一区| 国产一区二区三区久久精品| 精品人伦一区二区三区潘金莲| 久久久久人妻一区精品性色av| 久久久久久人妻一区二区三区| 福利在线一区二区| 久久精品国产一区| 日本一区二三区好的精华液| 一区五十路在线中出| 天堂资源中文最新版在线一区| 久久精品成人一区二区三区| 亚洲成av人片一区二区三区 | 精品一区中文字幕| 中文字幕日韩一区二区三区不| 久久无码人妻一区二区三区午夜 | 亚欧色一区W666天堂| 成人一区二区三区视频在线观看| 一区二区国产在线播放| 久久久无码一区二区三区| 无码一区二区三区AV免费| 中文字幕在线播放一区| 亚洲综合色一区二区三区| 中文字幕久久亚洲一区| 亚洲色一区二区三区四区| 中文字幕AV一区中文字幕天堂| 伊人久久精品无码麻豆一区| 三上悠亚一区二区观看| 黑巨人与欧美精品一区| 夜夜添无码试看一区二区三区| 亚洲性色精品一区二区在线| 亚洲色精品aⅴ一区区三区| 亚洲乱码国产一区网址| 一区高清大胆人体| 中文字幕精品亚洲无线码一区应用| 2020天堂中文字幕一区在线观| 亚洲一区二区影院|