Skip to content

fix: 修复父组件修改值后 wd-input 显示不更新#1459

Open
Gitzzr wants to merge 1 commit intoMoonofweisheng:masterfrom
Gitzzr:fix/input-sync-issue
Open

fix: 修复父组件修改值后 wd-input 显示不更新#1459
Gitzzr wants to merge 1 commit intoMoonofweisheng:masterfrom
Gitzzr:fix/input-sync-issue

Conversation

@Gitzzr
Copy link
Copy Markdown

@Gitzzr Gitzzr commented Feb 2, 2026

Fix: 修复父组件修改值后 wd-input 显示不更新

🐛 问题描述

修复 wd-input 组件在被二次封装时,当父组件在 input 事件中修改值,且修改后的值与之前的 modelValue 相同时,输入框显示不更新的问题。

相关 Issue: #1458

📋 问题原因

当用户输入触发父组件修改值时的执行流程:

  1. wd-inputv-model 更新内部 inputValue 为用户输入的值
  2. 父组件在 @input 事件中处理后 emit 新值(例如限制小数位)
  3. 如果新值与 props.modelValue 相同(无变化)
  4. wd-inputwatch 不会触发(Vue 的 watch 只在值变化时触发)
  5. 导致内部 inputValueprops.modelValue 不一致
  6. 输入框显示错误的值

示例场景

  • 用户输入 123.456
  • 父组件限制小数位为 2 位,emit 123.45
  • props.modelValue 之前就是 123.45(无变化)
  • watch 不触发,输入框仍显示 123.456

🔧 修改内容

1. 添加必要的导入

import { computed, ref, watch, useSlots, type Slots, nextTick } from 'vue'

2. 修改 handleInput 函数(核心修复)

修改前

function handleInput({ detail }: any) {
  emit('update:modelValue', inputValue.value)
  emit('input', detail)
}

修改后

function handleInput({ detail }: any) {
  emit('update:modelValue', inputValue.value)
  emit('input', detail)

  // 等待父组件处理完毕
  nextTick(() => {
    // 检查父组件是否修改了值(例如限制小数位、格式化等)
    const newVal = isDef(props.modelValue) ? String(props.modelValue) : ''
    if (newVal !== inputValue.value) {
      inputValue.value = newVal
    }
  })
}

💡 技术实现

为什么需要 nextTick

nextTick 确保在父组件处理完 update:modelValue 事件并更新 props.modelValue 后再执行检查。这样可以获取到父组件处理后的最新值。

为什么不使用 watch

watch 只在值变化时触发。当父组件修改后的值与之前的 modelValue 相同时,watch 不会触发,无法同步 inputValue

性能影响

  • ✅ 每次 input 事件会执行一次 nextTick(微任务,性能开销极小)
  • ✅ 只有当父组件修改了值时才会更新 inputValue
  • ✅ 对正常输入场景无影响(不修改值时不执行额外操作)

🧪 测试方法

测试场景 1: 限制小数位数

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

const value = ref('')

function handleInput(e) {
  let val = e.detail.value.replace(/[^\d.]/g, '')
  if (val.includes('.')) {
    const [int, dec] = val.split('.')
    val = dec ? `${int}.${dec.slice(0, 2)}` : `${int}.`
  }
  value.value = val
}
</script>

<template>
  <wd-input v-model="value" @input="handleInput" label="限制2位小数" />
  <view>当前值: {{ value }}</view>
</template>

测试步骤:

  1. 输入 123.45
  2. 继续输入 6,变成 123.456
  3. 观察输入框显示

预期结果: 输入框显示 123.45(修复前会显示 123.456

测试场景 2: 千分位格式化

测试步骤:

  1. 输入 1234
  2. 继续输入 5,变成 12345
  3. 观察输入框显示

预期结果: 输入框正确显示格式化后的值

测试场景 3: 限制输入范围

测试步骤:

  1. 设置最大值为 100
  2. 输入 99
  3. 继续输入 9,变成 999
  4. 观察输入框显示

预期结果: 输入框显示 100(最大值)

测试场景 4: 正常输入(无修改)

测试步骤:

  1. 正常输入任意内容
  2. 观察输入框显示

预期结果: 输入框显示与输入内容一致(无影响)

📊 影响范围

受益场景

所有需要在 input 事件中对值进行处理的二次封装场景:

  • ✅ 限制小数位数
  • ✅ 数字格式化(千分位、货币等)
  • ✅ 限制输入范围
  • ✅ 自定义输入规则
  • ✅ 实时校验和修正

兼容性

  • ✅ 不影响现有的正常使用场景
  • ✅ 不影响性能
  • ✅ 向后兼容
  • ✅ 跨平台兼容(H5、微信小程序、APP)
  • ✅ 纯响应式实现,无平台特定代码

✅ 检查清单

  • 代码已通过 ESLint 检查
  • 已在 H5 平台测试
  • 已在微信小程序平台测试
  • 已在 APP 平台测试

🔗 相关链接

📝 备注

此修复采用纯响应式方案,通过 nextTick 等待父组件处理完毕后同步内部状态,无需直接操作 DOM,确保跨平台兼容性。

@vercel
Copy link
Copy Markdown

vercel bot commented Feb 2, 2026

@Gitzzr is attempting to deploy a commit to the weisheng's projects Team on Vercel.

A member of the Team first needs to authorize it.

@netlify
Copy link
Copy Markdown

netlify bot commented Feb 2, 2026

Deploy Preview for wot-design-uni ready!

Built without sensitive environment variables

Name Link
🔨 Latest commit 3fb95ef
🔍 Latest deploy log https://app.netlify.com/projects/wot-design-uni/deploys/69804cdf7021ea0008a5d4a4
😎 Deploy Preview https://deploy-preview-1459--wot-design-uni.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.

To edit notification comments on pull requests, go to your Netlify project configuration.

@coderabbitai
Copy link
Copy Markdown

coderabbitai bot commented Feb 2, 2026

Walkthrough

在 wd-input 组件的 handleInput 中引入并使用了 Vue 的 nextTick,使输入处理变为异步:在下一次 DOM 更新周期后对比父组件传入的 modelValue 与当前内部 inputValue,若不同则同步更新 inputValue

Changes

Cohort / File(s) Summary
输入组件异步同步
src/uni_modules/wot-design-uni/components/wd-input/wd-input.vue
导入 nextTick 并将 handleInput 处理改为在 nextTick 回调中对比 props.modelValue 与内部 inputValue,若存在差异则更新 inputValue,确保父组件对值的格式化/限制能反映回来。

Sequence Diagram(s)

(无 —— 变更为局部的组件同步修正,未满足序列图生成条件)

Estimated code review effort

🎯 3 (中等) | ⏱️ ~20 分钟

可能相关的 Issue

可能相关的 PRs

建议的审查者

  • Moonofweisheng

诗歌

🐰 我在输入框旁轻轻跳,
nextTick 来临把节奏调,
父值回写落入我怀抱,
同步悄然在一瞬到,
小兔鼓掌,格式不跑。 🎉

🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed PR标题清晰地总结了主要变更:修复父组件修改值后wd-input显示不更新的问题,与PR的核心目标完全相符。

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Fix all issues with AI agents
In `@src/uni_modules/wot-design-uni/components/wd-input/wd-input.vue`:
- Line 22: inputRef.value.value = newVal is a direct DOM assignment that only
works on H5 and breaks cross-platform compatibility; remove the direct DOM write
(the three lines referencing inputRef and setting .value) and rely on the
reactive v-model update via inputValue (handled in the watcher), or if you
absolutely need DOM write for H5 only, wrap that block with conditional
compilation (// `#ifdef` H5 ... // `#endif`) around the inputRef assignment; locate
the watcher/update logic using inputValue and inputRef in wd-input.vue to apply
the change.

<slot v-else name="prefix"></slot>
</view>
<input
ref="inputRef"
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

# First, let's check if the file exists and get its structure
cd src/uni_modules/wot-design-uni/components/wd-input && wc -l wd-input.vue && echo "---" && head -n 50 wd-input.vue

Repository: Moonofweisheng/wot-design-uni

Length of output: 2403


🏁 Script executed:

# Get the specific lines mentioned in the review
cat -n src/uni_modules/wot-design-uni/components/wd-input/wd-input.vue | sed -n '1,30p'

Repository: Moonofweisheng/wot-design-uni

Length of output: 1780


🏁 Script executed:

# Check lines 93, 129, 274-289
cat -n src/uni_modules/wot-design-uni/components/wd-input/wd-input.vue | sed -n '85,100p;120,135p;265,295p'

Repository: Moonofweisheng/wot-design-uni

Length of output: 2314


🌐 Web query:

uni-app Vue 3 ref input element H5 WeChat mini-program behavior differences value assignment

💡 Result:

uni-app(Vue 3) 里,用 ref 去拿 <input> 并“直接给元素赋值”在 H5微信小程序(mp-weixin) 上行为确实会不一样,核心原因是:H5 有真实 DOM;小程序逻辑层/视图层分离,没有可同步操作的 DOM

1) H5:ref 基本等同拿到 DOM,可直接改 el.value

H5 下 <input ref="inp" /> 通常能拿到对应元素对象,因此像下面这种直接赋值一般可立即反映到界面:

inp.value.value = 'abc'   // 或 inp.value.setAttribute('value','abc')

2) 微信小程序:不要指望用 ref 当 DOM,用“数据驱动”更新 value

小程序端由于逻辑层与视图层分离,大多数同步 DOM API 不可用,可操作能力受限。(doc.dcloud.net.cn)
并且在 非 uni-app x 场景下,用 refs 去取“内置组件引用”往往会是 undefined(或拿到的也不是 H5 那种 DOM)。(doc.dcloud.net.cn)

因此在 mp-weixin,正确且跨端的做法是:

  • v-model / :value 绑定数据,通过修改响应式数据来改输入框显示
  • 必要时配合 nextTick 确保渲染时序

示例:

<template>
  <input v-model="val" />
</template>

<script setup>
import { ref, nextTick } from 'vue'
const val = ref('')

async function setVal(v){
  val.value = v
  await nextTick()
}
</script>

3) 如果你在看 uni-app x:小程序端拿到的也只是“受限的 UniElement”,且通常要配合 id

uni-app x 文档明确提到:小程序平台如果期望用 ref 获取到 UniElement,需要在该元素上设置 id,并且小程序端 UniElement 可用属性/方法是受限的(偏样式/布局查询等)。(doc.dcloud.net.cn)


结论

  • H5 可以“ref → DOM → 直接改 .value”。
  • mp-weixin 应该“改绑定数据(v-model/:value)→ 框架渲染更新”,不要依赖 ref 直接给 input 元素赋值。(doc.dcloud.net.cn)

Citations:


🌐 Web query:

uni-app Vue 3 template ref native input element across platforms H5 小程序 APP

💡 Result:

在 uni-app(Vue 3)里,<input> 用 template ref 想“拿到原生 DOM input 元素”做跨端统一,是做不到的:只有 H5 才有真实 DOM;小程序/App(非 nvue)没有浏览器 DOM 这一层(且部分小程序里 input 聚焦时还是“原生组件”表现),因此 ref 的含义会变。(uniapp.dcloud.io)

各端 ref 能拿到什么

  • H5ref 基本可拿到 HTMLInputElement(可 focus() / select() 等)。
  • 小程序 / App(vue 页面):不要期待拿到原生 DOM。ref 更接近“组件/元素代理对象”,并且在小程序端如果想用 ref 得到 UniElement,通常还需要给该元素设置 id,且能力受限。(doc.dcloud.net.cn)

跨端推荐做法(不要依赖原生 DOM)

1) 用 focus 属性做统一“聚焦/失焦”

<template>
  <input v-model="val" :focus="focusIt" />
</template>

<script setup>
import { ref, nextTick } from 'vue'
const val = ref('')
const focusIt = ref(false)

async function focus() {
  focusIt.value = false
  await nextTick()
  focusIt.value = true
}
</script>

2) 需要“查位置/尺寸”等:用 uni.createSelectorQuery()(跨端)

createSelectorQuery 用来查节点信息(如 boundingClientRect),需要在 mounted 之后调用。(en.uniapp.dcloud.io)

注意:nodesRef.node() 主要用于取 canvas 的 Node,并不是用来获取 input 原生节点的。(en.uniapp.dcloud.io)

3) 仅 H5 才写 DOM 逻辑:用条件编译隔离

<input ref="i" />

<script setup>
import { ref, onMounted } from 'vue'
const i = ref(null)

onMounted(() => {
  // `#ifdef` H5
  i.value?.focus?.()
  // `#endif`
})
</script>

如果你具体是想做“自动聚焦 / 光标定位 / 选择文本 / 获取键盘高度适配”等哪一种,我可以按目标给你一套真正跨 H5/小程序/App 的实现方式。

Citations:


删除或条件编译直接的 DOM 赋值,避免跨端兼容性问题

第 287 行 inputRef.value.value = newVal 直接赋值仅在 H5 生效,小程序/APP 端 ref 不能获取原生 DOM,此赋值会被忽略。由于第 284 行已通过 v-model 绑定的 inputValue.value = newVal 进行了响应式更新,直接 DOM 赋值是冗余且有害的。

建议方案

  • 完全移除第 286-288 行的 DOM 直接赋值逻辑(推荐),让 v-model 自动同步
  • 或使用条件编译 // #ifdef H5 包裹,仅在 H5 下执行(如有特殊需求)
相关代码位置
284:    inputValue.value = newVal
285:    // 强制更新 DOM
286:    if (inputRef.value) {
287:      inputRef.value.value = newVal
288:    }
🤖 Prompt for AI Agents
In `@src/uni_modules/wot-design-uni/components/wd-input/wd-input.vue` at line 22,
inputRef.value.value = newVal is a direct DOM assignment that only works on H5
and breaks cross-platform compatibility; remove the direct DOM write (the three
lines referencing inputRef and setting .value) and rely on the reactive v-model
update via inputValue (handled in the watcher), or if you absolutely need DOM
write for H5 only, wrap that block with conditional compilation (// `#ifdef` H5
... // `#endif`) around the inputRef assignment; locate the watcher/update logic
using inputValue and inputRef in wd-input.vue to apply the change.

@Gitzzr Gitzzr force-pushed the fix/input-sync-issue branch from 31a23d8 to 3fb95ef Compare February 2, 2026 07:06
@Gitzzr Gitzzr changed the title fix: 修复 wd-input 组件二次封装时 v-model 显示不同步问题 fix: 修复父组件修改值后 wd-input 显示不更新 Feb 2, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant