頁面tooltip組件限制工具函數使用示例詳解

需求描述
有這樣一個需求:頁面已經寫了太多的詳情表單元素,并且每一個表單元素都使用了Tooltip組件來包裹,這樣是不符合需求的,因為用戶需要限定當表單元素的文本太多時,也就是說出現了省略號才會出現Tooltip組件的包裹。比如項目采用的element UI組件庫。在一個頁面有太多的這樣的表單元素:
<el-form>
<el-form-item label="姓名" prop="name">
<el-tooltip :content="form.name">
<el-input v-model="form.name" disabled="true"></el-input>
</el-tooltip>
</el-form-item>
.....后續(xù)出現多個這樣的元素
</el-form>如果我每一個都加disabled屬性,那么頁面模板元素有將近一百個,很顯然我這樣加是很耗費時間的,很顯然對于追求高效的我是不喜歡一個一個加,然后一個一個判斷的。
在這之前,我們需要確定一點,那就是我們控制文本的截斷是通過CSS代碼來實現的。也就是如下這段代碼:
.el-input {
text-overflow:ellipsis;
white-space:nowrap;
overflow:hidden;
}因此,完成以上的需求的第一步就是需要先判斷哪些元素滿足被截斷的條件。那么如何判斷文本是否被截斷呢?關于這個實現,我想element ui的表格組件符合這種場景,所以我只需要去參考一下element ui的表格組件的截斷判斷實現就知道了。沒錯,我在源碼中找到了實現方式。
創(chuàng)建range元素
核心思路就是創(chuàng)建一個range元素,通過獲取range元素width然后與元素的offsetWidth進行判斷就行了。所以,我按照element ui的實現思路完成了這個工具函數。如下所示:
function isTextOverflow(element) {
// use range width instead of scrollWidth to determine whether the text is overflowing
// to address a potential FireFox bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1074543#c3
if (!element || !element.childNodes || !element.childNodes.length) {
return false;
}
const range = document.createRange();
range.setStart(element, 0);
range.setEnd(element, element.childNodes.length);
const rangeWidth = range.getBoundingClientRect().width;
// if the element has padding style,should add the padding value.
const padding = (parseInt(getStyle(element, 'paddingLeft'), 10) || 0) + (parseInt(getStyle(element, 'paddingRight'), 10) || 0);
return rangeWidth + padding > element.offsetWidth || element.scrollWidth > element.offsetWidth;
}
function hasClass(el, cls) {
if (!el || !cls) {
return false;
}
if (cls.indexOf(" ") > -1) {
return console.error(`className should not contain space!`);
}
if (el.classList) {
return el.classList.contains(cls);
} else {
return (" " + el.className + " ").indexOf(" " + cls + " ") > -1;
}
}
function camelCase(name) {
return name.replace(/([\:\_\-]+(.))/g, (_, separator, letter, offset) => offset ? letter.toUpperCase() : letter).replace(/^moz([A-Z])/, "Moz$1")
}
// IE version more than 9
function getStyle(el, styleName) {
if (!element || !styleName) return null;
styleName = camelCase(styleName);
if (styleName === 'float') {
styleName = 'cssFloat';
}
try {
var computed = document.defaultView.getComputedStyle(element, '');
return element.style[styleName] || computed ? computed[styleName] : null;
} catch (e) {
return element.style[styleName];
}
}收集所有的tooltip組件實例
這只是完成了第一步,接下來是第二步,就是我需要將頁面上所有包含tooltip組件的vue組件實例都要收集起來。首先我們可以確定頁面所有的toolTip組件實例應該都是當前這個表單組件實例的所有子組件,因此,我想到了遞歸去收集所有包含tooltip組件的組件實例。代碼如下:
export function findToolTip(children,tooltips = []){
//這里寫代碼
}所有的tooltip組件實例都是vue組件實例的子組件,所以我們可以知道我們去循環(huán)組件實例的子組件,即vm.$children屬性。然后tooltip組件有什么標志呢?或者說我們如何判斷該子組件實例就是一個tooltip組件呢?我又參考了element ui tooltip組件的實現,發(fā)現element ui tooltip組件都會有一個doDestory方法。所以我們就可以根據這個來做判斷。所以遞歸方法,我們就可以寫好了。如下:
//參數1:子組件實例數組
//參數2:收集組件實例的數組
export function findToolTip(children,tooltips = []){
for(let i = 0,len = children.length;i < len;i++){
//遞歸條件
if(Array.isArray(children[i]) && children[i].length){
findToolTip(children[i],tooltips);
}else{
//判斷如果doDestroy屬性是一個方法,則代表是一個tooltip組件,添加到數組中
if(typeof children[i].doDestroy === "function"){
tooltips.push(children[i]);
}
}
}
//把收集到的組件實例返回
return tooltips;
}
//調用方式,傳入當前組件實例this對象的所有子組件實例
//如:findToolTip(this.$children)我們找到所有tooltip組件實例了,接下來,我們要遍歷它,然后判斷是否符合截斷條件,不符合我們就需要將組件給銷毀,事實上,我們直接設置tooltip組件實例的disabled屬性為true就可以了。接下來,就是這個工具函數的實現了。如下:
// 參數1:當前組件實例this對象
// 參數2:用于獲取被tooltip包裹的子元素的類名
export function isShowToolTip(vm,className="el-input"){
//這里寫代碼
}如何修改tooltip組件?
接下來,我們就要實現這個工具函數。首先,我們需要確定的是,因為disabled是props數據,props是單向數據流,vue.js是不建議我們直接修改的,那么我們應該如何做到設置disabled呢?我想了很久,想的辦法就是重新渲染整個組件,利用Vue.compie API也就是編譯API直接重新編譯整個tooltip組件,然后替換原本渲染的tooltip組件。如下:
const res = Vue.compile(`<el-tooltip disabled><el-input value="${ child && child.innerText }" disabled></el-input></el-tooltip>`);
const reRender = new Vue({
render:res.render,
staticRenderFns:res.staticRenderFns
}).$mount(parent);//parent為獲取的tooltip組件實例根元素所以,接下來在工具函數里,我們可以這樣實現:
// 參數1:當前組件實例this對象
// 參數2:用于獲取被tooltip包裹的子元素的類名
export function isShowToolTip(vm,className="el-input"){
//為了確保能夠獲取到DOM元素,需要調用一次nextTick方法
vm.$nextTick(() => {
const allTooltips = findToolTip(vm.$children);
allTooltips.forEach(item => {
//獲取子元素
const child = item.$el.querySelector("." + className);
//判斷是否被截斷
if(!isTextOverflow(child)){
//獲取渲染元素
const parent = item.$el;
const res = Vue.compile(`<el-tooltip disabled><el-input value="${ child && child.innerText }" disabled></el-input></el-tooltip>`);
const reRender = new Vue({
render:res.render,
staticRenderFns:res.staticRenderFns
}).$mount(parent);
}
})
}};
}如何使用這個工具函數?
如此一來,就做到了一個方法完成了以上的需求。如何使用這個方法呢,很簡單,我們可以在詳情組件里面監(jiān)聽表單詳情數據的變化。如:
watch:{
form(val){
if(typeof val === "object" && val && Object.keys(val).length){
//將this當做參數傳入即可
isShowToolTip(this);
}
}
}關于這個需求更好的實現,如有更好的方法,望不吝賜教。
以上就是頁面tooltip組件的限制工具函數使用示例詳解的詳細內容,更多關于頁面tooltip組件限制的資料請關注腳本之家其它相關文章!
相關文章
Vue3使用echarts tree高度自適應支持滾動查看功能
這篇文章主要介紹了Vue3使用echarts tree高度自適應支持滾動查看功能,文章同通過代碼示例介紹的非常詳細,具有一定的參考價值,需要的朋友可以參考下2024-06-06
在vue中利用全局路由鉤子給url統(tǒng)一添加公共參數的例子
今天小編就為大家分享一篇在vue中利用全局路由鉤子給url統(tǒng)一添加公共參數的例子,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2019-11-11
vue + el-tree 實現插入節(jié)點自定義名稱數據的代碼
這篇文章主要介紹了vue + el-tree 實現插入節(jié)點自定義名稱數據的代碼,本文通過實例代碼給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友參考下吧2023-12-12

