首页 > Vue >

vue的el-input、el-select内容宽度自适应,文字自动撑开

时间: 作者:admin 浏览:

项目中需要做到根据<el-select>选中内容的宽度调整组件宽度,或者<el-input>根据输入内容自适应宽度,用以节省页面占用空间,以前有做过textarea的高度跟随内容变化,隐约记得也做过宽度跟随变化的,但input框输入内容时,宽度是不会像普通标签一样自动撑开,所以基本思想就是input宽度设置100%,宽度跟随父节点变化而变化,通过js获取输入的内容长度,再将相应长度赋值给父节点,但是简单的获取内容的length是不行的,中英文混杂无法做到准确的宽度,因此查了下资料,突然想起以前自己也写过这样的代码,那就是将input的宽度相关属性paddingLeft、paddingRight、boderLeft、borderRight、outlineWidth,fontSize、fontWeight、boxSizing等都同步给一个隐藏的span标签,将内容放到span里,父节点的宽度跟随这个span变化即可,相当聪明可靠的做法,下面将这个代码共享给大家参考,将这个自定义指令命名为v-autowidth:

auto-width.js

export default{
    directives:{
        autowidth:{
            bind(el, binding, vnode){
                let getComputedStyles = (dom)=>{
                    return window.getComputedStyle?getComputedStyle(dom, null):dom.currentStyle
                }
                let doUnit = (val)=>{
                    return typeof val === 'number'?val+'px':val
                }
                let spanClass = `auto-width-${vnode.context._uid}`,
                    spanElement = document.createElement('span')

                el.style.position = 'relative'
                spanElement.style.position = 'absolute'
                spanElement.style.height = 0
                spanElement.style.zIndex = -9999
                spanElement.style.right ='-9999px'
                spanElement.style.top = 0
                spanElement.style.visibility = 'hidden'
                spanElement.style.opacity = 0
                spanElement.style.display = 'inline-block'
                spanElement.style['word-break'] = 'keep-all'
                spanElement.style['white-space'] = 'nowrap'

                spanElement.innerText = binding.value
                spanElement.className = spanClass
                vnode.context.spanClass = spanClass
                vnode.context.getComputedStyles = getComputedStyles
                vnode.context.doUnit = doUnit

                el.appendChild(spanElement)

                let styleKeys = [
                    'paddingLeft',
                    'paddingRight',
                    'borderLeft',
                    'borderRight',
                    'outlineWidth',
                    'fontWeight',
                    'fontSize',
                    'boxSizing'
                ]

                vnode.context.$nextTick(()=>{
                    let inputDom = el.querySelector("input"),
                         styles = getComputedStyles(inputDom)

                    styleKeys.forEach((s)=>{
                        spanElement.style[s] = styles[s]
                    })

                    inputDom.style.width = '100%'
                    el.style.width = getComputedStyles(spanElement).width
                    if(binding?.arg?.min){
                        el.style.minWidth = doUnit(binding.arg.min)
                    }
                    if(binding?.arg?.max){
                        el.style.maxWidth = doUnit(binding.arg.max)
                    }
                })
            },
            update(el, binding, vnode){
                if(binding.value !== binding.oldValue){
                    let spanElement = el.querySelector("."+vnode.context.spanClass)
                    spanElement.innerText = binding.value
                    vnode.context.$nextTick(()=>{
                        el.style.width = vnode.context.getComputedStyles(spanElement).width
                    })
                }
            }
        }
    }
}

小编将上面的代码存在一个js里,作为公共组件到处mixins引用,当然你也可以写在局部某个vue文件中的directives钩子中使用;

使用例子:

因为<el-input /><el-select />组件是在input基础上嵌套父元素实现的,所以可以直接使用v-autowidth,原生的<input />则要绑定在其父元素中

template

<template>
    <el-input v-model="valuea" v-autowidth="valuea" />
    <el-select v-model="selected"  v-autowidth="valueb">
        <el-option
            v-for="item in options"
            :key="item.value"
            :value="item.value"
            :label="item.label"
        ></el-option>
    </el-select>
    <div v-autowidth="valuec">
        <input type="text" v-model="valuec" />
    </div>
</template>

javascript

export default{
    data(){
        return {
            valuea:"abc",
            options:[{
                label:"长字符串xxxxxx"
                value:"long"
            },{
                label:"短字符串"
                value:"short"
            }],
            selected:"long",
            valuec:"xyz"
        }
    },
    computed:{
        valueb(){
            return this.options.find(v=>v.value === this.selected).label
        }
    }
}

就是如此,应该都差不多了,快去试试吧

前端新手交流群
欢迎加入web前端新手交流qq群:734802480

更多文章

栏目文章


Copyright © 2014-2022 seozhijia.net 版权所有-粤ICP备13087626号-4