vue项目中文本域textarea跟随内容自动改变高度,并且阻止默认的回车换行事件
作者:互联网
先来几张简单图:
基本思路:
要想实现文本域跟随内容自动高度,这里准备两个textarea文本域,
文本域1:固定高度,超出部分滚动,设置绝对定位放到文本域2下面不做显示,但是注意不要设置为隐藏,否怎会读取不到宽高
文本域2:通过css设置初始宽高与文本域1一样,相对定位覆盖在文本域1上,使用vue的属性绑定 :style="{height: inputH + 'px'}" 动态的改变其高度,建议最低高度不低于文本域1的高度。
通过 v-model="source.txt" 将文本域2中输入的内容写入文本域1中,因文本域1固定高度超出滚动,然后通过vue的 watch 监听数据 source.txt 的变化,在监听中读取文本域1的滚动高度$refs.transInput0.scrollHeight 并设置文本域2的高度 this.inputH = this.$refs.transInput0.scrollHeight,为防止输入过程中出现频繁的高度变化造成闪烁设置延时 setTimeout(() => {}, 1000) 和 (tims - this.times < 1000),即停止输入1000ms后或两次输入间隔超过1000ms时才会进行高度的设置变化。
具体代码:
<template> <div class="part-top"> <div class="trans-wrap layui-row"> <div class="layui-col-md6 trans-left"> <div class="input-wrap"> <textarea ref="transInput0" v-model="source.txt" :class="['layui-textarea', 'txt0', {'more': source.txt.length > 23}]" /> <textarea ref="transInput" v-model="source.txt" :class="['layui-textarea', 'txt', {'more': source.txt.length > 23}]" :style="{height: inputH + 'px'}" @keydown="interpretListen" /> <span v-show="source.txt" class="layui-icon layui-icon-close" @click="clear()" /> </div> </div> <div class="layui-col-md6 trans-right"> <div ref="transOutput0" :class="['output-wrap', 'out0', {'more': target.txt.length > 25}]"> <p>{{ target.txt }}</p> </div> <div ref="transOutput" :class="['output-wrap', {'more': target.txt.length > 25}]" :style="{height: outputH + 'px'}"> <p>{{ target.txt }}</p> </div> </div> </div> </div> </template> <script> export default { name: 'IdentifyPane', props: { name: { type: String, default: '' }, moduleId: { type: String, default: '' }, iUri: { type: String, default: '' }, index: { type: Number, default: -1 }, enabled: { type: String, default: 'false' } }, data() { return { // 初始化标识 完成后即为false isInit: true, // 是否显示当前模块 isShow: false, datas: {}, inputH: 130, outputH: 155, source: { flag: 'source', txt: '' }, target: { flag: 'target', txt: '' }, langsBox: { show: false, for: '' }, times: 0, timeout: undefined } }, watch: { // 动态监听数据是否变化 'source.txt': function(newVal, oldVal) { // console.log(`new value -> ${newVal}\nold value -> ${oldVal}`) this.resetTransHeight() }, 'target.txt': function(newVal, oldVal) { // console.log(`new value -> ${newVal}\nold value -> ${oldVal}`) this.resetTransHeight() }, isShow: function(newVal, oldval) { if (newVal) { setTimeout(() => { // console.log(`${this.$refs.transInput.offsetWidth} ->>>- ${this.$refs.transOutput.offsetWidth}`) this.$refs.transInput0.style.width = this.$refs.transInput.offsetWidth + 'px' this.$refs.transOutput0.style.width = this.$refs.transOutput.offsetWidth + 'px' }, 100) } } }, created() { this.source.lang = this.languages[1] this.target.lang = this.languages[0] // console.log(this.source) // console.log(this.target) this.datas[this.moduleId] = [] }, mounted() { }, methods: { showModule() { this.isShow = true }, // 点击面板标题 显示(展开)/隐藏(收起)面板 showHidePanel(index) { this.datas[this.moduleId][index]['isShow'] = !this.datas[this.moduleId][index]['isShow'] this.$forceUpdate() }, resetTransHeight() { const tims = new Date().getTime() if (!this.timeout) { this.timeoutReset() } if (this.times === 0) { this.times = tims } else { if (tims - this.times < 1000) { clearTimeout(this.timeout) this.timeoutReset() this.times = tims } } }, timeoutReset() { this.timeout = setTimeout(() => { this.timeout = undefined const ish = this.$refs.transInput0.scrollHeight const osh = this.$refs.transOutput0.scrollHeight console.log(`input height -> ${ish}\noutput height -> ${osh}`) if (ish > osh) { this.inputH = ish this.outputH = ish + 25 } else { this.inputH = osh - 25 this.outputH = osh } this.times = 0 }, 1000) }, // 发送消息 interpret() { console.log(`interpret ->>> `) }, // 清空输入和翻译结果 clear() { this.source.txt = '' this.target.txt = '' }, // 文本输入默认回车换行改为发送消息 interpretListen(event) { console.log(`key down interpret listen ->>>`) if (event.keyCode === 13) { this.interpret() // 调用发送消息 event.preventDefault() // 阻止浏览器默认的换行操作 return false } } } } </script> <style scoped> .trans-wrap { width: 100%; margin: 6px 0; } .trans-wrap .input-wrap, .trans-wrap .output-wrap { width: 100%; padding: 10px; } .trans-wrap .input-wrap { border: 1px solid #dcdcdc; } .trans-wrap .input-wrap>textarea { resize: none; height: 130px; min-height: 100%; font-size: 22px; display: inline-block; width: calc(100% - 20px); } .trans-wrap .input-wrap>.layui-icon-close { top: 15px; right: 5px; width: 30px; display: inline-block; } .trans-wrap .output-wrap { background: #f0f0f0; font-size: 22px; height: 155px; } .trans-wrap .output-wrap.more, .trans-wrap .input-wrap>textarea.more { font-size: 16px; line-height: 20px; } .trans-wrap .output-wrap::-webkit-scrollbar, .trans-wrap .input-wrap>textarea::-webkit-scrollbar { /* 滚动条整体样式 */ display: none; } .trans-wrap .output-wrap.out0, .trans-wrap .input-wrap>textarea.txt0 { position: absolute; min-height: unset; z-index: -1; } /* 旋转180° */ .rotate180 { transform: rotate(180deg); -ms-transform: rotate(180deg); /* IE 9 */ -moz-transform: rotate(180deg); /* Firefox */ -webkit-transform: rotate(180deg); /* Safari 和 Chrome */ -o-transform: rotate(180deg); /* Opera */ } </style>
每天进步一点点,点滴记录,积少成多。
以此做个记录,
如有不足之处还望多多留言指教!
标签:vue,textarea,refs,文本,height,wrap,txt,trans,回车 来源: https://www.cnblogs.com/jindao3691/p/16145026.html