从0搭建vue3组件库: Input组件( 四 )

具体实现原理是通过监听输入框值的变化来调整textarea的样式,其中用到了一些原生的方法譬如window.getComputedStyle(获取原生css对象),getPropertyValue(获取css属性值)等,所以原生js忘记的可以复习一下
...const textareaStyle = ref<any>()const textarea = shallowRef<HTMLTextAreaElement>()watch(() => inputProps.modelValue, () => {if (attrs.type === 'textarea' && inputProps.autosize) {const minRows = isObject(inputProps.autosize) ? (inputProps.autosize as AutosizeObj).minRows : undefinedconst maxRows = isObject(inputProps.autosize) ? (inputProps.autosize as AutosizeObj).maxRows : undefinednextTick(() => {textareaStyle.value = https://www.huyubaike.com/biancheng/calcTextareaHeight(textarea.value!, minRows, maxRows)})}}, { immediate: true })其中calcTextareaHeight
const isNumber = (val: any): boolean => {return typeof val === 'number'}//隐藏的元素let hiddenTextarea: HTMLTextAreaElement | undefined = undefined//隐藏元素样式const HIDDEN_STYLE = `height:0 !important;visibility:hidden !important;overflow:hidden !important;position:absolute !important;z-index:-1000 !important;top:0 !important;right:0 !important;`const CONTEXT_STYLE = ['letter-spacing','line-height','padding-top','padding-bottom','font-family','font-weight','font-size','text-rendering','text-transform','width','text-indent','padding-left','padding-right','border-width','box-sizing',]type NodeStyle = {contextStyle: stringboxSizing: stringpaddingSize: numberborderSize: number}type TextAreaHeight = {height: stringminHeight?: string}function calculateNodeStyling(targetElement: Element): NodeStyle {//获取实际textarea样式返回并赋值给隐藏的textareaconst style = window.getComputedStyle(targetElement)const boxSizing = style.getPropertyValue('box-sizing')const paddingSize =Number.parseFloat(style.getPropertyValue('padding-bottom')) +Number.parseFloat(style.getPropertyValue('padding-top'))const borderSize =Number.parseFloat(style.getPropertyValue('border-bottom-width')) +Number.parseFloat(style.getPropertyValue('border-top-width'))const contextStyle = CONTEXT_STYLE.map((name) => `${name}:${style.getPropertyValue(name)}`).join(';')return { contextStyle, paddingSize, borderSize, boxSizing }}export function calcTextareaHeight(targetElement: HTMLTextAreaElement,minRows = 1,maxRows?: number): TextAreaHeight {if (!hiddenTextarea) {//创建隐藏的textareahiddenTextarea = document.createElement('textarea')document.body.appendChild(hiddenTextarea)}//给隐藏的teatarea赋予实际textarea的样式以及值(value)const { paddingSize, borderSize, boxSizing, contextStyle } =calculateNodeStyling(targetElement)hiddenTextarea.setAttribute('style', `${contextStyle};${HIDDEN_STYLE}`)hiddenTextarea.value = https://www.huyubaike.com/biancheng/targetElement.value || targetElement.placeholder ||''//隐藏textarea整个高度,包括内边距padding,borderlet height = hiddenTextarea.scrollHeightconst result = {} as TextAreaHeight//判断boxSizing,返回实际高度if (boxSizing === 'border-box') {height = height + borderSize} else if (boxSizing === 'content-box') {height = height - paddingSize}hiddenTextarea.valuehttps://www.huyubaike.com/biancheng/= ''//计算单行高度const singleRowHeight = hiddenTextarea.scrollHeight - paddingSizeif (isNumber(minRows)) {let minHeight = singleRowHeight * minRowsif (boxSizing === 'border-box') {minHeight = minHeight + paddingSize + borderSize}height = Math.max(minHeight, height)result.minHeight = `${minHeight}px`}if (isNumber(maxRows)) {let maxHeight = singleRowHeight * maxRows!if (boxSizing === 'border-box') {maxHeight = maxHeight + paddingSize + borderSize}height = Math.min(maxHeight, height)}result.height = `${height}px`hiddenTextarea.parentNode?.removeChild(hiddenTextarea)hiddenTextarea = undefinedreturn result}

这里的逻辑稍微复杂一点,大致就是创建一个隐藏的textarea,然后每次当输入框值发生变化时,将它的

经验总结扩展阅读