You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Vue3中contenteditable div子元素聚焦与新元素焦点设置问题

Vue3 contenteditable 动态子元素聚焦与添加解决方案

一、更优的当前聚焦元素追踪方案

比起每次调用Selection API查询,更推荐通过Vue事件绑定实时追踪当前聚焦的子元素,逻辑更清晰且性能更优:

  • 给v-for循环的子元素绑定@focus事件,传递循环索引
  • 用响应式变量存储当前活跃元素的索引,后续添加新元素时直接基于这个索引确定插入位置

代码示例:

<template>
  <div contenteditable="true" class="editable-container">
    <div 
      v-for="(item, index) in items" 
      :key="index" 
      class="editable-item"
      tabindex="0"
      @focus="activeItemIndex = index"
    >
      {{ item.content }}
    </div>
  </div>
  <button @click="addNewItem">添加新元素</button>
</template>

<script setup>
import { ref, nextTick } from 'vue'

const items = ref([{ content: '初始元素1' }, { content: '初始元素2' }])
const activeItemIndex = ref(0)
</script>

二、解决新元素无法聚焦的问题

contenteditable容器内直接调用element.focus()经常失效,需要结合nextTick等待DOM更新,再用Range API精准设置光标位置:

  1. 基于activeItemIndex在当前活跃元素后方插入新元素
  2. 用nextTick等待Vue完成DOM渲染
  3. 创建Range对象并将光标定位到新元素内部,再关联到选区完成聚焦

代码示例(补充到上述script部分):

const addNewItem = async () => {
  // 在当前活跃元素后插入新元素
  const newItem = { content: '新元素' }
  items.value.splice(activeItemIndex.value + 1, 0, newItem)
  activeItemIndex.value += 1

  await nextTick() // 等待DOM更新完成

  const newElement = document.querySelector(`.editable-item:nth-child(${activeItemIndex.value + 1})`)
  if (newElement) {
    const range = document.createRange()
    const selection = window.getSelection()
    
    range.selectNodeContents(newElement)
    range.collapse(true) // 将光标定位到元素开头
    selection.removeAllRanges()
    selection.addRange(range)
    newElement.focus()
  }
}

补充说明:

  • 子元素需要添加tabindex="0",确保div能被聚焦(div默认不可获得焦点)
  • 直接调用focus()仅能让容器获得焦点,无法精准定位到子元素内部,必须配合Range API设置光标位置

内容的提问来源于stack exchange,提问作者Sahar Elbehery

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.25 09:57:13