vue1.0 @input动作中文输入无响应的解决方案

本文解决了一个Vue1.0项目中遇到的问题:使用@input监听文本框中文输入时,无法立即获取到输入内容。通过设置setTimeout延时10毫秒的方法解决了这一难题。

用vue1.0开发项目的时候,发现一个文本框的@input,在敲入中文之后,没有取回文本框中的中文,只能拿回一堆空值

解决方案是setTimeout 延迟个10毫秒之后再去取内容,就能取到了

<think>我们正在使用Vue3和Element Plus(假设使用Element Plus,因为el-input通常来自Element UI/Plus) 目标:在el-input的textarea类型中获取当前光标所在行号 思路: 1. 我们需要监听textarea的光标位置变化(包括点击和键盘事件) 2. 通过计算文本中换行符的数量来确定行号(因为文本域本身有直接提供行号的属性) 具体步骤: - 给el-input绑定ref,以便获取DOM元素 - 监听textarea的input事件(内容变化)和cursor事件(但注意,标准textarea有专门的光标事件,我们可以用selectionchange事件,但兼容性不好,所以通常使用input、click和keyup事件来捕获光标位置) - 在事件处理函数中,获取textarea的selectionStart属性(光标开始位置),然后计算从文本开始到该位置之间换行符的个数(换行符为'\n'),行号 = 换行符个数 + 1 注意:由于el-input是组件,我们需要获取内部的textarea元素。在Element Plus中,el-input的textarea类型内部就是一个textarea,我们可以通过ref获取到组件实例,然后通过组件的ref找到textarea元素。 实现: 1. 模板部分: <el-input ref="inputRef" type="textarea" v-model="text" @input="handleInput" @click="handleCursorChange" @keyup="handleCursorChange" /> 2. 在setup中: import { ref, nextTick } from 'vue' const inputRef = ref(null) const text = ref('') const currentLine = ref(1) // 当前行号 // 获取光标位置并计算行号 const getCurrentLine = () => { // 获取textarea元素 const textarea = inputRef.value?.textarea if (!textarea) return // 获取光标位置 const cursorPosition = textarea.selectionStart // 截取从开始到光标位置的文本 const textBeforeCursor = text.value.substring(0, cursorPosition) // 计算换行符的个数 const lineNumber = (textBeforeCursor.match(/\n/g) || []).length + 1 currentLine.value = lineNumber } // 在input事件中,我们可能需要更新行号(因为输入可能导致换行符增加) // 同时,在点击和键盘事件后,光标位置改变,我们也需要更新行号 const handleInput = () => { // 由于input事件触发时,DOM可能还未更新,所以使用nextTick确保获取到最新的值 nextTick(() => { getCurrentLine() }) } const handleCursorChange = () => { getCurrentLine() } 但是,注意:在Vue3中,我们使用Composition API,并且Element Plus的el-input组件内部暴露了textarea元素作为组件的textarea属性(通过ref获取组件实例,然后.textarea即可得到textarea DOM元素) 另外,我们也可以使用watch来监听text的变化,但是光标位置变化不一定伴随文本变化(比如用方向键移动光标),所以我们需要单独处理光标移动事件(click和keyup)。 然而,keyup事件并不能捕获鼠标点击后光标移动(所以我们需要click事件),而click事件也不能捕获键盘移动光标(所以我们需要keyup)。另外,还可以考虑使用selectionchange事件,但兼容性需要处理。 为了更全面的捕获光标变化,我们可以同时监听click、keyup和keydown(但keydown时光标位置可能还未改变,所以通常用keyup)。另外,Element Plus的el-input可能有提供所有原生事件,我们可以使用.native修饰符,但在Vue3中,对于组件的原生事件,我们需要使用@click.native吗?实际上,在Element Plus中,我们可以直接绑定在组件上,它会透传给内部的textarea。但是,对于el-input,我们绑定的click和keyup事件实际上会作用在内部的textarea上,因为el-input组件内部处理了这些事件并传递给了textarea。 不过,为了确保能够监听到,我们可以直接给el-input绑定这些事件。 但是,注意:在el-input上绑定click和keyup事件,实际上是绑定在组件根元素(一个div)上,而不是textarea上。所以我们需要通过ref获取textarea元素,然后给textarea元素添加事件监听。 因此,我们可以在onMounted中手动添加事件监听: 另一种做法: 在onMounted中: onMounted(() => { const textarea = inputRef.value?.textarea if (textarea) { textarea.addEventListener('click', handleCursorChange) textarea.addEventListener('keyup', handleCursorChange) } }) 在onUnmounted中移除事件监听。 但是,考虑到可能textarea在组件更新时被重新创建(虽然不太可能),我们可以使用watchEffect来动态添加和移除事件。 为了简单,我们使用在mounted中绑定,unmounted中移除。 完整代示例: 注意:由于我们使用了ref获取textarea,确保组件已经渲染完成(在mounted之后) 实现: 在Vue3的setup中:</think># Vue3中获取el-input textarea光标所在行号 在Vue3中获取el-input textarea类型的光标所在行号,需要结合原生DOM操作和Vue的响应式系统。下面我将提供一个完整的解决方案。 ## 解决方案思路 1. 使用`ref`获取el-input实例 2. 监听textarea的`input`、`click`和`keyup`事件 3. 通过`selectionStart`属性获取光标位置 4. 计算从文本开始到光标位置之间的换行符数量 5. 行号 = 换行符数量 + 1 ## 完整实现代 ```html <!DOCTYPE html> <html lang="zh-CN"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Vue3获取textarea光标行号</title> <link rel="stylesheet" href="https://unpkg.com/element-plus/dist/index.css"> <script src="https://unpkg.com/vue@3/dist/vue.global.js"></script> <script src="https://unpkg.com/element-plus/dist/index.full.js"></script> <style> body { font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif; background: linear-gradient(135deg, #f5f7fa 0%, #c3cfe2 100%); padding: 20px; min-height: 100vh; margin: 0; } .container { max-width: 800px; margin: 0 auto; background: white; border-radius: 12px; box-shadow: 0 8px 30px rgba(0, 0, 0, 0.12); overflow: hidden; } .header { background: linear-gradient(90deg, #409eff, #66b1ff); color: white; padding: 20px 30px; } .header h1 { margin: 0; font-weight: 600; font-size: 1.8rem; } .header p { margin: 8px 0 0; opacity: 0.9; } .content { padding: 30px; } .input-container { position: relative; margin-bottom: 25px; } .info-panel { display: flex; justify-content: space-between; margin-top: 15px; padding: 15px; background: #f8fafc; border-radius: 8px; font-size: 1.1rem; } .info-item { display: flex; flex-direction: column; } .info-label { font-size: 0.9rem; color: #606266; margin-bottom: 5px; } .info-value { font-weight: 600; color: #409eff; font-size: 1.4rem; } .code-block { background: #2d2d2d; color: #f8f8f2; border-radius: 8px; padding: 20px; font-family: 'Fira Code', monospace; overflow-x: auto; margin-top: 30px; position: relative; } .code-title { position: absolute; top: -12px; left: 20px; background: #2d2d2d; color: #66d9ef; padding: 0 10px; font-weight: 600; border-radius: 4px; } .explanation { background: #ecf5ff; padding: 20px; border-radius: 8px; margin-top: 25px; border-left: 4px solid #409eff; } .explanation h3 { margin-top: 0; color: #409eff; } .step { display: flex; margin-bottom: 15px; align-items: flex-start; } .step-number { background: #409eff; color: white; width: 28px; height: 28px; border-radius: 50%; display: flex; align-items: center; justify-content: center; margin-right: 15px; flex-shrink: 0; } .footer { text-align: center; padding: 20px; color: #909399; font-size: 0.9rem; border-top: 1px solid #ebeef5; } </style> </head> <body> <div id="app"> <div class="container"> <div class="header"> <h1>获取Textarea光标所在行号</h1> <p>在Vue3中实现el-input textarea的光标行号定位功能</p> </div> <div class="content"> <div class="input-container"> <el-input ref="inputRef" v-model="text" type="textarea" :autosize="{ minRows: 8, maxRows: 12 }" placeholder="在此输入多行文本..." @input="updateCursorInfo" @click="updateCursorInfo" @keyup="updateCursorInfo" ></el-input> </div> <div class="info-panel"> <div class="info-item"> <span class="info-label">当前行号</span> <span class="info-value">{{ currentLine }}</span> </div> <div class="info-item"> <span class="info-label">总行数</span> <span class="info-value">{{ totalLines }}</span> </div> <div class="info-item"> <span class="info-label">光标位置</span> <span class="info-value">{{ cursorPosition }}</span> </div> </div> <div class="explanation"> <h3>实现原理</h3> <div class="step"> <div class="step-number">1</div> <div> <strong>获取textarea元素</strong> - 通过ref获取el-input组件的textarea元素 </div> </div> <div class="step"> <div class="step-number">2</div> <div> <strong>监听事件</strong> - 监听input输入)、click(点击)和keyup(按键)事件 </div> </div> <div class="step"> <div class="step-number">3</div> <div> <strong>获取光标位置</strong> - 使用selectionStart属性获取光标在文本中的位置 </div> </div> <div class="step"> <div class="step-number">4</div> <div> <strong>计算行号</strong> - 统计从文本开始到光标位置之间的换行符数量 <div style="margin-top: 8px; font-style: italic;"> 行号 = 换行符数量 + 1 </div> </div> </div> </div> <div class="code-block"> <div class="code-title">核心代</div> <pre><code>// 获取光标所在行号 const getCurrentLine = () => { const textarea = inputRef.value?.textarea; if (!textarea) return 1; // 获取光标位置 const cursorPosition = textarea.selectionStart; // 截取从开始到光标位置的文本 const textBeforeCursor = text.value.substring(0, cursorPosition); // 计算换行符的数量 const newlineCount = (textBeforeCursor.match(/\n/g) || []).length; // 行号 = 换行符数量 + 1 return newlineCount + 1; }; // 更新光标信息 const updateCursorInfo = () => { currentLine.value = getCurrentLine(); totalLines.value = text.value.split('\n').length; cursorPosition.value = inputRef.value?.textarea?.selectionStart || 0; };</code></pre> </div> </div> <div class="footer"> Vue3 + Element Plus 实现 | 光标行号定位功能 </div> </div> </div> <script> const { createApp, ref, onMounted } = Vue; const app = createApp({ setup() { const inputRef = ref(null); const text = ref('第一行文本\n第二行文本\n第三行文本'); const currentLine = ref(1); const totalLines = ref(3); const cursorPosition = ref(0); // 获取光标所在行号 const getCurrentLine = () => { const textarea = inputRef.value?.textarea; if (!textarea) return 1; // 获取光标位置 const cursorPos = textarea.selectionStart; // 截取从开始到光标位置的文本 const textBeforeCursor = text.value.substring(0, cursorPos); // 计算换行符的数量 const newlineCount = (textBeforeCursor.match(/\n/g) || []).length; // 行号 = 换行符数量 + 1 return newlineCount + 1; }; // 更新光标信息 const updateCursorInfo = () => { currentLine.value = getCurrentLine(); totalLines.value = text.value.split('\n').length; cursorPosition.value = inputRef.value?.textarea?.selectionStart || 0; }; onMounted(() => { // 初始计算 updateCursorInfo(); }); return { inputRef, text, currentLine, totalLines, cursorPosition, updateCursorInfo }; } }); app.use(ElementPlus); app.mount('#app'); </script> </body> </html> ``` ## 实现原理详解 1. **获取textarea元素**: - 使用`ref="inputRef"`获取el-input组件实例 - 通过`inputRef.value.textarea`访问原生textarea元素 2. **监听事件**: - `@input`:文本内容变化时触发 - `@click`:鼠标点击改变光标位置时触发 - `@keyup`:键盘操作改变光标位置时触发 3. **计算光标位置**: ```javascript const cursorPosition = textarea.selectionStart; ``` 4. **计算行号**: ```javascript const textBeforeCursor = text.value.substring(0, cursorPosition); const newlineCount = (textBeforeCursor.match(/\n/g) || []).length; const lineNumber = newlineCount + 1; ``` ## 使用说明 1. 在文本区域输入多行文本 2. 点击文本区域任意位置或使用键盘方向键移动光标 3. 当前行号、总行数和光标位置会实时更新 4. 核心代区域展示了实现的关键逻辑 ## 相关扩展问题 1. **如何获取当前行的文本内容?** - 可以基于当前行号,将整个文本按换行符分割成数组 - `const lines = text.value.split('\n');` - `const currentLineText = lines[currentLine.value - 1];` 2. **如何实现代编辑器的行号显示功能?** - 在textarea左侧添加一个显示行号的div - 根据总行数生成对应数量的行号元素 - 高亮显示当前行对应的行号 3. **如何支持更复杂的文本编辑器功能?** - 考虑使用专业的代编辑器库如CodeMirror或Monaco Editor - 这些库提供了更完善的API用于获取光标位置和行号信息 - 参考引用[2]和[3]中CodeMirror的集成方式 这个实现方案完全使用Vue3的Composition API,代简洁高效,能够准确获取el-input textarea的光标行号信息。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值