使用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. sql的书写顺序

    例:select t.* from (select *  from t_user where isDelete = 1 limit 0,10) t order by t.qq select from ...

  2. Yahoo!团队:网站性能优化的35条黄金守则

    Yahoo!的 Exceptional Performance团队为改善 Web性能带来最佳实践.他们为此进行了一系列的实验.开发了各种工具.写了大量的文章和博客并在各种会议上参与探讨.最佳实践的核心 ...

  3. kubernets轻量 contain log 日志收集技巧

    首先这里要收集的日志是容器的日志,而不是集群状态的日志 要完成的三个点,收集,监控,报警,收集是基础,监控和报警可以基于收集的日志来作,这篇主要实现收集 不想看字的可以直接看代码,一共没几行,尽量用调 ...

  4. selenium中quit与close方法的区别

    https://blog.csdn.net/lbxoqy/article/details/71981222

  5. 如何使用iTunes制作iPhone铃声

    新版iTunes(iTunes11)推出以后,界面上发生了一些改变,给人带来一种面貌一新的感觉,但也给许多朋友带来一些操作上的不太适应.下面就大家比较关心的iPhone的铃声制作方法,我在iTunes ...

  6. 【Linux_Shell 脚本编程学习笔记六、shell的数值运算】

    1.bc 命令的用法(可以整数也可以小数): bc是 UNIX下的计算器,它也可以用在命令行下面: 例: 给自变量 i 加 1 [root@docker Demo_test]# i= [root@do ...

  7. 如何模拟ip

    展开全部回答查看 https://segmentfault.com/q/1010000002990136 模拟国外ip https://gtmetrix.com/ 登录后才可以切换模拟的地区

  8. C# 开启线程的几种方式

    1.异步委托开启线程 public static void Main(string[] args) { Action<int,int> a=add; a.BeginInvoke(,,nul ...

  9. Java捕获并处理线程失败抛出的异常

    使用 UncaughtExceptionHandler 示例代码如下: Thread.UncaughtExceptionHandler handler = new Thread.UncaughtExc ...

  10. [洛谷P4720] [模板] 扩展卢卡斯

    题目传送门 求组合数的时候,如果模数p是质数,可以用卢卡斯定理解决. 但是卢卡斯定理仅仅适用于p是质数的情况. 当p不是质数的时候,我们就需要用扩展卢卡斯求解. 实际上,扩展卢卡斯=快速幂+快速乘+e ...