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

修改输入框值时绑定的v-model未同步问题求助

问题:屏幕键盘修改输入框值后v-model未同步更新

我正在实现一个屏幕数字键盘,用于给数十个输入框输入数字。目前通过focus事件记录当前激活的输入框,点击数字按键时把数字追加到输入框值末尾,但这样修改输入框值后,绑定的v-model数据并没有同步变化,用普通键盘输入却一切正常。

示例代码:

<template>
    <p>xSize</p>
    <input v-model="xSize">
    <p>ySize</p>
    <input v-model="ySize">
    <div class="keyboard">
        <button v-for="i in [1,2,3,4,5,6,7,8,9,0]" class="key" :key="i" @click="addChar(i)">{{i}}</button>
    </div>
    <p>xSize = {{xSize}}</p>
    <p>ySize = {{ySize}}</p>
    <div class="test-box" v-bind:style="{width: this.xSize + 'px', height: this.ySize + 'px'}"></div>
</template>

<script>
export default {
  data: function () {
    return {
      xSize: 50,
      ySize: 50,
      activeElement: null
    }
  },
  props: {},
  created() {
    document.addEventListener('focusin', this.focusChanged)
  },
  beforeUnmount() {
    document.removeEventListener('focusin', this.focusChanged)
  },
  methods: {
    focusChanged: function (event) {
      const el = event.target
      if (el.type === "text") {
        if (this.activeElement !== el && this.activeElement !== null) {
          this.activeElement.style.background = "white";
        }
        this.activeElement = el
        this.activeElement.style.background = "red";
      }
    },
    addChar: function (char) {
      if (this.activeElement !== null) {
        this.activeElement.value += char
      }
    }
  }
}
</script>

<style scoped>
.keyboard {
  display: flex;
}
.key {
  margin: 3px;
  width: 30px;
  height: 30px;
  border: 2px black ridge;
}

.test-box {
  border: 2px black ridge;
  background: red;
  margin: 15px;
}
</style>

问题原因

直接修改DOM元素的value属性,不会触发Vue的响应式更新机制。v-model的双向绑定依赖于input事件,手动修改DOM值不会触发这个事件,所以Vue无法感知到值的变化,也就不会更新对应的data属性。

解决方法

方法一:手动触发input事件(改动小)

修改addChar方法,在修改DOM值后手动触发input事件,让Vue捕获到变化:

addChar: function (char) {
  if (this.activeElement !== null) {
    this.activeElement.value += char;
    // 触发input事件,通知Vue更新v-model绑定的数据
    this.activeElement.dispatchEvent(new Event('input'));
  }
}

方法二:直接操作data属性(更符合Vue思想)

放弃直接操作DOM,改为记录当前激活输入框对应的data字段名,点击按键时直接修改data值,利用Vue的响应式自动同步到输入框。

修改后的完整代码:

<template>
    <p>xSize</p>
    <!-- 用data-field绑定对应的data字段 -->
    <input v-model="xSize" data-field="xSize">
    <p>ySize</p>
    <input v-model="ySize" data-field="ySize">
    <div class="keyboard">
        <button v-for="i in [1,2,3,4,5,6,7,8,9,0]" class="key" :key="i" @click="addChar(i)">{{i}}</button>
    </div>
    <p>xSize = {{xSize}}</p>
    <p>ySize = {{ySize}}</p>
    <div class="test-box" :style="{width: xSize + 'px', height: ySize + 'px'}"></div>
</template>

<script>
export default {
  data() {
    return {
      xSize: 50,
      ySize: 50,
      activeField: '' // 记录当前激活的data字段名
    }
  },
  created() {
    document.addEventListener('focusin', this.focusChanged)
  },
  beforeUnmount() {
    document.removeEventListener('focusin', this.focusChanged)
  },
  methods: {
    focusChanged(event) {
      const el = event.target
      if (el.type === "text" && el.dataset.field) {
        // 移除之前激活输入框的样式
        if (this.activeField) {
          const prevEl = document.querySelector(`[data-field="${this.activeField}"]`);
          if (prevEl) prevEl.style.background = "white";
        }
        // 记录当前激活的字段名
        this.activeField = el.dataset.field;
        el.style.background = "red";
      }
    },
    addChar(char) {
      if (this.activeField) {
        // 直接修改data中的对应字段,Vue自动同步到输入框
        this[this.activeField] = `${this[this.activeField]}${char}`;
      }
    }
  }
}
</script>

<style scoped>
.keyboard {
  display: flex;
}
.key {
  margin: 3px;
  width: 30px;
  height: 30px;
  border: 2px black ridge;
}

.test-box {
  border: 2px black ridge;
  background: red;
  margin: 15px;
}
</style>

推荐说明

方法二更适合大量输入框的场景,完全遵循Vue数据驱动的思想,不需要直接操作DOM,只需要给每个输入框添加data-field属性绑定对应的data字段即可,代码更易维护。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.20 02:15:14