页面tooltip组件限制工具函数使用示例详解

 更新时间:2023年09月06日 11:32:11   作者:夕水  
这篇文章主要为大家介绍了页面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>
   .....后续出现多个这样的元素
</el-form>

如果我每一个都加disabled属性,那么页面模板元素有将近一百个,很显然我这样加是很耗费时间的,很显然对于追求高效的我是不喜欢一个一个加,然后一个一个判断的。

在这之前,我们需要确定一点,那就是我们控制文本的截断是通过CSS代码来实现的。也就是如下这段代码:

.el-input {
    text-overflow:ellipsis;
    white-space:nowrap;
    overflow:hidden;
}

因此,完成以上的需求的第一步就是需要先判断哪些元素满足被截断的条件。那么如何判断文本是否被截断呢?关于这个实现,我想element ui的表格组件符合这种场景,所以我只需要去参考一下element ui的表格组件的截断判断实现就知道了。没错,我在源码中找到了实现方式。

创建range元素

核心思路就是创建一个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组件实例的子组件,所以我们可以知道我们去循环组件实例的子组件,即vm.$children属性。然后tooltip组件有什么标志呢?或者说我们如何判断该子组件实例就是一个tooltip组件呢?我又参考了element ui tooltip组件的实现,发现element ui tooltip组件都会有一个doDestory方法。所以我们就可以根据这个来做判断。所以递归方法,我们就可以写好了。如下:

//参数1:子组件实例数组
//参数2:收集组件实例的数组
export function findToolTip(children,tooltips = []){
    for(let i = 0,len = children.length;i &lt; len;i++){
        //递归条件
        if(Array.isArray(children[i]) &amp;&amp; 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);
            }
        })
    }};
}

如何使用这个工具函数?

如此一来,就做到了一个方法完成了以上的需求。如何使用这个方法呢,很简单,我们可以在详情组件里面监听表单详情数据的变化。如:

watch:{
    form(val){
        if(typeof val === "object" && val && Object.keys(val).length){
            //将this当做参数传入即可
            isShowToolTip(this);
        }
    }
}

关于这个需求更好的实现,如有更好的方法,望不吝赐教。

以上就是页面tooltip组件的限制工具函数使用示例详解的详细内容,更多关于页面tooltip组件限制的资料请关注脚本之家其它相关文章!

相关文章

  • Vue el-autocomplete远程搜索下拉框并实现自动填充功能(推荐)

    Vue el-autocomplete远程搜索下拉框并实现自动填充功能(推荐)

    在elementui Input输入框中可以找到远程搜索组件,获取服务端的数据。这篇文章主要给大家介绍Vue el-autocomplete远程搜索下拉框并实现自动填充功能,感兴趣的朋友一起看看吧
    2019-10-10
  • vue使用vue-draggable的全过程

    vue使用vue-draggable的全过程

    这篇文章主要介绍了vue使用vue-draggable的全过程,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教
    2024-03-03
  • vue打开其他项目页面并传入数据详解

    vue打开其他项目页面并传入数据详解

    这篇文章主要给大家介绍了关于vue打开其他项目页面并传入数据的相关资料,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2020-11-11
  • vue3项目引入pinia报错的简单解决

    vue3项目引入pinia报错的简单解决

    这篇文章主要介绍了vue3项目引入pinia报错的简单解决,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教
    2023-10-10
  • 前端vue中实现嵌入代码编辑器的详细代码

    前端vue中实现嵌入代码编辑器的详细代码

    随着Web技术的不断发展,前端开发也正日新月异,下面这篇文章主要给大家介绍了关于前端vue中实现嵌入代码编辑器的相关资料,文中通过代码介绍的非常详细,需要的朋友可以参考下
    2024-07-07
  • vue3+ts重复参数提取成方法多处调用以及字段无值时不传字段给后端问题

    vue3+ts重复参数提取成方法多处调用以及字段无值时不传字段给后端问题

    在进行API开发时,优化参数传递是一个重要的考量,传统方法中,即使参数值为空,也会被包含在请求中发送给后端,这可能会导致不必要的数据处理,而优化后的方法则只会传递那些实际有值的字段,从而提高数据传输的有效性和后端处理的效率
    2024-10-10
  • Vue前端如何实现与后端进行数据交互

    Vue前端如何实现与后端进行数据交互

    这篇文章主要介绍了Vue前端如何实现与后端进行数据交互,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2022-03-03
  • Vue中如何使用base64编码和解码

    Vue中如何使用base64编码和解码

    这篇文章主要介绍了Vue中如何使用base64编码和解码问题,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2023-02-02
  • Vue路由Hash模式分析

    Vue路由Hash模式分析

    Vue-router是Vue的核心组件,主要是作为Vue的路由管理器,Vue-router默认hash模式,本文讲给大家详细分析Vue路由Hash模式,文中有相关的代码示例供大家参考,感兴趣的同学可以借鉴一下
    2023-06-06
  • 解决Vue运行项目报错proxy error: could not proxy request

    解决Vue运行项目报错proxy error: could not proxy request

    这篇文章主要给大家介绍了关于如何解决Vue运行项目报错proxy error:could not proxy request的相关资料,Proxy Error指的是代理服务器无法正确处理请求的错误,需要的朋友可以参考下
    2023-08-08

最新评论