如何实现Vue组件中contenteditable div的v-model双向绑定

来源:3D模型作者:高永康头衔:资深程序员
导读:本期聚焦于小伙伴创作的《如何实现Vue组件中contenteditable div的v-model双向绑定》,敬请观看详情,探索知识的价值。以下视频、文章将为您系统阐述其核心内容与价值。如果您觉得《如何实现Vue组件中contenteditable div的v-model双向绑定》有用,将其分享出去将是对创作者最好的鼓励。

在Vue项目开发中,我们经常会遇到需要自定义富文本输入场景的需求,此时使用带有contenteditable属性的div会比原生textarea更灵活,但Vue原生的v-model指令仅支持input、textarea等表单元素,无法直接作用于contenteditable div,需要我们手动实现双向绑定的逻辑。

如何实现Vue组件中contenteditable div的v-model双向绑定

核心实现思路

双向绑定的本质是数据变化时更新DOM内容,DOM内容变化时同步更新数据。对于contenteditable div来说,我们需要监听div的输入事件来同步数据,同时在数据变化时更新div的innerHTML,核心逻辑可以分为两个方向实现。

方案一:通过事件监听直接实现

我们可以在组件内部直接监听contenteditable div的input事件,在事件回调中获取最新内容并更新绑定的数据,同时监听数据变化更新div内容。以下是Vue 3的组合式API实现示例:

<template>
  <div>
    <div
      ref="editableDiv"
      contenteditable="true"
      @input="handleInput"
      style="border: 1px solid #ccc; min-height: 100px; padding: 8px;"
    ></div>
    <p>当前内容:{{ content }}</p>
  </div>
</template>

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

const content = ref('')
const editableDiv = ref(null)

// 监听输入事件同步数据
const handleInput = (e) => {
  content.value = e.target.innerHTML
}

// 监听数据变化更新DOM
watch(content, (newVal) => {
  if (editableDiv.value && editableDiv.value.innerHTML !== newVal) {
    editableDiv.value.innerHTML = newVal
  }
})
</script>

这种方式的优点是逻辑直观,不需要额外封装,适合单个组件内使用。但需要注意,直接设置innerHTML会导致光标位置重置,在用户连续输入时体验较差。

方案二:封装自定义指令实现v-model

如果多个组件都需要使用这个能力,封装一个自定义指令会更通用,让contenteditable div可以直接使用v-model指令。以下是Vue 3的自定义指令实现示例:

<template>
  <div>
    <div
      v-model="content"
      contenteditable="true"
      style="border: 1px solid #ccc; min-height: 100px; padding: 8px;"
    ></div>
    <p>当前内容:{{ content }}</p>
  </div>
</template>

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

const content = ref('')

// 注册自定义指令
const vModel = directive('model', {
  // 绑定元素时初始化内容
  mounted(el, binding) {
    el.innerHTML = binding.value || ''
    // 监听输入事件更新数据
    const handler = (e) => {
      binding.instance[binding.exp] = e.target.innerHTML
    }
    el.addEventListener('input', handler)
    // 保存handler用于卸载时移除
    el._vModelHandler = handler
  },
  // 数据更新时同步DOM
  updated(el, binding) {
    if (el.innerHTML !== binding.value) {
      el.innerHTML = binding.value || ''
    }
  },
  // 卸载时移除事件监听
  unmounted(el) {
    if (el._vModelHandler) {
      el.removeEventListener('input', el._vModelHandler)
    }
  }
})
</script>

实现注意事项

  • 输入法兼容:部分输入法输入过程中会触发多次input事件,需要做防抖处理避免频繁更新数据。
  • 光标位置:直接设置innerHTML会导致光标跳转到内容开头,复杂场景下需要额外记录光标位置并恢复。
  • 数据对比:更新DOM前需要对比当前内容和目标内容是否一致,避免不必要的DOM操作导致性能问题。
  • XSS风险:如果内容来自用户输入,需要对innerHTML的内容做过滤,避免插入恶意脚本。

不同Vue版本适配

如果是Vue 2项目,自定义指令的钩子函数名称和参数会有差异,mounted对应bind,updated对应update,具体可以参考Vue 2的官方指令文档调整实现逻辑,核心的双向绑定思路是一致的。

Vuecontenteditablev_model自定义指令修改时间:2026-06-20 02:57:29

免责声明:​ 已尽一切努力确保本网站所含信息的准确性。网站内容多为原创整理与精心编撰,观点力求客观中立。本站旨在免费分享,内容仅供个人学习、研究或参考使用。若引用了第三方作品,版权归原作者所有。如内容涉及您的权益,请联系我们处理。
内容垂直聚焦
专注技术核心技术栏目,确保每篇文章深度聚焦于实用技能。从代码技巧到架构设计,为用户提供无干扰的纯技术知识沉淀,精准满足专业提升需求。
知识结构清晰
覆盖从开发到部署的全链路。AI、前端、编程、数据库、服务器、建站、系统层层递进,构建清晰学习路径,帮助用户系统化掌握开发与运维所需的核心技术。
深度技术解析
拒绝泛泛而谈,深入技术细节与实践难点。无论是数据库优化还是服务器配置,均结合真实场景与代码示例进行剖析,致力于提供可直接应用于工作的解决方案。
专业领域覆盖
精准对应开发生命周期。从前端界面到后端编程,从数据库操作到服务器运维,形成完整闭环,一站式满足全栈工程师和运维人员的技术需求。
即学即用高效
内容强调实操性,步骤清晰、代码完整。用户可根据教程直接复现和应用于自身项目,显著缩短从学习到实践的距离,快速解决开发中的具体问题。
持续更新保障
专注既定技术方向进行长期、稳定的内容输出。确保各栏目技术文章持续更新迭代,紧跟主流技术发展趋势,为用户提供经久不衰的学习价值。