Vue中textarea⾃适应⾼度⽅案的实现
⽬录
隐藏的问题
解决⾃适应⾼度的⽅案
先给⽅案,Vue栈有需求的同学可以直接下载
隐藏的问题
抛开原⽣JS,框架的⼤部分UI库都⽀持⾃适应textarea⾼度功能,但普遍都忽略了⼀个功能,就是⾃适应⾼度的回显。
使⽤这些库的时候,我们很容易的在textarea中键⼊内容,超出范围时会⾃动延展⼀⾏,保证内容⾼度的⾃适应。当我们提交内容,在其它页⾯使⽤同样的UI来渲染时,⿇烦的就来了,有些UI库是不⽀持⾃适应回显的,这就需要我们通过⾏⾼、⾏数甚⾄⾼度之间的计算得出⼀个基值,从⽽实现回显。
解决⾃适应⾼度的⽅案
常见得⽅案有两种,⼀种是在页⾯地“边远地区”添加⼀个ghost dom来模拟输⼊换⾏,这个dom的可能是editable属性为true的div或者是⼀个⼀摸⼀样得textarea。
以element-ui的input组件举例,当我们在组件内输⼊值时,会调⽤resizeTextarea⽅法
resizeTextarea() {
if (this.$isServer) return;
const { autosize, type } = this;
if (type !== 'textarea') return;
if (!autosize) {
minHeight: calcTextareaHeight(this.$area).minHeight
};
return;
}
textstyleconst minRows = autosize.minRows;
const maxRows = autosize.maxRows;
}
当设置了autosize为true则textarea设为⾃适应⾼度。此时textarea的⾼度会通过calcTextareaHeight⽅法实时计算。
export default function calcTextareaHeight(
targetElement,
minRows = 1,
maxRows = null
) {
if (!hiddenTextarea) {
hiddenTextarea = ateElement('textarea');
document.body.appendChild(hiddenTextarea);
}
let {
paddingSize,
borderSize,
boxSizing,
contextStyle
} = calculateNodeStyling(targetElement);
hiddenTextarea.setAttribute('style', `${contextStyle};${HIDDEN_STYLE}`);
hiddenTextarea.value = targetElement.value || targetElement.placeholder || '';
let height = hiddenTextarea.scrollHeight;
const result = {};
if (boxSizing === 'border-box') {
height = height + borderSize;
} else if (boxSizing === 'content-box') {
height = height - paddingSize;
}
hiddenTextarea.value = '';
let singleRowHeight = hiddenTextarea.scrollHeight - paddingSize;
if (minRows !== null) {
let minHeight = singleRowHeight * minRows;
if (boxSizing === 'border-box') {
minHeight = minHeight + paddingSize + borderSize;
}
height = Math.max(minHeight, height);
result.minHeight = `${ minHeight }px`;
}
if (maxRows !== null) {
let maxHeight = singleRowHeight * maxRows;
if (boxSizing === 'border-box') {
maxHeight = maxHeight + paddingSize + borderSize;
}
height = Math.min(maxHeight, height);
}
result.height = `${ height }px`;
hiddenTextarea.parentNode && veChild(hiddenTextarea);
hiddenTextarea = null;
return result;
};
我们可以看到
if (!hiddenTextarea) {
hiddenTextarea = ateElement('textarea');
document.body.appendChild(hiddenTextarea);
}
element-ui创建了⼀个textarea的dom,通过calculateNodeStyling⽅法将真正的textarea的样式复制给
hiddenTextarea(overflow不同步,真正的textarea是为hidden)。接着监听textarea的输⼊值,同步给hiddenTextarea。同时将hiddenTextarea的scrollHeight同步给textarea的⾼度,最后再将dom销毁掉。
关于样式的同步,element这⾥⽤了getComputedStyle和getPropertyValue这两个API。当然,如果你⾃⼰封装的话,也可以使⽤css预处理器的mixin。
第⼆种⽅案与第⼀种⽅案类似,不过不会创建额外的dom。以开头的vue-awesome-textarea举例:
init() {
this.initAutoResize()
},
initAutoResize () {
this.autoResize && this.$nextTick(this.calcResize)
}
在页⾯mounted或者内容变动且开启⾃适应⾼度autoResize的时候,执⾏this.calcResize⽅法。
calcResize() {
this.calcTextareaH()
},
resetHeight() {
this.height = 'auto'
},
calcTextareaH() {
let contentHeight = this.calcContentHeight()
this.height = this.calcHeightChange(contentHeight) + 'px'
if (dUpdateRows(contentHeight)) {
this.updateRows(contentHeight)
}
this.oldContentHeight = contentHeight
},
calcContentHeight () {
const { paddingSize } = this.calcNodeStyle(this.$el)
return this.$el.scrollHeight - paddingSize
},
resetHeight()是来初始化textarea的⾼度,默认为auto。calcTextareaH()⽅法是⽤来计算内容区域的⾼度(textarea的scrollHeight减去padding的⾼度),同时将计算好的⾼度实时同步给textarea的⾼:
this.height = this.calcHeightChange(contentHeight) + 'px'
相⽐⽅案⼀,这个⽅案采⽤的思路相同(动态修改⾼度),但是减少了额外的dom创建和销毁的过程。
此外,vue-awesome-textarea还⽀持在⾃适应的过程中回调⾏数,可以更好的⽀持数据回显。实现的⽅法也很简单:computed: {
...
oneRowsHeight() {
return this.calcContentHeight() / ws) || 0
}
.
..
}
在computed中我们计算出单⾏的⾼度,同时在执⾏this.calcTextareaH()⽅法时我们记录下内容⾼度:
this.oldContentHeight = contentHeight
接着我们会⽐对是否存在添加⾏操作,⼀旦添加则新的内容⾼度和⽼的内容⾼度会不同:
needUpdateRows(newContentHeight) {
return this.oldContentHeight !== newContentHeight
},
此时我们会把最新的⾏⾼emit到组件外部:
updateRows(contentHeight) {
this.$emit('getRows', und(contentHeight / RowsHeight))
}
到此这篇关于Vue中textarea⾃适应⾼度⽅案的实现的⽂章就介绍到这了,更多相关Vue textarea⾃适应内容请搜索以前的⽂章或继续浏览下⾯的相关⽂章希望⼤家以后多多⽀持!
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论