整合營銷服務商

          電腦端+手機端+微信端=數據同步管理

          免費咨詢熱線:

          textarea中提示文本的實現,默認顯示,點擊消失

          美解決textarea輸入框提示文字,必須添加默認內容

          <input/>有placeholder標簽,可以添加提示文字 ,但是<textarea>沒有;所以提出以下解決方案

          1.

          <textarea id="t" rows="20" cols="20"></textarea>
          <script>
          	var t = document.getElementById('t');
          	let aaa = '項目需求概要';
          	t.innerHTML=aaa;
          	t.onfocus = function(){
          		if(this.value == aaa){this.value = ''}
          	};
          	 
          	t.onblur = function(){
          		if(this.value == ''){
          			this.value = aaa;
          		}
          	};
          </script>
          

          2.

          <textarea cols="50" rows="5" id="textarea" onfocus="if(value=='限100字'){value=''}" onblur="if (value ==''){value='限100字'}">限100字</textarea> 
          

          3.

          這你需要把id='note'的div 定位到textarea上面

           <div style="position:relative;">
           <textarea class="textarea" onfocus="document.getElementById('note').style.display='none'" onblur="if(value=='')document.getElementById('note').style.display='block'"></textarea>
           <div id="note" class="note">
           <font color="#777">項目需求概要</font>
           </div>
           </div>
          

          4.

          景介紹

          正如我們所知道的 textarea 是一個行內塊元素 display: inline-block 并且它的默認寬高由 cols & rows 決定, 也就是說 textarea 的 height 并不會自適應于內容長度.

          textarea 的寬高是如何決定的? 參考張鑫旭的文章 HTML textarea cols,rows屬性和寬度高度關系研究

          那么, 我們今天的任務就是來思考如何創建一個 高度內容自適應的 textarea 組件,我將介紹三種思路實現 高度內容自適應的 textarea,具體代碼 textareaAutoSizeSolutions

          方案概要

          這是三種方案的概述和實現思路的簡介, 實現方案 & 遇到的坑 & 拓展知識點, 點擊查看 teeeemoji 的 demo.

          方案一: 兩次調整 textarea.style.height

          textarea 的 onchange 觸發 resize 方法,下面是 resize 方法的邏輯

          textarea.style.height = 'auto';// 1. 讓 textarea 的高度恢復默認
          textarea.style.height = textarea.scrollHeight + 'px';// 2. textarea.scrollHeight 表示 *textarea* 內容的實際高度
          

          方案二: 利用一個 ghostTextarea 獲得輸入框內容高度, 再將這個高度設置給真實的 textarea

          textarea 構建時創建 ghostTextarea, onchange 觸發 resize 方法:

          1. 創建 textarea 的時候, 同時創建一個一模一樣的隱藏 ghostTextarea;
          2. ghostTextarea 的屬性全部克隆自 textarea, 但是 ghostTextarea 是 隱藏 的, 并且 ghostTextarea.style.height = 0; 也就是說 ghostTextarea.scrollHeight 就是 textarea 中內容的真是高度。

          resize 方法處理流程:

          1. textarea.value 先設置給 ghostTextarea,
          2. 拿到 ghostTextarea.scrollHeight
          3. 將 textarea.style.height = ghostTextarea.scrollHeight

          方案三: 使用 (div | p | ...).contenteditable 代替 textarea 作為輸入框

          div 是塊級元素, 高度本身就是內容自適應的(除非設置 max-width or min-widht) 使用 contenteditable 讓 div 代替 textarea, 省去各種計算高度的邏輯。

          方案對比

          滿分3分, 三種方案通過優化, 在用戶體驗和兼容性上都能達到滿分. 因此差別僅僅在于這幾個方案的實現難度. (僅僅是基于 react 組件的實現復雜度). 方案對比:

          毫無疑問方案一是最優選擇, 多加1分以示獎勵;

          方案一兩次調整 textarea.style.height

          實現思路

          1. 渲染一個 textarea 元素
          <textarea
           ref={this.bindRef}
           className={style['textarea'] + ' ' + className}
           placeholder={placeholder}
           value={value}
           onChange={this.handleChange} // 看這里
          />
          
          1. textarea 的 onChange 事件觸發 resize
          handleChange(e) {
           this.props.onChange(e.target.value);
           this.resize();	// 看這里
          }
          
          1. resize 事件的實現
          // 重新計算 textarea 的高度
          resize() {
           if (this.inputRef) {
           console.log('resizing...')
           this.inputRef.style.height = 'auto';
           this.inputRef.style.height = this.inputRef.scrollHeight + 'px';
           }
          }
          
          1. 注意 componentDidMount 的時候, 執行一次 resize 方法, 初始化 textarea 的高度哦.

          優化點

          避免兩次渲染,造成內容抖動

          在 react 中, 組件 receiveProps 的時候會 render 一次, 直接調整 textarea 的 height 也會瀏覽器的重繪,那么就會造成兩次重繪, 并且兩次重繪的時候, textarea 的內容可能會發生抖動.

          優化思路:先觸發 resize 后觸發 render 用最簡單的思路完美解決問題

          方案二: 利用一個 ghostTextarea 獲得輸入框內容高度, 再將這個高度設置給真實的 textarea

          實現思路

          同時渲染兩個 textarea, 一個真實 textarea 一個隱藏 textarea

          return (
           <div className={style['comp-textarea-with-ghost']}>
           <textarea // 這個是真的
           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 的樣式再組件外也能控制, 因此初始化的時候 copy style 是最安全的。

          這是所以要拷貝的屬性的列表:

          const SIZING_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-right-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',
          };
          

          這是拷貝 style 的工具方法

          // 拿到真實 textarea 的所有 style
          function calculateNodeStyling(node) {
          	const style = window.getComputedStyle(node);
          	if (style === null) {
          		return null;
          	}
          	return SIZING_STYLE.reduce((obj, name) => {
          		obj[name] = style.getPropertyValue(name);
          			return obj;
          	}, {});
          }
          // 拷貝 真實 textarea 的 style 到 ghostTextarea
          export 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 事件 先 reize 再觸發 change 事件

          handleChange(e) {
          	this.resize();
          	let value = e.target.value;
          	this.props.onChange(value);
          }
          

          textarea 的 resize 方法

          resize() {
          	console.log('resizing...')
          	const height = calculateGhostTextareaHeight(this.ghostRef, this.inputRef);
          	this.setState({height});
          }
          

          calculateGhostTextareaHeight 工具方法

          // 先將內容設置進 ghostTextarea, 再拿到 ghostTextarea.scrollHeight
          export const calculateGhostTextareaHeight = function (ghostTextarea, textarea) {
          	if (!ghostTextarea) {
          		return;
          	}
          	ghostTextarea.value = textarea.value || textarea.placeholder || 'x'
          	return ghostTextarea.scrollHeight;
          }
          

          優化點

          避免兩次渲染,造成內容抖動

          在 react 中, 組件 receiveProps 的時候會 render 一次, 給 textarea 設置 height 屬性也會瀏覽器的重繪.那么就會造成兩次重繪, 并且兩次重繪的時候, textarea 的內容可能會發生抖動.

          下面兩種思路, 在 demo 中均有體現

          優化思路一: 合并禎渲染

          使用 window.requestAnimationFrame & window.cancelAnimationFrame 來取消第一禎的渲染, 而直接渲染高度已經調整好的 textarea;

          優化思路二: 減少渲染次數

          利用 react 批處理 setState 方法, 減少 rerender 的特性; 在 textarea onChange 方法中同時觸發兩個 setState;

          更多優化思路

          • 頁面存在多個 textarea 的時候, 能不能考慮 復用同一個 ghostTextarea

          方案三: 使用 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 來取值 or 設置值, 但換成了 div 之后, 就要使用 div.innerHTML or div.innerText 來取值 or 設置值.

          使用 div.innerHTML 會出現以下兩種問題:

          • & 會被轉碼成 &
          • 空白符合并 使用 div.innerText 在低版本 firfox 上要做兼容處理.

          因此使用哪種方式 主要看需求.

          placeholder 的實現:

          div 的 placeholder 屬性是無效, 不會顯示出來的, 現存一種最簡單的方式, 使用純 css 的方式實現 div 的 placeholder

          .textarea[placeholder]:empty:before { /*empty & before 兩個偽類*/
          	content: attr(placeholder); /*attr 函數*/
          	color: #555;
          }
          

          優化點

          去除支持富文本

          div.contenteditable 是默認支持富文本的, 可能會以 粘貼 or 拖拽 讓輸入框出現富文本;

          監聽 div 的 onPaste 事件

          handlePaste(e) {
           e.preventDefault();
           let text = e.clipboardData.getData('text/plain'); // 拿到純文本
           document.execCommand('insertText', false, text); // 讓瀏覽器執行插入文本操作
          }
          

          handlePaste 的更多兼容性處理

          幾個大網站的高度自適應 textarea 對比

          我分別查看了微博, ant.design組件庫, 知乎 的自適應輸入框的實現.

          幾個大網站的高度自適應 textarea 對比

          我分別查看了微博, ant.design組件庫, 知乎 的自適應輸入框的實現.

          微博: 采用方案二

          未輸入時

          輸入后

          但是微博的實現存在用戶體驗上的缺陷, 會抖動!!!

          ant.design: 采用方案二

          體驗超級棒哦

          知乎: 采用方案三

          看上去竟然存在 bug , 其實上面的截圖也有

          希望本文能幫助到您!

          點贊+轉發,讓更多的人也能看到這篇內容(收藏不點贊,都是耍流氓-_-)

          關注 {我},享受文章首發體驗!

          每周重點攻克一個前端技術難點。更多精彩前端內容私信 我 回復“教程”

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

          作者:張庭岑

          extarea內容某個高度之內自適應,超過指定高度固定,今天講解下實現textarea內容自適應的方法

          實現方法如下:

          html:

          <textarea id="textarea" ></textarea>

          css:

          javascript:

          效果圖:


          主站蜘蛛池模板: 国产精品亚洲一区二区三区在线| 蜜桃传媒一区二区亚洲AV| 日产亚洲一区二区三区| 消息称老熟妇乱视频一区二区| 日本伊人精品一区二区三区 | 国产乱子伦一区二区三区| 国产av福利一区二区三巨| 人妻无码第一区二区三区| 内射白浆一区二区在线观看| 国产一区二区免费| 精品免费久久久久国产一区| 日韩精品无码中文字幕一区二区 | 国产福利91精品一区二区三区| 立川理惠在线播放一区| 日韩在线一区视频| 国产精品视频一区麻豆| 久久99精品一区二区三区| 国产高清在线精品一区小说| 无码人妻一区二区三区免费视频 | 中文字幕一区二区三匹| 国产精品一区二区久久精品| 无码一区二区三区免费| 无码AV天堂一区二区三区| 中文字幕一区二区三| 韩国福利一区二区三区高清视频| 国产精品成人99一区无码| 爱爱帝国亚洲一区二区三区| 3d动漫精品成人一区二区三| 在线播放一区二区| 亚洲AV成人一区二区三区在线看| 精品国产一区AV天美传媒| 亚洲av日韩综合一区二区三区| 久久青青草原一区二区| 美女AV一区二区三区| 精品少妇一区二区三区在线| 亚洲AV无码一区东京热| 蜜桃AV抽搐高潮一区二区| 精品国产日产一区二区三区| 亚洲一区二区三区写真| 区三区激情福利综合中文字幕在线一区| 成人区人妻精品一区二区不卡视频|