js实现高度自适应的简单文本编辑框

2018-07-30  本文已影响0人  团子Secret

摘要:本文描述了一种实现随着文本输入或删除能自动改变高度适应文字量的简单文本编辑框的方法,效果入下图(没有富文本格式,只有基本的换行、空格等格式)。主要思路是建立两个textarea元素,隐藏其中一个,随着文字输入检查隐藏的textarea元素的滚动高度,把这个高度值赋给显示的textarea

自适应文本框.gif

起因

前段时间做了一个类ppt的在线编辑器,当然功能比ppt简单很多。其中在插入文字的时候由于输入完成之后要有基本的换行,空格之类的格式,因此用<textarea>元素是比较合适的。但是在textarea元素内输入文字的时候,如果内容比较多,超出元素高度的时候,就会出现滚动条,这显然是不符合一个类ppt编辑器对文字元素的要求的。当然简单一点可以让不去管它,提供一个功能让用户自己去调整文字框的大小,不过既然做了总想做好一点。于是通过搜索和摸索实现了一个能够随着文字输入或删除,高度能够自适应改变的文本框。

实现思路和过程

初始方案

一开始的基本思路就是每当在textarea元素的内容发生改变之后,获取textareascrollHeight,然后让textareastyle.height等于这个值。于是初版代码大约是这样(我用的vue框架,其他框架或者不用框架应该也是类似):

<textarea type="text" @focus="textFocus" v-model="content" ref="input" :style="{height: teaxtAreaHeight}" rows="1" 
    style="overflow-y: hidden;">
</textarea>
export default {
    data() {
        content: '',
        teaxtAreaHeight: ''
    },
    methods: {
        textFocus() {
            document.addEventListener('keyup', () => {
                this.$nextTick(() => {
                    const height = `${(this.$refs.input).scrollHeight}px`;
                    if (height !== this.teaxtAreaHeight) {
                        this.teaxtAreaHeight = height;
                    }
                });
            });
        }
    }
}

界面上的textarea元素内容绑定了content变量,元素高度height绑定变量textAreaHeight,初始是默认高度。overflow-y属性是hidden,为的是不出现滚动条。当文本框获得焦点时,执行textFocus,监听键盘输入事件,获取文本框的scrollHeight也就是滚动高度,如果滚动高度和现在文本框的高度不一样,说明因为文字输入导致了文本内容高度与文本框高度不同,则改变文本框高度teaxtAreaHeight。其中$nextTick方法是vue中用于等待下一次dom重新渲染后再执行其中的代码,因为文字输入后文本框的scrollHeight要等到dom重新渲染才会变化。这样就可以实现随着文字输入,文本框高度自动适应文本内容高度,不会有滚动条了。

初始方案的问题

上面这个方案虽然实现了随着文字输入高度自动增加来适应文本内容,但是有个问题,就是不能够随着文字的删除来自动减小高度适应删减后的文本高度。因为一旦给textarea设置了较大的高度height,那么在文字删除后scollHeight也不会重新减小了!

改进

为了解决上面的问题,加入第二个textarea。这个textarea始终是隐藏的,与显示的textarea绑定了同样的文本内容,不改变该textareaheight,这样scollHeight就会随着文字内容高度的变化而变化,这样由它作为一把高度的尺子,以它的scollHeight为标准去改变显示textareaheight

<textarea @focus="textFocus" type="text" v-model="content" ref="input" :style="{height: teaxtAreaHeight}"
    rows="1" style="overflow-y: hidden;">
</textarea>
<textarea style="position: absolute; visibility:hidden;" ref="heightRuler" v-model="content" rows="1"></textarea>
export default {
    data() {
        content: '',
        teaxtAreaHeight: ''
    },
    methods: {
        textFocus() {
            document.addEventListener('keyup', () => {
                this.$nextTick(() => {
                    const height = `${(this.$refs.heightRuler).scrollHeight}px`;
                    if (height !== this.teaxtAreaHeight) {
                        this.teaxtAreaHeight = height;
                    }
                });
            });
        }
    }
}

vue优化版

思路还是之前那个思路,不过代码可以变得更加优雅。之前的做法是监听键盘事件,在vue中还可以直接通过watch监听value值来计算高度,也可以通过计算属性的set方法在value发生改变的时候计算高度

上一篇下一篇

猜你喜欢

热点阅读