项目中需要做到根据<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
}
}
}
就是如此,应该都差不多了,快去试试吧