整合營銷服務商

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

          免費咨詢熱線:

          實現canvas繪制文本折行

          家在用canvas繪制文本時,經常會碰到怎么解決文本折行的問題。今天,老K為大家分享一種實現方法。


          實現的基本思路:

          先將輸入的每個字拆分成單個元素,再將這些元素插入到一個隱藏的元素中,該元素寬度和目標canvas的寬度相等,接下來只需要遍歷插入容器中的子元素,然后根據子元素相對插入容器的相對距離繪制文字到canvas里。

          <!DOCTYPE html>
           <head>
           <meta charset="utf-8">
           <title>canvas-text-wrap</title>
           <style type="text/css">
           * {
           margin: 0
           }
           #main {
           width: 400px;
           margin: 20px auto 0;
           }
           #canvas, #editableWarp, #editable, #hideText {
           width: 400px;
           height: 125px;
           padding: 0;
           border: 0;
           background: #333;
           color: #FFF;
           font-size: 14px;
           font-family: 'sans-serif';
           position: relative;
           z-index: 1
           }
           #hideText {
           z-index: 0;
           position: absolute;
            word-break: break-word;
           word-wrap: break-word;
           }
           p {
           line-height: 32px;
           }
          </style>
           </head>
           <body>
           <div id="main">
           <p>
           輸入:
           </p>
           <div id="editableWarp">
           <div id="hideText"></div>
           <textarea id="editable" placeholder="請輸入文字..."></textarea>
           </div>
           <p>
           canvas輸出:
           </p>
           </div>
           <script type="text/javascript">
           function addEvent(obj,type,handle){//封裝綁定事件方法
           try{ // Chrome、FireFox、Opera、Safari、IE9.0及其以上版本
           obj.addEventListener(type,handle,false);
           }catch(e){
           try{ // IE8.0及其以下版本
           obj.attachEvent('on' + type,handle);
           }catch(e){ // 早期瀏覽器
           obj['on' + type] = handle;
           }
           }
           };
           function getStyle(node, styleType){//獲取標簽樣式方法
           return node.currentStyle? node.currentStyle[styleType]: getComputedStyle(node)[styleType];//瀏覽器中有node.currentStyle方法就用,沒有就用另一個
           };
          
           var $editable = document.getElementById('editable'),
           $hideText = document.getElementById('hideText'),
           $main = document.getElementById('main'),
           editable_pos = $editable.getBoundingClientRect();
           function initCanvasDom(){//創建canvas標簽
           var $canvas = document.createElement('canvas');
           $canvas.innerHTML = '您的瀏覽器不支持canvas'; 
           $canvas.width = '400';
           $canvas.height = '125';
           $canvas.id = 'canvas';
           $main.appendChild($canvas);
           return $canvas;
           }
           var $canvas = initCanvasDom();
           var ctx = $canvas.getContext('2d');
           addEvent($editable,'blur',function(){//綁定方法
           var txt = $editable.value,
           html = converText(txt);
           $hideText.innerHTML = '';
           $hideText.innerHTML = html;
           drawText();
           });
           function converText(txt) {
           var html = txt.replace(/(\S)/ig, '<span>$1</span>');
           html = html.replace(/\n|\r/ig,'<br>');
           html = html.replace(/\s/ig,' ');
           return html;
           }
           function drawText() {
           $main.removeChild($canvas);//刪除舊的canvas標簽
           $canvas = initCanvasDom();//創建新的canvas標簽
           ctx = $canvas.getContext('2d');
           var canvas_width = getStyle($canvas,'width'),
           canvas_height = getStyle($canvas,'height');
           ctx.clearRect(0,0,canvas_width,canvas_height);
           var fontSize = getStyle($hideText,'fontSize');
           ctx.font = fontSize + ' sans-serif';
           ctx.textAlign = 'center';
           ctx.textBaseline = 'top';
           ctx.fillStyle = '#FFFFFF';
           var text_span_list = $hideText.getElementsByTagName('span'),
           i = 0,text_span_list_length = text_span_list.length,pos = null, tex='',item_left=0,item_top=0;
           for(;i<text_span_list_length;i++){
           pos = text_span_list[i].getBoundingClientRect();
           txt = text_span_list[i].innerHTML;
           item_left = parseInt(pos.left-editable_pos.left);
           item_top = parseInt(pos.top-editable_pos.top);
           ctx.fillText(txt,item_left,item_top);
           }
           }
          </script>
           </body>
          </html>

          這樣基本實現了這個功能。大家可以參考一下代碼,自己親自試一下。為了實現canvas里的文字時時更新,需要動態創建canvas標簽,并且每次執行drawText方法時要刪掉上一次創建的canvas標簽,重新創建一個新的。


          本文為原創內容,若轉載請注明出處,轉發感激不盡。

          響應式系統設計的時候遇到需要對標題進行多行文字截取的效果,如下圖:


          看似十分簡單的標題截斷效果,但是竟然沒有一個統一 CSS 屬性實現標準,需要用到一些奇淫妙計來實現,一般來說,在做這樣文字截斷效果時我們更多是希望:

          • 兼容性好,對各大主流瀏覽器有好的支持
          • 響應式截斷,根據不同寬度做出調整
          • 文本超出范圍才顯示省略號,否則不顯示省略號
          • 省略號位置顯示剛好

          基于上述的準則,下面我就講介紹各種技巧實現截斷效果,并根據上述的評判標準得出最優解(代碼我都傳到 jsfiddle 平臺,可點擊 demo 地址查看)。

          單行文本截斷 text-overflow

          文本溢出我們經常用到的應該就是 text-overflow:ellipsis 了,相信大家也很熟悉,只需輕松幾行代碼就可以實現單行文本截斷。

          div {
           white-space: nowrap;
           overflow: hidden;
           text-overflow: ellipsis;
          }
          

          實現效果:



          屬性瀏覽器原生支持,各大瀏覽器兼容性好,缺點就是只支持單行文本截斷,并不支持多行文本截取。

          適用場景:單行文字截斷最簡單實現,效果最好,放心使用。

          如果是多行文字截取效果,實現起來就沒有那么輕松。

          -webkit-line-clamp 實現

          先介紹第一種方式,就是通過 -webkit-line-clamp 屬性實現。具體的方式如下:

          div {
           display: -webkit-box;
           overflow: hidden;
           -webkit-line-clamp: 2;
           -webkit-box-orient: vertical;
          }
          

          它需要和 display、 -webkit-box-orient 和 overflow 結合使用:

          • display:-webkit-box; 必須結合的屬性,將對象作為彈性伸縮盒子模型顯示。
          • -webkit-box-orient; 必須結合的屬性,設置或檢索伸縮盒對象的子元素的排列方式。
          • text-overflow:ellipsis; 可選屬性,可以用來多行文本的情況下,用省略號“…”隱藏超出范圍的文本。

          實現效果:



          從效果上來看,它的優點有:

          1. 響應式截斷,根據不同寬度做出調整。
          2. 文本超出范圍才顯示省略號,否則不顯示省略號。
          3. 瀏覽器原生實現,所以省略號位置顯示剛好。

          但是缺點也是很直接,因為 -webkit-line-clamp 是一個不規范的屬性,它沒有出現在 CSS 規范草案中。也就是說只有 webkit 內核的瀏覽器才支持這個屬性,像 Firefox, IE 瀏覽器統統都不支持這個屬性,瀏覽器兼容性不好。

          使用場景:多用于移動端頁面,因為移動設備瀏覽器更多是基于 webkit 內核,除了兼容性不好,實現截斷的效果不錯。

          定位元素實現多行文本截斷

          另外還有一種靠譜簡單的做法就是設置相對定位的容器高度,用包含省略號(…)的元素模擬實現,實現方式如下:

          p {
           position: relative;
           line-height: 18px;
           height: 36px;
           overflow: hidden;
          }
          p::after {
           content:"...";
           font-weight:bold;
           position:absolute;
           bottom:0;
           right:0;
           padding:0 20px 1px 45px;
           /* 為了展示效果更好 */
           background: -webkit-gradient(linear, left top, right top, from(rgba(255, 255, 255, 0)), to(white), color-stop(50%, white));
           background: -moz-linear-gradient(to right, rgba(255, 255, 255, 0), white 50%,white);
           background: -o-linear-gradient(to right, rgba(255, 255, 255, 0), white 50%,white);
           background: -ms-linear-gradient(to right, rgba(255, 255, 255, 0), white 50%,white);
           background: linear-gradient(to right, rgba(255, 255, 255, 0), white 50%, white);
          }
          

          實現原理很好理解,就是通過偽元素絕對定位到行尾并遮住文字,再通過 overflow:hidden隱藏多余文字。

          實現效果:



          從實現效果來看,它所具備的優點:

          1. 兼容性好,對各大主流瀏覽器有好的支持
          2. 響應式截斷,根據不同寬度做出調整

          但是它無法識別文字的長短,即文本超出范圍才顯示省略號,否則不顯示省略號。還有因為是我們人為地在文字末尾添加一個省略號效果,就會導致它跟文字其實沒有貼合的很緊密,遇到這種情況可以通過添加 word-break:break-all; 使一個單詞能夠在換行時進行拆分。



          適合場景:文字內容較多,確定文字內容一定會超過容器的,那么選擇這種方式不錯。

          float 特性實現多行文本截斷

          回到一開始我要做的內容是多行標題文字截取效果,顯然是無法控制標題的長度的,顯然是無法使用上述的方式。回到事情的本質來看:我們希望 CSS 能夠有一種屬性,能夠在文字溢出的情況下顯示省略號,不溢出時不顯示省略號(兩種形式,兩種效果)。

          正當我以為 CSS 已經無能為力,只能通過 JS 去實現的時候,后來看到了一個方法非常巧妙,而且能夠滿足上述提到的所有準則,下面我就介紹如何通過 float 特性實現多行文本截斷效果。

          基本原理:



          有個三個盒子 div,粉色盒子左浮動,淺藍色盒子和黃色盒子右浮動:

          1. 當淺藍色盒子的高度低于粉色盒子,黃色盒子仍會處于淺藍色盒子右下方。
          2. 如果淺藍色盒子文本過多,高度超過了粉色盒子,則黃色盒子不會停留在右下方,而是掉到了粉色盒子下。

          好了,這樣兩種狀態的兩種展示形式已經區分開了,那么我們可以將黃色盒子進行相對定位,將內容溢出的黃色盒子移動到文本內容右下角,而未溢出的則會被移到外太空去了,只要我們使用 overflow:hidden就可以隱藏掉。


          基本原理就是這樣,我們可以將淺藍色區域想象成標題,黃色區域想象為省略號效果。那么你可能會覺得粉色盒子占了空間,那豈不是標題會整體延后了嗎,這里可以通過 margin 的負值來出來,設置淺藍色盒子的 margin-left 的負值與粉色盒子的寬度相同,標題也能正常顯示。

          那么我們將前面的 DOM 結構簡化下,變成下面這樣:

          <div class="wrap">
           
           <div class="text">Lorem ipsum dolor sit amet, consectetur adipisicing elit.Dignissimos labore sit vel itaque delectus atque quos magnam assumenda quod architecto perspiciatis animi.</div>
          </div>
          

          剛才的粉色盒子和黃色盒子都可以用偽元素來代替。

          .wrap {
           height: 40px;
           line-height: 20px;
           overflow: hidden;
          }
          .wrap .text {
           float: right;
           margin-left: -5px;
           width: 100%;
           word-break: break-all;
          }
          .wrap::before {
           float: left;
           width: 5px;
           content: '';
           height: 40px;
          }
          .wrap::after {
           float: right;
           content: "...";
           height: 20px;
           line-height: 20px;
           /* 為三個省略號的寬度 */
           width: 3em;
           /* 使盒子不占位置 */
           margin-left: -3em;
           /* 移動省略號位置 */
           position: relative;
           left: 100%;
           top: -20px;
           padding-right: 5px;
          }
          

          實現效果:



          這里我目前看到最巧妙的方式了。只需要支持 CSS 2.1 的特性就可以了,它的優點有:

          1. 兼容性好,對各大主流瀏覽器有好的支持。
          2. 響應式截斷,根據不同寬度做出調整。
          3. 文本超出范圍才顯示省略號,否則不顯示省略號。

          至于缺點,因為我們是模擬省略號,所以顯示位置有時候沒辦法剛剛好,所以可以考慮:

          1. 加一個漸變效果,貼合文字,就像上述 demo 效果一樣。
          2. 添加 word-break:break-all; 使一個單詞能夠在換行時進行拆分,這樣文字和省略號貼合效果更佳。

          這個方法應該是我看到最好的用純 CSS 處理的方式了,如果你有更好的方法,歡迎留言交流!

          者:semlinker

          轉發鏈接:https://mp.weixin.qq.com/s/p0U8sVLtWd78CLc8kM22FQ


          主站蜘蛛池模板: 无码日韩精品一区二区免费暖暖 | 波多野结衣久久一区二区| 国产伦精品一区二区三区精品| 国产麻豆剧果冻传媒一区| 国产一区二区在线视频播放| 一区二区在线视频免费观看| 精品国产一区二区三区2021| 一区二区在线视频| 国产一区二区三区在线观看影院| 一区二区三区四区无限乱码| 久久国产精品最新一区| 久久精品无码一区二区三区不卡| 亚洲日本一区二区一本一道| 亚洲爆乳精品无码一区二区三区 | 亚洲欧美国产国产综合一区| 国产精品一区二区毛卡片| 无码日韩人妻AV一区免费l| 久久精品视频一区| 日韩免费无码一区二区视频| 久久精品中文字幕一区| 精品深夜AV无码一区二区老年| 精品国产一区二区22| 女同一区二区在线观看| 国产一区二区在线视频| 精品一区二区三区中文| 在线精品亚洲一区二区| 久久亚洲国产精品一区二区| 波多野结衣电影区一区二区三区| 久久se精品一区二区国产| 亚洲日本中文字幕一区二区三区| 无码国产精品久久一区免费| 中文字幕色AV一区二区三区| 极品少妇伦理一区二区| 亚洲Av永久无码精品一区二区| 亚洲一区二区在线视频| 精品国产亚洲一区二区在线观看| 免费观看日本污污ww网站一区| 中文字幕一区在线观看视频| 日产精品久久久一区二区| 中文字幕人妻无码一区二区三区| 一区二区在线视频观看|