使用contenteditable+div模拟textarea文本域实现高度自适应

开发过程中由于需要在发送消息的时候需要有一个可以高度自适应的文本域,一开始是使用textarea并搭配auto-size插件来做到textarea的高度自适应,后来因为遇到一些问题,而且也多加了依赖缺乏可定制,所以决定使用contenteditable来实现。

contenteditable介绍

contenteditable属性规定元素内容是否可编辑,是H5新增的属性,支持情况相当好,基本上所有的浏览器都兼容。

语法:

<element contenteditable="true|false">

实现主要代码如下

代码实现是基于vue来实现的。
html部分:

<template>
<div class="textarea" contenteditable="true"></div>
</template>

CSS部分

<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>

代码解读:

  • 设置-webkit-user-modify属性,是为了在剪切复制的时候会把剪切的内容的格式也一并带过来,由于我们是仿写textarea,是不支持富文本的,所以需要需要将内容格式化成文本格式,而该属性在webkit内核下就可以达到我们的目的。
  • 设置-webkit-user-select属性,是为了解决在测试过程中出现部分IOS手机不支持contenteditable属性的问题。

JS部分:

<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>

代码解读:

  • 其中addEventPaste方法是为了解决非webkit内核对于-webkit-user-select属性支持不好的问题。里面主要是监听黏贴事件然后或者剪切板的文本内容然后再阻止黏贴事件,并将文本内容追加到光标中,并将光标移动到相应的位置。
  • 其中replaceToBreak方法是为了解决在textarea中换行的问题,在该伪textarea中换行是会单独将换行内容放到新的DIV中的,所以,当我们需要对该内容进行格式化处理才行。
  • this.$el.scrollIntoView的作用是为了当使用者将我们的输入框是使用绝对定位放在页面底部的时候而被虚拟键盘遮挡的问题。

issue

  • 使用该组件注意一个问题就是不要在可视化区域的节点上使用-webkit-user-select: none样式,否则会出现当鼠标焦点小时光标和小水滴无法消失的情况

github地址

github项目地址

参考链接

div模拟textarea文本域轻松实现高度自适应
如何让contenteditable元素只能输入纯文本

使用contenteditable+div模拟textarea文本域实现高度自适应的更多相关文章

  1. div模拟textarea文本域轻松实现高度自适应——张鑫旭

    by zhangxinxu from http://www.zhangxinxu.com本文地址:http://www.zhangxinxu.com/wordpress/?p=1362 一.关于tex ...

  2. div模拟textarea文本域轻松实现高度自适应

    <!doctype html> <html lang="en"> <head> <meta charset="UTF-8&quo ...

  3. css之——div模拟textarea文本域的实现

    1.问题的出现: <textarea>标签为表单元素,但一般用于多行文本的输入,但是有一个明显的缺点就是不能实现高度自适应,内容过多就回出现滚动条. 为了实现高度自适应:用div标签来代模 ...

  4. jquery之div模拟textarea文本域轻松实现高度自适应

    <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title> ...

  5. textarea文本域的高度随内容的变化而变化

    用css控制textarea文本域的高度随内容的变化而变化,不出现滚动条. CSS代码: 复制代码 代码如下: .t_area{ width:300px; overflow-y:visible } & ...

  6. DIV仿textarea文本域,contenteditable如何只能输入纯文本

    对于支持HTML5浏览器有2种方法: 1. HTML5 <div contenteditable="plaintext-only"></div> 2.  C ...

  7. div模拟textarea自适应高度

    之前在公司做项目的时候,有这么一个需求,要我写一个评论框,可以随着评论的行数增加而自动扩大,最开始我想用textarea实现,但是后来尝试后发现textarea并不适合,textarea的高度不会随着 ...

  8. textarea文本域轻松实现高度自适应

    转载:http://www.xuanfengge.com/textarea-on-how-to-achieve-a-high-degree-of-adaptive.html 今天需要些一个回复评论的页 ...

  9. div模拟textarea

    有些Weber可能没有用过contenteditable这个属性,如果想编辑一个DIV里面的内容,这个属性是一个非常不错的选择   <div contenteditable="true ...

随机推荐

  1. HTTP Status 500 - Request processing failed; nested exception is java.lang.IllegalArgumentException: Control character in cookie value or attribute.

    HTTP Status 500 - Request processing failed; nested exception is java.lang.IllegalArgumentException: ...

  2. day13-面向对象

    #解决同一类问题,使用面向对象的思想.类是制造对象的模具,类是抽象的,我们能知道它有哪些属性(name,age,saraly),但不知道具体的属性值. #看下面代码:类Penson制造了实例化对象re ...

  3. 用@font-face应用自定义字体

    @font-face格式 @font-face { font-family: <YourWebFontName>; src: <source> [<format>] ...

  4. Arcpy处理修改shapefile FeatureClass 线要素坐标

    需求:在开发的webgis系统中需要将道路矢量数据与谷歌地图瓦片叠加,谷歌地图瓦片在国家测绘局的要求是进行了偏移处理的,人称“火星坐标系GCJ_02”,道路数据是WGS-84坐标系下的经纬度坐标,现在 ...

  5. 学习python-20191230(1)-Python Flask高级编程开发鱼书_第04章_应用、蓝图与视图函数

    视频06: 1.自动导包快捷键——默认为alt + enter 键组合          选中的字符由小写变为大写——Ctrl + Shift + U键组合 2.DataRequired()——防止用 ...

  6. SQL语句:把Excel文件中数据导入SQL数据库中的方法

    1.从Excel文件中,导入数据到SQL数据库情况一.如果接受数据导入的表不存在 select * into jd$ from OPENROWSET('MICROSOFT.JET.OLEDB.4.0' ...

  7. springboot学习笔记:4.logback日志配置

    springboot中日志组件推荐使用logback: 由于springboot内置了logback,所以可以直接在application.properties中配置:如果要功能丰富些,则配置下log ...

  8. deepin 更改默认网卡名称为eth和wlan

    deepin 更改默认的网卡名称为eth和无线网卡名wlan vim /etc/default/grub 在 GRUB_CMDLINE_LINUX_DEFAULT="sqlash quiet ...

  9. 深入JVM内核--JVM运行机制

    JVM启动流程 JVM基本结构 PC寄存器 每个线程拥有一个PC寄存器 在线程创建时 创建 指向下一条指令的地址 执行本地方法时,PC的值为undefined 方法区 保存装载的类信息 类型的常量池 ...

  10. Doc: NetBeans

    NetBeans的最新版本已经更新为Apache NetBeans. 安装JDK 在Mac OS X下,有".dmg"的安装包,可以直接安装.只要JDK的版本大于1.8.0就可以安 ...