探索在網頁中使用「標註」

本文爲做者行舟客投稿,點擊閱讀原文可到達github地址~
github地址:https://github.com/1314mxc/yunUI ,歡迎star!css

提及「標註」,在HTML5以前,你可能想起的是各類瀏覽器插件,emmmmmmm或者說你根本不認爲瀏覽器上能夠有這種玩意。前端

可是HTML5來了,這是它的時代。node

咱們徹底能夠不借助CSS、JavaScript的力量實現這個東西 —— 由於瀏覽器實現了 <ruby></ruby> 這個神奇的標籤:ios

<ruby>
 <rb>中文</rb>
 <rp>(</rp><rt>zhongwen</rt><rp>)</rp>
</ruby>

它是這樣表現的:探索在網頁中使用「標註」
聽說在不支持ruby的瀏覽器中也能這樣適應:
探索在網頁中使用「標註」git

除此以外,隨着前端的發展,CSS3也給咱們帶來了「驚喜」 —— 文字強調裝飾 text-emphasistext-emphasis家族總共有4個CSS屬性,分別是:github

  1. text-emphasis
  2. text-emphasis-color
  3. text-emphasis-style
  4. text-emphasis-position
    其中,text-emphasis是text-emphasis-color和text-emphasis-style這兩個CSS屬性的縮寫,注意,並不包含text-emphasis-position屬性,text-emphasis-position屬性是獨立的!text-emphasis-position屬性用來指定強調裝飾符的位置,默認位置是在正文的上方,咱們能夠指定強調裝飾符在正文的下方,也能夠指定垂直排版的時候強調裝飾符是左側仍是右側。語法以下:
text-emphasis-position: [ over | under ] && [ right | left ]

使用示意:web

text-emphasis-position: over left;
text-emphasis-position: under right;
text-emphasis-position: under left;

text-emphasis-position: left over;
text-emphasis-position: right under;
text-emphasis-position: left under;
// text-emphasis-position的初始值是over right。right定位出如今文
字垂直排版的時候,例如設置writing-mode:vertical-rl,此時就能夠看到強調裝飾符在右側了

好比:小程序

<p id="p">aishfaoihfoiahfoahdfoiahfdoshoigsoidshioshghudsihfisjhiodshoishoighdihishoighsoiv</p>

//css
color: red;
-webkit-text-emphasis-style: '·';
text-emphasis-style: '·';
-webkit-text-emphasis-color: red;
text-emphasis-color:red;
-webkit-text-emphasis-position:under;
text-emphasis-position: under;

它是這樣表現的:
探索在網頁中使用「標註」微信小程序

稍稍有些小遺憾的是:它不能「針對每一個字體設置不一樣的重點標誌」,因此經常只用來作輔助突出功能數組

筆者一直認同的是:能用HTML完成的就不用CSS,能用CSS的就不用JS。並在平常實踐中愈發以爲這是一條「至理」!」
那麼問題來了,如今我想實現這樣一個功能:如今的「網頁翻譯」大可能是「頁面總體翻譯」或者「彈框拖入」,少部分是「選中文字後在文字旁彈出一個提示框」,可是這幾種方式不論是哪種都會有一絲絲的影響:好比遮擋頁面其他內容、精確度不高等等。那能不能「當用戶選中文字後在選中文本下方有突出強調、在文本上方出現翻譯」呢?

(這個筆者在本文先不說,以避免形成「長篇大論」,本文只把實現的基礎知識全盤托出!)

首先是HTML:這裏咱們簡單的作一個p標籤:

<p id="p">aishfaoihfoiahfoahdfoiahfdoshoigsoidshioshghudsihfisjhiodshoishoighdihishoighsoiv</p>

筆者的思路是:當用戶鼠標「擡起」時,去判斷有沒有選中文本,若是沒有則啥事沒有、反之則要將這一部分選中的文本替換成標籤!

p.onmouseup=function(e){
    var txt = window.getSelection();
 console.log(txt)
 var selectStr = txt.toString();
 console.log(selectStr)
 if(selectStr!==''){
  replaceSelectedStrByEle(txt,selectStr,'nite-writer-pen')
 }
}

這裏 window.getSelection() 是瀏覽器API,專門用於獲取用戶選中的文本,其具體值用 .toString() 便可得到。

/**
  * 用元素替換被選中的文本
  */
var replaceSelectedStrByEle = function(selecter,selectStr,className){
  if (selectStr.trim != "") {
    var rang = selecter.getRangeAt(0);
 var ele = document.createElement("span");
 ele.style.cssText="-webkit-text-emphasis-style: '·';text-emphasis-style: '·';text-emphasis-color:red;-webkit-text-emphasis-position:under;text-emphasis-position:under";
    ele.className = className;
    ele.textContent = selectStr;
    rang.surroundContents(ele);
  }
}

selecter.getRangeAt(0):selection API是將每次選中的都保存到內部的數組裏,並且是最新的保存到第一個這樣的順序。沒錯這裏就是用的 -webkit-text-emphasis 突出強調符 —— 若是要爲某個元素一次添加多個樣式,cssText能夠優化性能!

受筆者「信奉」準則的影響,其實在這裏一開始還想用純CSS的 僞類::selection 去作突出強調,可是很不幸的是:這個僞類裏面只能改變選中文字的顏色相關:如背景顏色、字體自己顏色。其餘的什麼都改變不了(不知道爲啥,感受很奇怪:雖然說它是子選擇器行爲,可是其影響應該是和display之流是同樣的,並不會產生太大的變更)。諸君請看:
探索在網頁中使用「標註」
探索在網頁中使用「標註」
selection
(如上圖)至此,選中狀態已經差很少了 —— 至於沒說的翻譯,這裏若是你沒有足夠的能力建一個「詞庫」,那麼我仍是建議你啓用「第三方庫/插件」或者在線翻譯API。這裏還有一個問題是:在筆者實踐過程當中發現,ruby標籤是沒有辦法嵌套在行內元素中的:它會帶着其內包裹的文字消失不見 !這一點必定注意。

好了,你總不能讓用戶一直處於這個狀態吧。那就要在必定狀況下取消上面的狀態 —— 這裏筆者也遇到了一些「奇葩」問題:

  1. 何時結束選中狀態?我建議,在點擊頁面其他空白地方時改變狀態 —— 由於爲了更好的體驗,上面選中使用的mouseup:這裏涉及到一個「瀏覽器事件觸發的優先級」。你可讓文本處於「高zIndex區域」、或者用JS去隔離。

  2. 怎麼取消?對這個纔是大問題:你這裏可能「理所應當的」想到了「把元素的標籤去掉不就完了」,這裏你能夠嘗試一下,可不是一件簡單的事。一開始筆者想到了 將dom再轉化回string,可是隨即想到了這個string怎麼插入到父p標籤中,並且要插入到原位置!

展轉了一上午,想到了一個「取巧的方法」:由於選中的文本已是一個dom了,將選中的文本都轉化爲string,而後再用字符串替換替換掉父p標籤的innerText內容的相同之處!~

/**
 * 將dom轉化爲文本
*/
function nodeToString ( node ) {  
 //createElement()返回一個Element對象
 var tmpNode = document.createElement( "div" ); 
 //appendChild()  參數Node對象   返回Node對象  Element方法
 //cloneNode()  參數布爾類型  返回Node對象   Element方法
 tmpNode.appendChild( node.cloneNode( true ) );  
 var str = tmpNode.innerHTML;  
 tmpNode = node = null;
 return str;  
}
mxc.onclick=function(){
 if(document.querySelector('p .nite-writer-pen')){
  let p=document.querySelector('p .nite-writer-pen').parentNode
  let nite=document.querySelector('p .nite-writer-pen')
  console.log(nite)
  console.log(p)
  p.innerText=(p.innerHTML).replace(nodeToString(nite),nite.innerText)
 }
}

探索在網頁中使用「標註」
display
筆者開源了微信小程序日期組件擴展:可自定義精確到分、秒;可自定義位置、顏色、是否用默認樣式。地址:https://github.com/1314mxc/yunUI 歡迎star!

最後

  • 歡迎加我微信(winty230),拉你進技術羣,長期交流學習...
  • 歡迎關注「前端Q」,認真學前端,作個專業的技術人...
    探索在網頁中使用「標註」
相關文章
相關標籤/搜索