開發過程當中因爲須要在發送消息的時候須要有一個能夠高度自適應的文本域,一開始是使用textarea並搭配auto-size插件來作到textarea的高度自適應,後來由於遇到一些問題,並且也多加了依賴缺少可定製,因此決定使用contenteditable來實現。css
contenteditable屬性規定元素內容是否可編輯,是H5新增的屬性,支持狀況至關好,基本上全部的瀏覽器都兼容。html
語法:vue
<element contenteditable="true|false">
代碼實現是基於vue來實現的。
html部分:ios
<template> <div class="textarea" contenteditable="true"></div> </template>
CSS部分git
<style scoped lang="less" rel="stylesheet/less"> .textarea { box-sizing: border-box; min-height: 136px; max-height: 300px; margin-left: auto; margin-right: auto; padding: 3px; outline: 0; border: 1px solid #a0b3d6; font-size: 12px; word-wrap: break-word; overflow-x: hidden; overflow-y: auto; _overflow-y: visible; -webkit-user-modify: read-write-plaintext-only; // 只是編輯text文本,只能解決webkit內核裏面問題,手機端適用 -webkit-user-select: text; // 解決IOS部分手機不支持contenteditable=true屬性問題 p { margin: 0; } } </style>
代碼解讀:github
JS部分:web
<script type="text/babel"> export default { mounted() { this.addInputEvent(); this.addFocusEvent(); this.addEventPaste(this.$el); }, methods: { /** * 監聽鼠標input事件 */ addInputEvent(){ this.$el.addEventListener('input', () => { this.$emit('input', this.getValue()); }) }, /** * 監聽鼠標獲取焦點事件 */ addFocusEvent(){ this.$el.addEventListener('focus', () => { setTimeout(() => { // 解決:若是ios手機使用的不是原生鍵盤(也可能不止IOS手機有這個問題),則會出現鍵盤擋住輸入框問題,當bottom=0的狀況,使用這個屬性就能夠滾動屏幕中央 this.$el.scrollIntoView(true); }, 300); this.$emit('focus'); }) }, /** * 追加 * @param value * @param bool */ appendValue(value, bool) { this.$el.innerText += value; this.$emit('input', this.getValue()); }, /** * 監聽複製事件,去除樣式獲得純文本 */ addEventPaste: function (el) { // 幹掉IE http之類地址自動加連接 try { document.execCommand("AutoUrlDetect", false, false); } catch (e) { } // 監聽複製paste事件,目的是爲了讓-webkit-user-modify屬性兼容IE8,畢竟該屬性在IE兼容性很差 el.addEventListener('paste', function (e) { e.preventDefault(); var text = null; if (window.clipboardData && clipboardData.setData) { // IE text = window.clipboardData.getData('text'); } else { text = (e.originalEvent || e).clipboardData.getData('text/plain') || prompt('在這裏輸入文本'); } // 這裏的目的是爲了將鼠標的光標移動到複製以後文本的末尾的末尾 if (document.body.createTextRange) { if (document.selection) { textRange = document.selection.createRange(); } else if (window.getSelection) { sel = window.getSelection(); var range = sel.getRangeAt(0); // 建立臨時元素,使得TextRange能夠移動到正確的位置 var tempEl = document.createElement("span"); tempEl.innerHTML = "&#FEFF;"; range.deleteContents(); range.insertNode(tempEl); textRange = document.body.createTextRange(); textRange.moveToElementText(tempEl); tempEl.parentNode.removeChild(tempEl); } textRange.text = text; textRange.collapse(false); textRange.select(); } else { // Chrome之類瀏覽器 document.execCommand("insertText", false, text); } }); }, /** * 替換 * @param value */ setValue(value) { this.$el.innerText = value; this.$emit('input', this.getValue()); }, /** * 獲取值 * @returns {*} */ getValue() { return this.getHtmlToText(); }, /** * 獲取HTML轉換以後的文本(去除div標籤,替換<br/>爲換行) * @returns {string} */ getHtmlToText() { return this.replaceToBreak(this.getHtml()); }, /** * 獲取HTML */ getHtml() { return document.querySelector('.textarea').innerHTML }, /** * 替換DIV到換行符 * @returns {string} */ replaceToBreak(html) { html = String(html).replace(/<\/div>/gi, ''); html = html.replace(/<div>(<br>)?(<br\/>)?/gi, '\n'); html = html.replace(/<br>|<br\/>/gi, '\n'); return html; }, /** * 獲取純text文本 * @returns {string} */ getText(){ if (window.navigator.appName.indexOf("Explorer") > -1) return this.$el.innerText; else return this.$el.textContent; } }, } </script>
代碼解讀:瀏覽器
github項目地址babel