textarea属性(js获取textarea的行数)

背景我们知道,textarea是一个内联块元素显示:inline-block及其默认的宽度和高度是由cols & amp;Rows定义的,这决定了textare

背景我们知道,textarea是一个内联块元素显示:inline-block及其默认的宽度和高度是由cols & amp;Rows定义的,这决定了textarea的高度不适应内容长度。

textarea的宽度和高度是如何确定的?参考张新旭的文章HTML textarea cols,rows属性以及宽度和高度的关系。

因此,我们今天的任务是考虑如何创建一个高度内容自适应的textarea组件。我将介绍实现高度内容自适应的textarea的三种思路,具体代码为textareaAutoSizeSolutions。

方案概要

这是对三种方案的概述,也是对实现思路的简单介绍。实现方案&遇见坑&扩展知识点,点击查看teeeemoji演示。

方案一:调整textarea.style.height两次。

textarea的onchange触发resize方法。下面是resize方法的逻辑。

textarea . style . height = ' auto ';// 1.让textarea的高度恢复到默认的textarea . style . height = textarea . scroll height+' px ';// 2.textarea.scrollHeight表示*textarea*内容的实际高度。方案二:用一个ghostTextarea获取输入框的内容高度,然后将这个高度设置为真实的Textarea。

ghosttextarea是在构建textarea时创建的,resize方法由onchange触发:

创建 textarea 的时候, 同时创建一个一模一样的隐藏 ghostTextarea;ghostTextarea 的属性全部克隆自 textarea, 但是 ghostTextarea 是 隐藏 的, 并且 ghostTextarea.style.height = 0; 也就是说 ghostTextarea.scrollHeight 就是 textarea 中内容的真是高度。

Resize方法处理流程:

textarea.value 先设置给 ghostTextarea,拿到 ghostTextarea.scrollHeight将 textarea.style.height = ghostTextarea.scrollHeight

方案三:使用(div | p |...).contenteditable而不是textarea作为输入框。

Div是块级元素,高度本身是内容自适应的(除非设置了max-width或min-widht)。使用contenteditable让div替换textarea,省去了计算高度的各种逻辑。

方案比较

满分3分,通过优化,三种方案在用户体验和兼容性上都可以达到满分。所以区别只在于这些方案实现的难易程度(仅基于react组件实现的复杂程度)。方案比较:

textarea属性(js获取textarea的行数)插图

毫无疑问,第一个选项是最佳选择,加1分作为奖励;

Scheme调整textarea.style.height一次或两次。

实现思路渲染一个 textarea 元素

& lttextareref = { this . bind ref } class name = { style[' textarea ']+'+class name } placeholder = { placeholder } value = { value } onchange = { this . handle change }//看这里/& gt;Textarea的onChange事件触发resizehandlechange(e){ this . props . onChange(e . target . value);this . resize();//看到这里} resize事件的实现。//重新计算textarea resize()的高度{ if(this . input ref){ console . log(' resizing...)this . input ref . style . height = ' auto ';this . input ref . style . height = this . input ref . scroll height+' px ';}}注意,当componentDidMount时,执行一次resize方法来初始化textarea的高度。优化点,避免二次渲染,造成内容抖动。

react中,组件receiveProps会渲染一次,直接调整textarea的高度也会重绘浏览器,会造成两次重绘,重绘两次textarea的内容可能会抖动。

优化思路:先触发resize再触发render,用最简单的思路完美解决问题。

方案二:用一个ghostTextarea获取输入框内容的高度,然后将这个高度设置为真实的Textarea。

实现理念

同时渲染两个文本区域,一个真实文本区域和一个隐藏文本区域。

return(& lt;div class name = { style[' comp-textarea-with-ghost ']} & gt;& lttextarea//this is true ref = { this . bind ref } class name = { style[' textarea ']+'+class name } placeholder = { placeholder } value = { value } onchange = { this . handle change } style = { { height } }/>;& lttextarea//this is ghost textarea class name = { style[' textarea-ghost ']} ref = { this . bindgostref } onchange = { noop }/>;& lt/div & gt;)初始化时,复制属性。初始化时,必须使用tool方法将textarea的属性复制到ghostTextarea。因为可以在组件外部控制textarea的样式,所以在初始化时复制样式是最安全的。

以下是要复制的属性列表:

const size _ STYLE =[' letter-spacing ',' line-height ',' font-family ',' font-weight ',' font-size ',' font-style ',' tab-size ',' text-rendering ',' text-transform ',' width ',' text-indent ',' padding-top ',' padding-right ',' padding-bottom ',' padding-left ',' border-top-width ',' border-bottom-width ',' border-left-width ',' box-SIZING '];这是ghostTextarea的隐藏属性列表:

const HIDDEN _ TEXTAREA _ STYLE = { ' min-height ':' 0 ',' max-height': 'none ',height: '0 ',visibility: 'hidden ',overflow: 'hidden ',position: 'absolute ',' z-index ':-1000 ',top: '0 ',right: '0 ',};这是一种复制风格的工具方法。

//获取真实textarea { const style = window . getcomputedstyle(node)的所有样式函数calculateddestying(node);if(style = = = null){ return null;} return SIZING _ style . reduce((obj,name)= & gt;{ obj[name]= style . getpropertyvalue(name);返回obj}, {});}//将真实textarea的样式复制到ghosttextarea export const Copy style = function(to node,from node){ const node styling = calculatenodestying(from node);if(nodestying = = = null){ return null;}Object.keys(节点样式)。forEach(key = & gt;{ to node . style[key]= nodestying[key];});object . keys(HIDDEN _ TEXTAREA _ STYLE)。forEach(key = & gt;{toNode.style.setProperty(key,HIDDEN_TEXTAREA_STYLE[key],' important ',);});}textarea的onChange事件将在触发Change事件之前被reize。

handle change(e){ this . resize();设value = e . target . value;this.props.onChange(值);}textarea的resize方法

resize() {console.log('resizing ... ')const height = calculategghosttextareaheight(this . ghost ref,this . input ref);this . setstate({ height });} CalculeHostTextareaEight工具方法

//先将内容设置到ghostTextarea中,然后得到ghosttextarea.scrollheight导出const calculate ghost textarea eight = function(ghost textarea,textarea) {if(!ghost textarea){ return;} ghost textarea . value = textarea . value | | textarea . placeholder | | ' x ' return ghost textarea . scroll height;}优化点

避免渲染两次,导致内容抖动。

在react中,组件receiveProps会渲染一次,设置textarea的height属性也会重绘浏览器。那么就会造成两次重绘,两次重绘的时候textarea的内容可能会抖动。

以下两个想法在demo中有所体现。

优化思路1:合并镜头渲染

使用window . requestanimationframe & window . cancelanimationframe取消第一帧的渲染,直接渲染高度已经调整的textarea

优化思路二:减少渲染次数。

使用react batch setState方法减少rerender的特性;在textarea onChange方法中同时触发两个setState

textarea属性(js获取textarea的行数)插图(1)

更多优化想法

页面存在多个 textarea 的时候, 能不能考虑 复用同一个 ghostTextarea

方案三:用div.contenteditable代替textarea。

实现理念

呈现div.contenteditable=true

return(& lt;div class name = { style[' comp-div-content editable ']} & gt;& ltdiv ref = { this . bind ref } className = { class name(style[' textarea '],class name,{[style['empty']]:!value })} onChange = { this . handle change } on paste = { this . handle paste } placeholder = { placeholder } content editable/& gt;& lt/div & gt;)get &amp编辑什么:textarea通过textarea.value取值或设置值,但改为div后,就需要使用div.innerHTML或div.innerText取值或设置值。

使用div.innerHTML时会出现以下两个问题:

& 会被转码成 &空白符合并 使用 div.innerText 在低版本 firfox 上要做兼容处理.

所以用哪种方法主要看需求。

占位符的实现:

div的占位符属性无效,将不会显示。有一种最简单的方法,通过使用纯css来实现div的占位符。

。textarea[placeholder]:empty:before {/* empty & amp;*/content之前的两个伪类:attr(占位符);/*属性函数*/color:# 555;}优化点

移除rtf支持。

Div.contenteditable默认支持富文本,通过粘贴或拖动可能导致富文本出现在输入框中;

textarea属性(js获取textarea的行数)插图(2)

监听div的onPaste事件

handle paste(e){ e . prevent default();let text = e . clipboard data . get data(' text/plain ');//获取纯文本document . exec command(' insert text ',false,text);//让浏览器执行插入文本的操作}更多兼容性处理}handlePaste

几大网站高适应性文本区的比较

我分别在微博、ant.design组件库、知乎查看了自适应输入框的实现。

几大网站高适应性文本区的比较

我分别在微博、ant.design组件库、知乎查看了自适应输入框的实现。

微博:采用方案二。

未输入时

textarea属性(js获取textarea的行数)插图(3)

输入后

textarea属性(js获取textarea的行数)插图(4)

但是微博的实现在用户体验上有一些缺陷,会动摇!!!

textarea属性(js获取textarea的行数)插图(5)

Ant.design:采用方案二。

体验超级好。

textarea属性(js获取textarea的行数)插图(6)

Zhihu:采用方案3

好像有bug,不过上面也有截图。

textarea属性(js获取textarea的行数)插图(7)

希望本文能帮助到您!

喜欢+转发,让更多人看到这个内容(如果收藏不喜欢,都是耍流氓-_-)

关注{I},享受文章首发体验!

每周集中攻克一个前端技术难点。更多精彩前端内容,私信我回复“教程”

原文链接:http://eux.baidu.com/blog/fe/%e9% AB % 98% E5 % BA % A6 % E8 % 87% AA % E9 % 80% 82% E5 % BA % 94% E7 % 9A % 84% 20

作者:张廷岑

免责声明:本站所有文章内容,图片,视频等均是来源于用户投稿和互联网及文摘转载整编而成,不代表本站观点,不承担相关法律责任。其著作权各归其原作者或其出版社所有。如发现本站有涉嫌抄袭侵权/违法违规的内容,侵犯到您的权益,请在线联系站长,一经查实,本站将立刻删除。

作者:美站资讯,如若转载,请注明出处:https://www.meizw.com/n/113071.html

发表回复

登录后才能评论