使用contenteditable+div模拟textarea文本域实现高度自适应
使用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地址
参考链接
使用contenteditable+div模拟textarea文本域实现高度自适应的更多相关文章
- div模拟textarea文本域轻松实现高度自适应——张鑫旭
by zhangxinxu from http://www.zhangxinxu.com本文地址:http://www.zhangxinxu.com/wordpress/?p=1362 一.关于tex ...
- div模拟textarea文本域轻松实现高度自适应
<!doctype html> <html lang="en"> <head> <meta charset="UTF-8&quo ...
- css之——div模拟textarea文本域的实现
1.问题的出现: <textarea>标签为表单元素,但一般用于多行文本的输入,但是有一个明显的缺点就是不能实现高度自适应,内容过多就回出现滚动条. 为了实现高度自适应:用div标签来代模 ...
- jquery之div模拟textarea文本域轻松实现高度自适应
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title> ...
- textarea文本域的高度随内容的变化而变化
用css控制textarea文本域的高度随内容的变化而变化,不出现滚动条. CSS代码: 复制代码 代码如下: .t_area{ width:300px; overflow-y:visible } & ...
- DIV仿textarea文本域,contenteditable如何只能输入纯文本
对于支持HTML5浏览器有2种方法: 1. HTML5 <div contenteditable="plaintext-only"></div> 2. C ...
- div模拟textarea自适应高度
之前在公司做项目的时候,有这么一个需求,要我写一个评论框,可以随着评论的行数增加而自动扩大,最开始我想用textarea实现,但是后来尝试后发现textarea并不适合,textarea的高度不会随着 ...
- textarea文本域轻松实现高度自适应
转载:http://www.xuanfengge.com/textarea-on-how-to-achieve-a-high-degree-of-adaptive.html 今天需要些一个回复评论的页 ...
- div模拟textarea
有些Weber可能没有用过contenteditable这个属性,如果想编辑一个DIV里面的内容,这个属性是一个非常不错的选择 <div contenteditable="true ...
随机推荐
- [NOIP 2002普及组]产生数(floyd+高精度)
https://www.luogu.org/problem/P1037 题目描述 给出一个整数 n(n<1030) 和 k 个变换规则(k<=15). 规则: 一位数可变换成另一个一位数: ...
- 单调栈and单调队列(此文太多坑了,以后再填)
单调栈 单调栈是一种特殊的栈,特殊之处在于栈内的元素都保持一个单调性,可能为单调递增,也可能为单调递减. 性质: 单调栈里的元素具有单调性 元素加入栈前,会在栈顶端把破坏栈单调性的元素都删除 使用单调 ...
- mysql自定义函数统计订单状态:GET_ORDER_STATUS()
DELIMITER $$ USE `local_hnyz`$$ DROP FUNCTION IF EXISTS `GET_ORDER_STATUS`$$ CREATE DEFINER=`root`@` ...
- Spring Cloud服务消费者(rest+ribbon)
在上一篇文章,讲了服务的注册和发现.在微服务架构中,业务都会被拆分成一个独立的服务,服务与服务的通讯是基于http restful的.Spring cloud有两种服务调用方式,一种是ribbon+r ...
- 如何使用css伪类,实现div左上角出现封面等提示信息
HTML <div class="ui-cover-tip”><div> CSS .ui-cover-tip{ position: relative; width: ...
- LinkedList源码剖析
LinkedList简介 LinkedList是基于双向循环链表(从源码中可以很容易看出)实现的,除了可以当做链表来操作外,它还可以当做栈.队列和双端队列来使用. LinkedList同样是非线程安全 ...
- tomcat打印接口延迟时间
项目中有些页面时延不稳定,需要看每次接口调用时延,怎么看,有两种方法:一种是直接去catalina.out日志中看,一种是直接去localhost_access_log日志中看,第一种需要在代码中实现 ...
- python实现使用代码进行代理配置
#!/usr/local/bin/python3.7 import urllib.request import urllib.parse # 创建handler handler = urllib.re ...
- StringTokenizer(字符串分隔解析类型)
java.util.StringTokenizer 功效:将字符串以定界符为界,分析为一个个的token(可理解为单词),定界符可以自己指定. 1.构造函数. 1. StringTokenizer( ...
- Visual Studio通过Cordova支持混合跨平台移动开发
Microsoft在Visual Studio 2013 Update 2中添加了对混合跨平台移动应用程序的本地支持. Microsoft早在2011年就已经开始了与PhoneGap的合作,那时候是为 ...