Vue 使用div contenteditable属性模拟输入框
使用div模拟输入框的原因:input不能让文本换行、textarea高度始终固定需要配合js才能自适应文本高度,使用div模拟输入框,可以让高度自适应文本内容。首先还是先介绍一下相关属性:contenteditable:true | false | plaintext-only true: 富文本编辑(可粘贴html格式的) ...
使用div模拟输入框的原因:input不能让文本换行、textarea高度始终固定需要配合js才能自适应文本高度,使用div模拟输入框,可以让高度自适应文本内容。
首先还是先介绍一下相关属性:
contenteditable:true | false | plaintext-only
true: 富文本编辑(可粘贴html格式的)
false: 不可编辑
plaintext-only: 纯文本编辑
user-modify: read-only | read-write | write-only(基本浏览器都不支持) | read-write-plaintext-only
read-only: 内容只可读
read-write:可读写(带有html样式的)
read-write-plaintext-only: 可读写,但是丢失粘贴文本的样式(纯文本)
user-modify和contenteditable具有相同的效果,只需要设置一个即可,目前只有webkit内核浏览器支持read-write-plaintext-only这个值,因此使用时其实是:
-webkit-user-modify: read-write-plaintext-only
contenteditable="plaintext-only"和CSS的-webkit-user-modify: read-write-plaintext-only一样
常见问题
- 光标位置一直在最前面的问题
keepLastIndex(obj) { if (window.getSelection) { //ie11 10 9 ff safari obj.focus(); //解决ff不获取焦点无法定位问题 var range = window.getSelection(); //创建range range.selectAllChildren(obj); //range 选择obj下所有子内容 range.collapseToEnd(); //光标移至最后 } else if (document.selection) { //ie10 9 8 7 6 5 var range = document.selection.createRange(); //创建选择对象 //var range = document.body.createTextRange(); range.moveToElementText(obj); //range定位到obj range.collapse(false); //光标移至最后 range.select(); } }
- 回车发送输入框内容
<div class="input-msg" v-text="innerText" ref="msg" contenteditable="plaintext-only" @input="changeText" @keydown.enter.prevent="enterMsg"></div> <!-- 设置keydown事件,Ctrl+Enter同理 -->
- 内容无法清空。监听文本的内容,监听到空的时候清空div节点内的html。
watch: { value(newvalue) { if (!newvalue) // 清空节点内所有html来清空文本 this.$refs.msg.innerHTML = ''; } else { this.keepLastIndex(this.$refs.msg); } } },
- 清空内容后无法再次聚焦的问题。原因:可能是css没有设置最小高度,清空内容后导致高度崩塌。解决方法:添加min-height属性.
.input-msg { line-height: 17px; min-height: 17px; border: 0; display: block; flex: 1; width: 0; max-height: 57px; overflow-y: scroll; overflow-x: hidden; background-color: #f9f8fa; padding: 2px 2px 0 2px; user-select: text; -webkit-user-modify: read-write-plaintext-only; }
- 空格的判断,chrome70与chrome49的空格存在区别,chrome70是正常的空格符而chrome49为
结合一下上述代码(vue)let blank = this.inputmsg.split(' ').every(n => { return /^( )+$/.test(n); // 针对空格为 的情况 }) || this.inputmsg.trim().length === 0; // 普通空格的情况
<template> <div class="input-msg" ref="msg" contenteditable="plaintext-only" @input="changeText" @keydown.enter.prevent="enterMsg"></div> </template> <script> export default { name: 'editDiv', props: { value: { type: String, default: '' } }, watch: { value(newvalue) { console.log(newvalue); // if (!this.isLocked && !this.innerText) { if (!newvalue) { // 清空节点内所有html来清空文本 this.$refs.msg.innerHTML = ''; } else { this.keepLastIndex(this.$refs.msg); } } }, methods: { changeText(event) { this.$emit('input', this.$el.innerHTML); }, enterMsg(event) { this.$emit('send'); }, keepLastIndex(obj) { if (window.getSelection) { //ie11 10 9 ff safari obj.focus(); //解决ff不获取焦点无法定位问题 var range = window.getSelection(); //创建range range.selectAllChildren(obj); //range 选择obj下所有子内容 range.collapseToEnd(); //光标移至最后 } else if (document.selection) { //ie10 9 8 7 6 5 var range = document.selection.createRange(); //创建选择对象 //var range = document.body.createTextRange(); range.moveToElementText(obj); //range定位到obj range.collapse(false); //光标移至最后 range.select(); } } } }; </script> <style scoped> .input-msg { line-height: 17px; min-height: 17px; border: 0; display: block; flex: 1; width: 0; max-height: 57px; overflow-y: scroll; overflow-x: hidden; background-color: #f9f8fa; padding: 2px 2px 0 2px; user-select: text; -webkit-user-modify: read-write-plaintext-only; } .input-msg:focus { border: 0; outline: 0; } .input-msg:empty:before { content: ''; } </style>
调用组件<template> <div id="app"> <div class="box scroll-hover" ref="list"> <p v-for="(item, index) in msglist" :key="index"> {{ item.id }}. {{item.msg}} </p> </div> <div class="sendmsg"> <edit-div v-model="inputmsg" @send="send"></edit-div> </div> <textarea name="" id="" resize="none" v-model="tips"></textarea> </div> </template> <script> export default { name: 'app', components: { EditDiv: () => import(/* webpackChunkName: "editdiv" */ '@/components/EditDiv.vue') }, data() { return { inputmsg: '', msglist: [], index: 0, tips: '' }; }, watch: { inputmsg: function(newvale) { console.log('bbb'); } }, methods: { send() { let blank = this.inputmsg.split(' ').every(n => { return /^( )+$/.test(n); // 针对空格为 的情况 }) || this.inputmsg.trim().length === 0; // 普通空格的情况 if (blank) { this.tips = '内容不能为空'; return; } this.msglist.push({ id: this.index++, msg: this.inputmsg }); this.inputmsg = ''; this.tips = '发送成功'; this.$nextTick(() => { this.$refs.list.scrollTop = this.$refs.list.scrollHeight; }); } } }; </script> <style> #app { font-family: 'Avenir', Helvetica, Arial, sans-serif; -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; color: #2c3e50; margin: 0 auto; width: 1000px; } ::-webkit-scrollbar { width: 4px; height: 4px; } ::-webkit-scrollbar-thumb { background: rgba(48, 48, 48, 0); border-radius: 5px; height: 30px; transition: all 0.4s ease-out; } /* 鼠标移入出现滚动条,移出隐藏效果 */ .scroll-hover { overflow: scroll; } .scroll-hover:hover::-webkit-scrollbar-thumb { background: rgba(48, 48, 48, 0.4); } .sendmsg { width: 300px; line-height: 30px; display: flex; } .inputm { word-break: break-all; width: 200px; min-height: 40px; resize: none; } </style>
更多推荐
所有评论(0)