高考总分900分是哪个省
2023-04-08
更新时间:2024-09-15 19:10:40作者:匿名
textarea的宽度和高度是如何确定的?参考张鑫旭的文章HTML textarea cols、rows属性与宽高关系研究
所以,我们今天的任务就是思考如何创建一个高度内容自适应的textarea组件。我将介绍实现高度内容自适应文本区域的三个想法。具体代码是textareaAutoSizeSolutions。
这是三种解决方案的概述以及实现思路的介绍。实施方案中遇到的坑,拓展了知识点。点击查看teeeemoji 的演示。
解决方案1 : 调整textarea.style.height两次
textarea的onchange触发resize方法。以下是resize方法的逻辑。
textarea.style.height='自动'; //1.让textarea的高度恢复默认textarea.style.height=textarea.scrollHeight + 'px'; //2.textarea.scrollHeight代表*textarea*内容的实际高度方案2: 使用一个ghostTextarea获取输入框的内容高度,然后将这个高度设置为真实的textarea
GhostTextarea在textarea构建时创建,onchange触发resize方法:
创建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将textarea替换为div,消除各种高度计算逻辑。
方案比较
满分3分,三种方案通过优化在用户体验和兼容性方面均能取得满分。因此,区别仅在于这些解决方案的实施难度。 (仅基于react组件的实现复杂度)。解决方案比较:
毫无疑问,选项1是最好的选择,并且会额外加分作为奖励;
计划调整textarea.style.height一次或两次
渲染一个textarea元素textarea ref={this.bindRef} className={style['textarea'] + ' ' + className} placeholder={placeholder} value={value} onChange={this.handleChange} //参见Here/textarea的onChange事件触发resizehandleChange(e) { this.props.onChange(e.target.value); this.resize(); //看这里} resize事件的实现//重新计算textarea的高度resize() { if (this.inputRef) { console.log('resizing.') this.inputRef.style.height='auto'; this.inputRef.style.height=this.inputRef.scrollHeight + 'px'; } }注意,在componentDidMount时,执行一次resize方法,初始化textarea的高度。
避免渲染两次,导致内容抖动
在React 中,组件receiveProps 将渲染一次。直接调整textarea的高度也会导致浏览器重绘,从而导致两次重绘,而在两次重绘期间,textarea的内容可能会出现抖动。
优化思路:先触发resize,再渲染。用最简单的想法完美解决问题。
解决方案2 : 使用ghostTextarea获取输入框的内容高度,然后将这个高度设置为真实的textarea
实施思路
同时渲染两个文本区域,一个真实文本区域和一个隐藏文本区域
return ( div className={style['comp-textarea-with-ghost']} textarea //这是true ref={this.bindRef} className={style['textarea'] + ' ' + className} placeholder={ placeholder} value={value} onChange={this.handleChange} style={{height}}/textarea //这是GhostTextarea className={style['textarea-ghost']} ref={this.bindGhostRef} onChange={ noop} //div) 在初始化期间复制属性。初始化时必须使用工具方法将textarea属性复制到ghostTextarea。因为textarea的样式也可以在组件外部控制,所以初始化时复制样式是最安全的。
这是要复制的属性列表:
const SIZING_STYLE=['字母间距','行高','字体系列','字体粗细','字体大小','字体样式','制表符大小','文本渲染','文本变换','宽度','文本缩进','上边距','右边距','下边距','左边距','上边距宽度', '边框右宽度','边框底部宽度','边框左宽度','盒子大小'];这是ghostTextarea :的隐藏属性列表
const HIDDEN_TEXTAREA_STYLE={'最小高度': '0','最大高度': '无',height: '0',visibility: '隐藏',overflow: '隐藏',position: '绝对','z-index': '-1000',top: '0',right: '0',};这是复制样式的工具方法
//获取真实文本区域的所有样式函数calculateNodeStyling(node) { const style=window.getCompulatedStyle(node);if (style===null) {return null;}return SIZING_STYLE.reduce((obj, name)={ obj [name]=style.getPropertyValue(name);return obj;}, {});}//复制真实textarea的样式到ghostTextareaexport const copyStyle=function (toNode, fromNode) { const nodeStyling=calculateNodeStyling(fromNode) ;if (nodeStyling===null) {return null;}Object.keys(nodeStyling).forEach(key={toNode.style[key]=nodeStyling[key];});Object.keys(HIDDEN_TEXTAREA_STYLE).forEach( key={ toNode.style.setProperty(key,HIDDEN_TEXTAREA_STYLE[key],'important',);});}textarea的onChange事件先reizes,然后触发change事件
handleChange(e) {this.resize();let value=e.target.value;this.props.onChange(value);} textarea 的调整大小方法
resize() {console.log('resizing.')const height=calculateGhostTextareaHeight(this.ghostRef, this.inputRef);this.setState({height});}calculateGhostTextareaHeight 工具方法
//先将内容设置到ghostTextarea中,然后获取ghostTextarea.scrollHeightexport constcalculateGhostTextareaHeight=function (ghostTextarea, textarea) {if (!ghostTextarea) {return;}ghostTextarea.value=textarea.value ||文本区域.placeholder || 'x'return GhostTextarea.scrollHeight;}优化点
避免渲染两次,导致内容抖动
在react中,组件receiveProps会渲染一次,给textarea设置height属性也会导致浏览器重绘。这会导致两次重绘,并且在两次重绘期间,textarea的内容可能会出现抖动。
下面两个想法都在demo中得到了体现
优化思路1 : 合并帧渲染
使用window.requestAnimationFrame window.cancelAnimationFrame取消第一帧的渲染,直接渲染调整了高度的textarea;
优化思路2 : 减少渲染次数
使用react批量setState方法减少重新渲染功能;在textarea的onChange方法中同时触发两个setState;
更多优化思路
当页面上有多个textarea时,是否可以考虑复用同一个ghostTextarea?解决方案3: 使用div.contenteditable 而不是textarea
实施思路
渲染一个div.contenteditable=true
return ( div className={style['comp-div-contenteditable']} div ref={this.bindRef} className={classname(style['textarea'], className, {[style['empty']]: value})} onChange={this.handleChange} onPaste={this.handlePaste} placeholder={placeholder} contentEditable //div) 获取要编辑的内容:textarea使用textarea.value来获取或设置值,但是它是替换为div后,需要使用div.innerHTML或div.innerText来获取或设置值。
使用div.innerHTML会导致以下两个问题:
在低版本的firfox 上会转码为空白并使用div.innerText 进行兼容性处理。所以使用哪种方法主要还是看需求。
占位符:的实现
div的placeholder属性无效,不会显示。目前有最简单的方法是使用纯CSS实现div的占位符。
.textarea[placeholder]:empty:before { /*两个伪类之前为空*/content: attr(placeholder); /*attr函数*/color: #555;}优化点
删除对富文本的支持
div.contenteditable 默认支持富文本。您可以粘贴或拖动使输入框中出现富文本;
监听div的onPaste事件
处理粘贴(e) { e.preventDefault();让文本=e.clipboardData.getData('text/plain'); //获取纯文本document.execCommand('insertText', false, text); //让浏览处理器执行插入文本操作}handlePaste的更多兼容性处理
几个大型网站的高自适应文本区域对比
我分别在微博、ant.design组件库、知乎查看了自适应输入框的实现。
几个大型网站的高自适应文本区域对比
我分别在微博、ant.design组件库、知乎查看了自适应输入框的实现。
微博:采用方案2
未输入时
输入后
但是微博的实现在用户体验上存在缺陷,会抖动!
ant.design:采用方案2
很棒的经历
知乎:采用方案三
看起来有一个错误。其实上面的截图也有。
用户评论
这篇关于实现高度内容自适应的文本区域的博文太实用了!我一直在找这样的解决方案,希望能早点看到这样的技术分享。
有7位网友表示赞同!
高度内容自适应的文本区域,听起来好高大上,不知道具体操作起来难不难?
有20位网友表示赞同!
用了那么多自适应布局工具,还是觉得手动控制更靠谱,这篇博文给了我希望。
有7位网友表示赞同!
实现高度内容自适应的文本区域,这是不是意味着我可以不用再担心页面排版问题了?
有8位网友表示赞同!
高度内容自适应的文本区域,听起来好像可以解决我写文章时排版乱码的问题。
有7位网友表示赞同!
看了这篇博文,我才发现自己之前用的那些自适应布局方法都是小儿科,哈哈。
有12位网友表示赞同!
实现高度内容自适应的文本区域,这是否意味着我可以摆脱那些繁琐的CSS代码了?
有6位网友表示赞同!
高度内容自适应的文本区域,听起来好复杂,不知道自己能不能学会。
有15位网友表示赞同!
这篇文章介绍的方法好专业,我得好好研究研究,看看能不能应用到我的项目中。
有20位网友表示赞同!
实现高度内容自适应的文本区域,这对我来说是个福音,终于不用再为排版头疼了。
有20位网友表示赞同!
看了这篇博文,我觉得高度内容自适应的文本区域其实也没有那么难,关键是掌握方法。
有6位网友表示赞同!
实现高度内容自适应的文本区域,这个功能对我来说太重要了,希望博主能详细讲解一下。
有16位网友表示赞同!
这篇博文让我对高度内容自适应的文本区域有了新的认识,感谢分享。
有10位网友表示赞同!
高度内容自适应的文本区域,听起来好像可以解决很多网页设计中的问题,期待能学到更多。
有5位网友表示赞同!
实现高度内容自适应的文本区域,这是不是意味着我可以用更少的代码实现更好的效果?
有16位网友表示赞同!
这篇文章太棒了,高度内容自适应的文本区域解决了我一直以来的痛点,感谢分享。
有9位网友表示赞同!
实现高度内容自适应的文本区域,这个技术听起来好高大上,我得好好研究一下。
有5位网友表示赞同!
看了这篇博文,我对高度内容自适应的文本区域有了更深入的了解,感觉自己离专业又近了一步。
有17位网友表示赞同!
实现高度内容自适应的文本区域,这个功能太实用了,希望博主能分享更多相关技巧。
有12位网友表示赞同!