本文爲做者行舟客投稿,點擊閱讀原文可到達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
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標籤是沒有辦法嵌套在行內元素中的:它會帶着其內包裹的文字消失不見 !這一點必定注意。
好了,你總不能讓用戶一直處於這個狀態吧。那就要在必定狀況下取消上面的狀態 —— 這裏筆者也遇到了一些「奇葩」問題:
何時結束選中狀態?我建議,在點擊頁面其他空白地方時改變狀態 —— 由於爲了更好的體驗,上面選中使用的mouseup:這裏涉及到一個「瀏覽器事件觸發的優先級」。你可讓文本處於「高zIndex區域」、或者用JS去隔離。
展轉了一上午,想到了一個「取巧的方法」:由於選中的文本已是一個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!