您好,登錄后才能下訂單哦!
這篇文章主要介紹了如何通過封裝一個v-clamp的指令處理多行文本溢出,具有一定借鑒價值,感興趣的朋友可以參考下,希望大家閱讀完這篇文章之后大有收獲,下面讓小編帶著大家一起了解一下。
最近做項目時,遇到了一個需求:要求div里文本在兩行顯示,div的寬度是固定的,如果溢出的話就顯示省略號。單行文本的溢出問題,我們都很熟悉,只要添加以下css屬性就ok:
overflow: hidden; white-space: nowrap; //段落中文本不換行 text-overflow: ellipsis;
查了資料之后發現還是有辦法的
在WebKit瀏覽器或移動端(絕大部分是WebKit內核的瀏覽器)的頁面實現比較簡單,可以直接使用WebKit的CSS擴展屬性(WebKit是私有屬性)-webkit-line-clamp ;注意:這是一個 不規范的屬性(unsupported WebKit property),它沒有出現在 CSS 規范草案中。-webkit-line-clamp用來限制在一個塊元素顯示的文本的行數。 為了實現該效果,它需要組合其他的WebKit屬性。
我們用一下代碼即可實現:
overflow : hidden; text-overflow: ellipsis; display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical;
但是這樣處理會遇到兼容性問題,在Firefox瀏覽器上就不起作用。
為了解決兼容性問題,有一個clamp.js[https://www.npmjs.com/package...]很好的解決這個問題。
為了更好的跟Vue相結合,今天我們就封裝一個v-clamp的指令,來方便的解決這個問題。
// 注冊一個全局自定義指令 `v-clamp` Vue.directive('clamp', { // 當被綁定的元素插入到 DOM 中時…… update: function (el, binding) { function clamp(element, options) { options = options || {}; var self = this, win = window, opt = { clamp: options.clamp || 2, useNativeClamp: typeof(options.useNativeClamp) != 'undefined' ? options.useNativeClamp : true, splitOnChars: options.splitOnChars || ['.', '-', '–', '—', ' '], //Split on sentences (periods), hypens, en-dashes, em-dashes, and words (spaces). animate: options.animate || false, truncationChar: options.truncationChar || '…', truncationHTML: options.truncationHTML }, sty = element.style, originalText = element.innerHTML, supportsNativeClamp = typeof(element.style.webkitLineClamp) != 'undefined', clampValue = opt.clamp, isCSSValue = clampValue.indexOf && (clampValue.indexOf('px') > -1 || clampValue.indexOf('em') > -1), truncationHTMLContainer; if (opt.truncationHTML) { truncationHTMLContainer = document.createElement('span'); truncationHTMLContainer.innerHTML = opt.truncationHTML; } // UTILITY FUNCTIONS __________________________________________________________ /** * Return the current style for an element. * @param {HTMLElement} elem The element to compute. * @param {string} prop The style property. * @returns {number} */ function computeStyle(elem, prop) { if (!win.getComputedStyle) { win.getComputedStyle = function(el, pseudo) { this.el = el; this.getPropertyValue = function(prop) { var re = /(\-([a-z]){1})/g; if (prop == 'float') prop = 'styleFloat'; if (re.test(prop)) { prop = prop.replace(re, function() { return arguments[2].toUpperCase(); }); } return el.currentStyle && el.currentStyle[prop] ? el.currentStyle[prop] : null; }; return this; }; } return win.getComputedStyle(elem, null).getPropertyValue(prop); } /** * Returns the maximum number of lines of text that should be rendered based * on the current height of the element and the line-height of the text. */ function getMaxLines(height) { var availHeight = height || element.clientHeight, lineHeight = getLineHeight(element); return Math.max(Math.floor(availHeight / lineHeight), 0); } /** * Returns the maximum height a given element should have based on the line- * height of the text and the given clamp value. */ function getMaxHeight(clmp) { var lineHeight = getLineHeight(element); return lineHeight * clmp; } /** * Returns the line-height of an element as an integer. */ function getLineHeight(elem) { var lh = computeStyle(elem, 'line-height'); if (lh == 'normal') { // Normal line heights vary from browser to browser. The spec recommends // a value between 1.0 and 1.2 of the font size. Using 1.1 to split the diff. lh = parseInt(computeStyle(elem, 'font-size')) * 1.2; } return parseInt(lh); } // MEAT AND POTATOES (MMMM, POTATOES...) ______________________________________ var splitOnChars = opt.splitOnChars.slice(0), splitChar = splitOnChars[0], chunks, lastChunk; /** * Gets an element's last child. That may be another node or a node's contents. */ function getLastChild(elem) { //Current element has children, need to go deeper and get last child as a text node if (elem.lastChild.children && elem.lastChild.children.length > 0) { return getLastChild(Array.prototype.slice.call(elem.children).pop()); } //This is the absolute last child, a text node, but something's wrong with it. Remove it and keep trying else if (!elem.lastChild || !elem.lastChild.nodeValue || elem.lastChild.nodeValue === '' || elem.lastChild.nodeValue == opt.truncationChar) { elem.lastChild.parentNode.removeChild(elem.lastChild); return getLastChild(element); } //This is the last child we want, return it else { return elem.lastChild; } } /** * Removes one character at a time from the text until its width or * height is beneath the passed-in max param. */ function truncate(target, maxHeight) { if (!maxHeight) { return; } /** * Resets global variables. */ function reset() { splitOnChars = opt.splitOnChars.slice(0); splitChar = splitOnChars[0]; chunks = null; lastChunk = null; } var nodeValue = target.nodeValue.replace(opt.truncationChar, ''); //Grab the next chunks if (!chunks) { //If there are more characters to try, grab the next one if (splitOnChars.length > 0) { splitChar = splitOnChars.shift(); } //No characters to chunk by. Go character-by-character else { splitChar = ''; } chunks = nodeValue.split(splitChar); } //If there are chunks left to remove, remove the last one and see if // the nodeValue fits. if (chunks.length > 1) { // console.log('chunks', chunks); lastChunk = chunks.pop(); // console.log('lastChunk', lastChunk); applyEllipsis(target, chunks.join(splitChar)); } //No more chunks can be removed using this character else { chunks = null; } //Insert the custom HTML before the truncation character if (truncationHTMLContainer) { target.nodeValue = target.nodeValue.replace(opt.truncationChar, ''); element.innerHTML = target.nodeValue + ' ' + truncationHTMLContainer.innerHTML + opt.truncationChar; } //Search produced valid chunks if (chunks) { //It fits if (element.clientHeight <= maxHeight) { //There's still more characters to try splitting on, not quite done yet if (splitOnChars.length >= 0 && splitChar !== '') { applyEllipsis(target, chunks.join(splitChar) + splitChar + lastChunk); chunks = null; } //Finished! else { return element.innerHTML; } } } //No valid chunks produced else { //No valid chunks even when splitting by letter, time to move //on to the next node if (splitChar === '') { applyEllipsis(target, ''); target = getLastChild(element); reset(); } } //If you get here it means still too big, let's keep truncating if (opt.animate) { setTimeout(function() { truncate(target, maxHeight); }, opt.animate === true ? 10 : opt.animate); } else { return truncate(target, maxHeight); } } function applyEllipsis(elem, str) { elem.nodeValue = str + opt.truncationChar; } // CONSTRUCTOR ________________________________________________________________ if (clampValue == 'auto') { clampValue = getMaxLines(); } else if (isCSSValue) { clampValue = getMaxLines(parseInt(clampValue)); } var clampedText; if (supportsNativeClamp && opt.useNativeClamp) { sty.overflow = 'hidden'; sty.textOverflow = 'ellipsis'; sty.webkitBoxOrient = 'vertical'; sty.display = '-webkit-box'; sty.webkitLineClamp = clampValue; if (isCSSValue) { sty.height = opt.clamp + 'px'; } } else { var height = getMaxHeight(clampValue); if (height <= element.clientHeight) { console.log(getLastChild(element)); clampedText = truncate(getLastChild(element), height); } } return { 'original': originalText, 'clamped': clampedText }; } clamp(el,{clamp: 2}) } })
其實很簡單,僅僅是把clamp.js中的函數搬移了過來。然后就可以像這樣來使用:
<div class="txt" v-clamp>很抱歉!沒有搜索到相關模板很抱歉!沒有搜索到相關模板很抱歉!沒有搜索到相關模板很抱歉!沒有搜索到相關模板</div>
感謝你能夠認真閱讀完這篇文章,希望小編分享的“如何通過封裝一個v-clamp的指令處理多行文本溢出”這篇文章對大家有幫助,同時也希望大家多多支持億速云,關注億速云行業資訊頻道,更多相關知識等著你來學習!
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。