Skip to content

fix: 🐛 优化 InputNumbe 处理中间状态值的逻辑,支持配置不立即响应输入变化 - #1116

Merged
Moonofweisheng merged 4 commits into
masterfrom
feat/input-number-refactor
Jun 22, 2025
Merged

fix: 🐛 优化 InputNumbe 处理中间状态值的逻辑,支持配置不立即响应输入变化#1116
Moonofweisheng merged 4 commits into
masterfrom
feat/input-number-refactor

Conversation

@Moonofweisheng

@Moonofweisheng Moonofweisheng commented Jun 17, 2025

Copy link
Copy Markdown
Owner

🤔 这个 PR 的性质是?(至少选择一个)

  • 日常 bug 修复
  • 新特性提交
  • 站点、文档改进
  • 演示代码改进
  • 组件样式/交互改进
  • TypeScript 定义更新
  • CI/CD 改进
  • 包体积优化
  • 性能优化
  • 功能增强
  • 国际化改进
  • 代码重构
  • 代码风格优化
  • 测试用例
  • 分支合并
  • 其他改动(是关于什么的改动?)

🔗 相关 Issue

相关功能需求和用户反馈,主要解决InputNumber组件在使用过程中缺少的细粒度控制功能。

💡 需求背景和解决方案

需求背景

InputNumber组件在实际使用中存在以下需求:

  1. 输入更新策略控制 - 某些场景下需要减少频繁的change事件触发,只在用户完成输入后才更新
  2. 初始值处理策略 - 在使用严格步进模式时,需要控制是否自动修正初始值到有效范围

解决方案

1. 新增更新模式控制

// 非立即更新模式,仅在失焦和按钮点击时触发change事件
<wd-input-number v-model="value" :immediate-change="false" />

2. 新增初始化行为控制

// 不在初始化时自动修正值
<wd-input-number v-model="value" :format-on-init="false" :min="3" :step="2" step-strictly />

API 实现

新增属性:

  • immediate-change: boolean - 是否立即响应输入变化,默认true
  • format-on-init: boolean - 是否在初始化时自动修正值到有效范围,默认true

TypeScript类型定义:

export const inputNumberProps = {
  // ... 其他属性
  immediateChange: makeBooleanProp(true),
  formatOnInit: makeBooleanProp(true)
}

功能演示

新增了以下演示用例:

  • 禁用减号/加号按钮的独立控制
  • 严格步进模式下的边界限制处理
  • 非立即更新模式的对比演示
  • 初始化自动修正的开关控制
  • 临时空值处理的边界情况

☑️ 请求合并前的自查清单

⚠️ 请自检并全部勾选全部选项⚠️

  • 文档已补充或无须补充
  • 代码演示已提供或无须提供
  • TypeScript 定义已补充或无须补充

Summary by CodeRabbit

  • 新功能

    • 输入框组件支持分别禁用加号和减号按钮。
    • 新增“非即时更新模式”,可控制变更事件是在输入时立即触发还是仅在失焦/按钮点击时触发。
    • 增加初始化时自动校正初始值的功能,确保初始值符合范围和步长约束。
    • 新增支持输入框类型切换(数字或数字键盘模式)。
    • 优化输入解析、格式化和事件处理,提升输入体验和边界情况支持。
    • 新增多个示例展示上述功能及其他高级用法。
  • 文档

    • 输入框组件文档新增上述功能的详细说明和使用示例,完善属性表说明。
  • 测试

    • 大幅扩展和优化了输入框组件的测试用例,覆盖更多场景和边界情况,提升组件稳定性。

@vercel

vercel Bot commented Jun 17, 2025

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for Git ↗︎

Name Status Preview Comments Updated (UTC)
wot-design-uni ✅ Ready (Inspect) Visit Preview 💬 Add feedback Jun 22, 2025 3:29am

@netlify

netlify Bot commented Jun 17, 2025

Copy link
Copy Markdown

Deploy Preview for wot-design-uni ready!

Name Link
🔨 Latest commit bb8d30a
🔍 Latest deploy log https://app.netlify.com/projects/wot-design-uni/deploys/6857783d5e37da0008548a0b
😎 Deploy Preview https://deploy-preview-1116--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

coderabbitai Bot commented Jun 17, 2025

Copy link
Copy Markdown

"""

Walkthrough

本次更新为 wd-input-number 组件及其文档带来了多项新特性,包括按钮禁用、非即时更新模式、初始化自动校正等。组件内部的输入解析、格式化、归一化和事件处理逻辑进行了重构,测试用例也全面扩展以覆盖各种边界和交互场景,文档同步新增详细说明和示例。

Changes

文件/分组 变更摘要
docs/component/input-number.md
docs/en-US/component/input-number.md
文档新增“禁用按钮”、“非即时更新模式”、“初始化自动校正”三大特性说明及属性表条目,补充示例。
src/subPages/inputNumber/Index.vue 新增多个演示块与对应响应式变量、变更处理函数及样式,展示新特性。
src/uni_modules/wot-design-uni/components/wd-input-number/types.ts 移除 InputNumberEventType 枚举,新增 immediateChangeupdateOnInit 两个布尔型 prop 及类型别名。
src/uni_modules/wot-design-uni/components/wd-input-number/wd-input-number.vue 输入类型切换、输入解析与格式化重构、事件处理和按钮逻辑优化,支持新属性,提升健壮性。
tests/components/wd-input-number.test.ts 测试重构,新增大量覆盖新特性和边界场景的用例,辅助函数和模拟方法完善。

Sequence Diagram(s)

sequenceDiagram
    participant User
    participant InputNumber
    participant Parent

    User->>InputNumber: 输入/点击加减按钮
    alt immediateChange = true
        InputNumber->>Parent: 立即触发 change 事件
    else immediateChange = false
        InputNumber-->>User: 展示输入但不立即触发 change
        User->>InputNumber: 失焦/点击按钮
        InputNumber->>Parent: 此时触发 change 事件
    end

    Note over InputNumber: 初始化时<br>若 updateOnInit = true,自动校正初始值
Loading

Possibly related PRs

Poem

兔子写代码,组件又升级,
加减按钮可禁用,输入更灵犀。
即时与否随你选,初始化能校齐。
测试覆盖无死角,
跳跃数字乐无比!
(=^● ⋏ ●^=)
"""


📜 Recent review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 24cf5d4 and bb8d30a.

📒 Files selected for processing (6)
  • docs/component/input-number.md (3 hunks)
  • docs/en-US/component/input-number.md (3 hunks)
  • src/subPages/inputNumber/Index.vue (5 hunks)
  • src/uni_modules/wot-design-uni/components/wd-input-number/types.ts (2 hunks)
  • src/uni_modules/wot-design-uni/components/wd-input-number/wd-input-number.vue (2 hunks)
  • tests/components/wd-input-number.test.ts (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (4)
  • src/uni_modules/wot-design-uni/components/wd-input-number/types.ts
  • docs/en-US/component/input-number.md
  • docs/component/input-number.md
  • src/subPages/inputNumber/Index.vue
🧰 Additional context used
🧬 Code Graph Analysis (1)
tests/components/wd-input-number.test.ts (1)
src/uni_modules/wot-design-uni/components/wd-input-number/types.ts (1)
  • InputNumberProps (110-110)
⏰ Context from checks skipped due to timeout of 90000ms (4)
  • GitHub Check: Redirect rules - wot-design-uni
  • GitHub Check: Header rules - wot-design-uni
  • GitHub Check: Pages changed - wot-design-uni
  • GitHub Check: ESLint Check
✨ Finishing Touches
  • 📝 Generate Docstrings

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
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Explain this complex logic.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai explain this code block.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and explain its main purpose.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR.
  • @coderabbitai generate sequence diagram to generate a sequence diagram of the changes in this PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

@github-actions

Copy link
Copy Markdown

组件测试摘要 (H5 平台)

测试时间: Tue Jun 17 05:23:58 UTC 2025

测试结果

组件 状态 覆盖率

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 4

🧹 Nitpick comments (3)
src/subPages/inputNumber/Index.vue (1)

198-288: 建议合并重复的 CSS 样式

四个 demo 类(.immediate-demo.temp-empty-demo.strict-bounds-demo.format-init-demo)的样式基本相同,建议提取公共样式以减少代码重复。

-<style lang="scss" scoped>
-.flex {
-  display: flex;
-  justify-content: space-between;
-  align-items: center;
-}
-
-.immediate-demo {
-  .demo-title {
-    font-size: 14px;
-    color: #333;
-    margin-bottom: 8px;
-    font-weight: 500;
-  }
-
-  .demo-note {
-    font-size: 12px;
-    color: #999;
-    margin-top: 12px;
-    line-height: 1.4;
-    padding: 8px;
-    background: #f5f5f5;
-    border-radius: 4px;
-  }
-
-  .wd-input-number {
-    margin-bottom: 16px;
-  }
-}
-
-.temp-empty-demo {
-  .demo-description {
-    font-size: 14px;
-    color: #333;
-    margin-bottom: 8px;
-    font-weight: 500;
-  }
-
-  .demo-note {
-    font-size: 12px;
-    color: #999;
-    margin-top: 12px;
-    line-height: 1.4;
-    padding: 8px;
-    background: #f5f5f5;
-    border-radius: 4px;
-  }
-
-  .wd-input-number {
-    margin-bottom: 16px;
-  }
-}
-
-.strict-bounds-demo {
-  .demo-description {
-    font-size: 14px;
-    color: #333;
-    margin-bottom: 8px;
-    font-weight: 500;
-  }
-
-  .demo-note {
-    font-size: 12px;
-    color: #999;
-    margin-top: 12px;
-    line-height: 1.4;
-    padding: 8px;
-    background: #f5f5f5;
-    border-radius: 4px;
-  }
-
-  .wd-input-number {
-    margin-bottom: 16px;
-  }
-}
-
-.format-init-demo {
-  .demo-title {
-    font-size: 14px;
-    color: #333;
-    margin-bottom: 8px;
-    font-weight: 500;
-  }
-
-  .demo-note {
-    font-size: 12px;
-    color: #999;
-    margin-top: 12px;
-    line-height: 1.4;
-    padding: 8px;
-    background: #f5f5f5;
-    border-radius: 4px;
-  }
-
-  .wd-input-number {
-    margin-bottom: 16px;
-  }
-}
+<style lang="scss" scoped>
+.flex {
+  display: flex;
+  justify-content: space-between;
+  align-items: center;
+}
+
+.demo-wrapper {
+  .demo-title,
+  .demo-description {
+    font-size: 14px;
+    color: #333;
+    margin-bottom: 8px;
+    font-weight: 500;
+  }
+
+  .demo-note {
+    font-size: 12px;
+    color: #999;
+    margin-top: 12px;
+    line-height: 1.4;
+    padding: 8px;
+    background: #f5f5f5;
+    border-radius: 4px;
+  }
+
+  .wd-input-number {
+    margin-bottom: 16px;
+  }
+}
+
+.immediate-demo,
+.temp-empty-demo,
+.strict-bounds-demo,
+.format-init-demo {
+  @extend .demo-wrapper;
+}
 </style>
src/uni_modules/wot-design-uni/components/wd-input-number/wd-input-number.vue (2)

68-70: addStep 判定冗余,始终返回 ≥ min

addStep 调用 normalizeValue 后会再次 clamp 到 min,因此
addStep(val, -props.step) < props.min 恒为 false
可以直接判断 val <= props.min 以降低计算量并避免误读。


76-78: 同理,maxDisabled 中的上界判定多余

addStep(val, props.step) 经归一化后不会超过 max
保留 val >= props.max 即可。

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 6026137 and 4358296.

📒 Files selected for processing (6)
  • docs/component/input-number.md (3 hunks)
  • docs/en-US/component/input-number.md (3 hunks)
  • src/subPages/inputNumber/Index.vue (6 hunks)
  • src/uni_modules/wot-design-uni/components/wd-input-number/types.ts (2 hunks)
  • src/uni_modules/wot-design-uni/components/wd-input-number/wd-input-number.vue (2 hunks)
  • tests/components/wd-input-number.test.ts (1 hunks)
🧰 Additional context used
🧬 Code Graph Analysis (1)
tests/components/wd-input-number.test.ts (1)
src/uni_modules/wot-design-uni/components/wd-input-number/types.ts (1)
  • InputNumberProps (102-102)
🪛 GitHub Check: Test Components (wd-input-number)
tests/components/wd-input-number.test.ts

[failure] 705-705: tests/components/wd-input-number.test.ts > WdInputNumber > 无效初始值处理
AssertionError: expected '1' to be 'invalid' // Object.is equality

Expected: "invalid"
Received: "1"

❯ tests/components/wd-input-number.test.ts:705:30


[failure] 372-372: tests/components/wd-input-number.test.ts > WdInputNumber > 初始化时自动修正
AssertionError: expected [ '4' ] to deeply equal [ 4 ]

  • Expected
  • Received

    [

  • 4,
  • "4",
    ]

❯ tests/components/wd-input-number.test.ts:372:30

⏰ Context from checks skipped due to timeout of 90000ms (3)
  • GitHub Check: Redirect rules - wot-design-uni
  • GitHub Check: Header rules - wot-design-uni
  • GitHub Check: Pages changed - wot-design-uni
🔇 Additional comments (3)
src/uni_modules/wot-design-uni/components/wd-input-number/types.ts (1)

10-10: 类型定义更新合理

新增的 immediateChangeformatOnInit 属性定义清晰,默认值设置得当。ExtractPropTypes 的引入和 InputNumberProps 类型导出提升了类型安全性。

Also applies to: 91-99, 102-102

docs/component/input-number.md (1)

207-208: 版本占位符需要替换

$LOWEST_VERSION$ 占位符需要在发布前替换为实际的版本号。

docs/en-US/component/input-number.md (1)

207-208: Version placeholders need to be replaced

The $LOWEST_VERSION$ placeholders should be replaced with actual version numbers before release.

Comment on lines +358 to +373
const wrapper = createPropsOnlyWrapper({
modelValue: 1,
min: 3,
max: 15,
step: 2,
stepStrictly: true,
formatOnInit: true
})

await nextTick()

// 应该触发update:modelValue事件,将值从1修正为4
const updateEvents = wrapper.emitted('update:modelValue')
expect(updateEvents).toBeTruthy()
expect(updateEvents![0]).toEqual([4])
})

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

测试用例失败:类型不匹配

第 372 行的测试期望 update:modelValue 事件发出数字 4,但实际发出的是字符串 '4'。这可能会导致类型不一致的问题。

建议确保组件始终发出正确类型的值。如果字符串是预期的,更新测试:

-    expect(updateEvents![0]).toEqual([4])
+    expect(updateEvents![0]).toEqual(['4'])

或者修复组件以确保发出数字类型。

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const wrapper = createPropsOnlyWrapper({
modelValue: 1,
min: 3,
max: 15,
step: 2,
stepStrictly: true,
formatOnInit: true
})
await nextTick()
// 应该触发update:modelValue事件,将值从1修正为4
const updateEvents = wrapper.emitted('update:modelValue')
expect(updateEvents).toBeTruthy()
expect(updateEvents![0]).toEqual([4])
})
const wrapper = createPropsOnlyWrapper({
modelValue: 1,
min: 3,
max: 15,
step: 2,
stepStrictly: true,
formatOnInit: true
})
await nextTick()
// 应该触发update:modelValue事件,将值从1修正为4
const updateEvents = wrapper.emitted('update:modelValue')
expect(updateEvents).toBeTruthy()
- expect(updateEvents![0]).toEqual([4])
+ expect(updateEvents![0]).toEqual(['4'])
})
🧰 Tools
🪛 GitHub Check: Test Components (wd-input-number)

[failure] 372-372: tests/components/wd-input-number.test.ts > WdInputNumber > 初始化时自动修正
AssertionError: expected [ '4' ] to deeply equal [ 4 ]

  • Expected
  • Received

    [

  • 4,
  • "4",
    ]

❯ tests/components/wd-input-number.test.ts:372:30

🤖 Prompt for AI Agents
In tests/components/wd-input-number.test.ts around lines 358 to 373, the test
expects the 'update:modelValue' event to emit a number 4, but it actually emits
a string '4', causing a type mismatch. To fix this, either update the test
expectation to expect a string '4' if that is intended behavior, or modify the
component code to ensure it emits a number type for the event value
consistently.

Comment on lines +686 to +713
test('无效初始值处理', async () => {
// 使用特殊的wrapper来处理无效值
const WrapperComponent = defineComponent({
components: { WdInputNumber },
setup() {
const value = ref('invalid' as any)
return {
value,
min: 1,
stepStrictly: true
}
},
template: '<WdInputNumber v-model="value" :min="min" :step-strictly="stepStrictly" />'
})

const wrapper = mount(WrapperComponent)
await nextTick()

// 初始化时保持无效值
expect(wrapper.vm.value).toBe('invalid')

// 用户交互时才会修正 - 模拟点击按钮
await wrapper.findAll('.wd-input-number__action')[1].trigger('click')
await nextTick()

// 按钮操作后应该被修正为最小值
expect(wrapper.vm.value).toBe(2)
})

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

测试用例失败:无效初始值处理

根据测试失败信息,第 705 行的断言失败了。组件似乎将无效的初始值 'invalid' 转换为了 '1'。需要确认这是预期行为还是需要修复。

如果组件应该保留无效值直到用户交互,建议修改组件逻辑。如果这是预期行为,应该更新测试用例:

-    // 初始化时保持无效值
-    expect(wrapper.vm.value).toBe('invalid')
+    // 初始化时无效值被转换为数字
+    expect(wrapper.vm.value).toBe(1)
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
test('无效初始值处理', async () => {
// 使用特殊的wrapper来处理无效值
const WrapperComponent = defineComponent({
components: { WdInputNumber },
setup() {
const value = ref('invalid' as any)
return {
value,
min: 1,
stepStrictly: true
}
},
template: '<WdInputNumber v-model="value" :min="min" :step-strictly="stepStrictly" />'
})
const wrapper = mount(WrapperComponent)
await nextTick()
// 初始化时保持无效值
expect(wrapper.vm.value).toBe('invalid')
// 用户交互时才会修正 - 模拟点击按钮
await wrapper.findAll('.wd-input-number__action')[1].trigger('click')
await nextTick()
// 按钮操作后应该被修正为最小值
expect(wrapper.vm.value).toBe(2)
})
test('无效初始值处理', async () => {
// 使用特殊的wrapper来处理无效值
const WrapperComponent = defineComponent({
components: { WdInputNumber },
setup() {
const value = ref('invalid' as any)
return {
value,
min: 1,
stepStrictly: true
}
},
template: '<WdInputNumber v-model="value" :min="min" :step-strictly="stepStrictly" />'
})
const wrapper = mount(WrapperComponent)
await nextTick()
// 初始化时无效值被转换为数字
expect(wrapper.vm.value).toBe(1)
// 用户交互时才会修正 - 模拟点击按钮
await wrapper.findAll('.wd-input-number__action')[1].trigger('click')
await nextTick()
// 按钮操作后应该被修正为最小值
expect(wrapper.vm.value).toBe(2)
})
🧰 Tools
🪛 GitHub Check: Test Components (wd-input-number)

[failure] 705-705: tests/components/wd-input-number.test.ts > WdInputNumber > 无效初始值处理
AssertionError: expected '1' to be 'invalid' // Object.is equality

Expected: "invalid"
Received: "1"

❯ tests/components/wd-input-number.test.ts:705:30

🤖 Prompt for AI Agents
In tests/components/wd-input-number.test.ts between lines 686 and 713, the test
expects the component to keep the invalid initial value 'invalid' until user
interaction, but the component converts it to '1' immediately, causing the
assertion at line 705 to fail. Determine if the component's behavior of
correcting invalid initial values on mount is intended. If so, update the test
to expect '1' instead of 'invalid' initially. If not, modify the component logic
to preserve the invalid value until user interaction occurs.

Comment on lines 16 to 19
:style="`${inputWidth ? 'width: ' + inputWidth : ''}`"
type="digit"
type="number"
:input-mode="precision ? 'decimal' : 'numeric'"
:disabled="disabled || disableInput"

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

type="number" 可能导致小数与负数输入受限

在微信小程序与部分 H5 环境中,<input type="number"> 默认拦截 “.” 和 “-”,这会直接与组件支持小数 / 负数的诉求冲突,即使 input-mode="decimal" 也无法完全规避。
建议改回 type="text",仅用 inputmode 控制键盘类型,并依赖现有 cleanInput 逻辑做格式校验。

🤖 Prompt for AI Agents
In src/uni_modules/wot-design-uni/components/wd-input-number/wd-input-number.vue
around lines 16 to 19, change the input element's type attribute from "number"
to "text" to avoid blocking decimal and negative inputs in some environments.
Keep using the inputmode attribute to control the keyboard type and rely on the
existing cleanInput logic for validating and formatting the input value.

@cloudflare-workers-and-pages

cloudflare-workers-and-pages Bot commented Jun 17, 2025

Copy link
Copy Markdown

Deploying wot-design-uni with  Cloudflare Pages  Cloudflare Pages

Latest commit: bb8d30a
Status: ✅  Deploy successful!
Preview URL: https://966fd255.wot-design-uni.pages.dev
Branch Preview URL: https://feat-input-number-refactor.wot-design-uni.pages.dev

View logs

@codecov-commenter

codecov-commenter commented Jun 17, 2025

Copy link
Copy Markdown

⚠️ Please install the 'codecov app svg image' to ensure uploads and comments are reliably processed by Codecov.

Codecov Report

Attention: Patch coverage is 89.63731% with 20 lines in your changes missing coverage. Please review.

Project coverage is 92.32%. Comparing base (6026137) to head (bb8d30a).
Report is 1 commits behind head on master.

Files with missing lines Patch % Lines
...uni/components/wd-input-number/wd-input-number.vue 89.41% 20 Missing ⚠️

❗ Your organization needs to install the Codecov GitHub app to enable full functionality.

Additional details and impacted files
@@            Coverage Diff             @@
##           master    #1116      +/-   ##
==========================================
+ Coverage   84.92%   92.32%   +7.40%     
==========================================
  Files         215        4     -211     
  Lines       17191      365   -16826     
  Branches     2743      111    -2632     
==========================================
- Hits        14600      337   -14263     
+ Misses       2591       28    -2563     
Flag Coverage Δ
h5 92.32% <89.63%> (+7.40%) ⬆️
wd-action-sheet ?
wd-backtop ?
wd-badge ?
wd-button ?
wd-calendar ?
wd-calendar-view ?
wd-card ?
wd-cell ?
wd-cell-group ?
wd-checkbox ?
wd-checkbox-group ?
wd-circle ?
wd-col-picker ?
wd-collapse ?
wd-config-provider ?
wd-count-down ?
wd-count-to ?
wd-curtain ?
wd-datetime-picker ?
wd-datetime-picker-view ?
wd-divider ?
wd-drop-menu ?
wd-fab ?
wd-floating-panel ?
wd-form ?
wd-gap ?
wd-grid ?
wd-grid-item ?
wd-icon ?
wd-img ?
wd-img-cropper ?
wd-index-anchor ?
wd-index-bar ?
wd-input ?
wd-input-number 92.32% <89.63%> (+17.83%) ⬆️
wd-keyboard ?
wd-layout ?
wd-loading ?
wd-loadmore ?
wd-message-box ?
wd-navbar ?
wd-navbar-capsule ?
wd-notice-bar ?
wd-notify ?
wd-number-keyboard ?
wd-overlay ?
wd-pagination ?
wd-password-input ?
wd-picker ?
wd-picker-view ?
wd-popover ?
wd-popup ?
wd-progress ?
wd-radio ?
wd-radio-group ?
wd-rate ?
wd-resize ?
wd-search ?
wd-segmented ?
wd-select-picker ?
wd-sidebar ?
wd-signature ?
wd-skeleton ?
wd-slider ?
wd-sort-button ?
wd-status-tip ?
wd-step ?
wd-steps ?
wd-sticky ?
wd-sticky-box ?
wd-swipe-action ?
wd-swiper ?
wd-swiper-nav ?
wd-switch ?
wd-tabbar ?
wd-table ?
wd-tabs ?
wd-tag ?
wd-text ?
wd-textarea ?
wd-toast ?
wd-tooltip ?
wd-transition ?
wd-upload ?
wd-video-preview ?
wd-watermark ?

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@github-actions

Copy link
Copy Markdown

组件测试摘要 (H5 平台)

测试时间: Tue Jun 17 06:10:25 UTC 2025

测试结果

组件 状态 覆盖率
wd-input-number ✅ 通过 93.08%

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 2

♻️ Duplicate comments (2)
src/uni_modules/wot-design-uni/components/wd-input-number/wd-input-number.vue (2)

17-19: type="number" 会拦截小数点和负号,导致输入受限

之前已指出同样问题:在微信小程序及部分 H5 环境下,<input type="number"> 会直接屏蔽 “.” 与 “-”,即使 inputmode="decimal" 也无法完全绕过,破坏组件对小数 / 负数的支持。

-        type="number"
+        type="text"

继续沿用 inputmode 控制键盘类型,并依赖现有 cleanInput 逻辑做格式校验即可。
未修复会导致用户无法输入合法值。


236-240: isIntermediate 逻辑过宽,整数被误判为中间态

再次保留了 (precision>0 && str.indexOf('.')===-1) 的判断,导致纯整数在设置 precision 时被视为“中间输入”,immediateChange 无法生效。请按先前建议仅判断 “结尾/开头带小数点或单独负号”的情形。

-return str.endsWith('.') || str.startsWith('.') || str.startsWith('-.') || str === '-' || (Number(props.precision) > 0 && str.indexOf('.') === -1)
+return str.endsWith('.') || str.startsWith('.') || str.startsWith('-.') || str === '-'
🧹 Nitpick comments (2)
src/uni_modules/wot-design-uni/components/wd-input-number/wd-input-number.vue (1)

68-78: 允许空值时 minDisabled/maxDisabled 计算可能异常

allowNull 且当前 inputValue 为空,toNumber 返回 NaN,与任何比较均为 false,导致按钮处于“可点击”状态;用户一点击即被强行修正为 props.min / props.max,体验突兀。可在 toNumber 遇到 NaN 时直接返回当前 modelValue 或使用哨兵值并在计算中显式处理。

tests/components/wd-input-number.test.ts (1)

115-122: 使用 .attributes('value') 获取输入值可能不可靠

inputvalueDOM 属性 而非属性节点,@vue/test-utils 在某些环境下不会同步到 attributes。为避免潜在误判,建议改为:

const inputEl = wrapper.find('.wd-input-number__input').element as HTMLInputElement
expect(inputEl.value).toBe('5')

能确保跨环境一致性。

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 4358296 and 00cff04.

📒 Files selected for processing (2)
  • src/uni_modules/wot-design-uni/components/wd-input-number/wd-input-number.vue (2 hunks)
  • tests/components/wd-input-number.test.ts (1 hunks)
🧰 Additional context used
🧬 Code Graph Analysis (1)
tests/components/wd-input-number.test.ts (1)
src/uni_modules/wot-design-uni/components/wd-input-number/types.ts (1)
  • InputNumberProps (102-102)
⏰ Context from checks skipped due to timeout of 90000ms (2)
  • GitHub Check: ESLint Check
  • GitHub Check: Cloudflare Pages
🔇 Additional comments (1)
tests/components/wd-input-number.test.ts (1)

358-373: 初始化自动修正用例已匹配新逻辑 ✅

该测试现期待数值 4(number),与组件 update:modelValue 的实际输出一致,解决了此前的类型不一致问题。

@github-actions

Copy link
Copy Markdown

组件测试摘要 (H5 平台)

测试时间: Sat Jun 21 10:16:15 UTC 2025

测试结果

组件 状态 覆盖率
wd-input-number ✅ 通过 93.06%

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 1

♻️ Duplicate comments (5)
tests/components/wd-input-number.test.ts (2)

358-373: 测试用例存在类型不匹配问题

根据过往评审意见,此处测试期望 update:modelValue 事件发出数字 4,但实际发出的是字符串 '4'。这与组件的实际行为不一致。

需要确认组件的预期行为并修正测试:

-    expect(updateEvents![0]).toEqual([4])
+    expect(updateEvents![0]).toEqual(['4'])

或者修复组件确保发出正确的数字类型。


686-705: 无效初始值处理测试与组件行为不符

根据过往评审意见,测试期望保留无效初始值 'invalid' 直到用户交互,但组件立即将其转换为 '1'。这表明测试假设与组件实际行为不一致。

需要明确组件对无效初始值的处理策略:

-    // 初始化时保持无效值
-    expect(wrapper.vm.value).toBe('invalid')
+    // 初始化时无效值被转换为最小值
+    expect(wrapper.vm.value).toBe(1)
src/uni_modules/wot-design-uni/components/wd-input-number/wd-input-number.vue (3)

17-18: 输入类型设置可能导致小数和负数输入问题

根据过往评审意见,type="number" 在微信小程序和部分 H5 环境中可能阻止小数点和负号输入,即使设置了 input-mode="decimal" 也无法完全解决。

建议改为 type="text" 并依赖现有的 cleanInput 逻辑:

-        type="number"
+        type="text"
         :input-mode="precision ? 'decimal' : 'numeric'"

132-154: toNumber 函数的边界处理可能导致用户体验问题

根据过往评审意见,将所有非法输入直接归为 props.min 可能导致用户输入的突然跳变,特别是当用户输入接近上限时。

建议改进非法值处理逻辑:

 function toNumber(val: string | number): number {
   // 空值处理
   if (props.allowNull && (!isDef(val) || val === '')) {
     return NaN
   }

   if (!isDef(val) || val === '') {
-    return props.min
+    // 保持当前值不变,避免意外跳变
+    return isNaN(Number(props.modelValue)) ? props.min : Number(props.modelValue)
   }

   let str = String(val)
   
   // 处理中间输入状态
   if (str.endsWith('.')) str = str.slice(0, -1)
   if (str.startsWith('.')) str = '0' + str
   if (str.startsWith('-.')) str = '-0' + str.substring(1)
-  if (str === '-' || str === '') return props.min
+  if (str === '-' || str === '') {
+    return isNaN(Number(props.modelValue)) ? props.min : Number(props.modelValue)
+  }

   let num = Number(str)
-  if (isNaN(num)) num = props.min
+  if (isNaN(num)) {
+    // 返回当前值或最小值,避免突然跳变
+    return isNaN(Number(props.modelValue)) ? props.min : Number(props.modelValue)
+  }

   return normalizeValue(num)
 }

235-239: isIntermediate 函数逻辑过于宽泛

根据过往评审意见,当 precision > 0 时,纯整数如 123 也被当作中间状态,这会阻止 updateValue 调用,导致 immediateChange 失效。

建议修正逻辑,只将真正的中间状态视为中间输入:

 function isIntermediate(val: string): boolean {
   if (!val) return false
   const str = String(val)
-  return str.endsWith('.') || str.startsWith('.') || str.startsWith('-.') || str === '-' || (Number(props.precision) > 0 && str.indexOf('.') === -1)
+  return str.endsWith('.') || str.startsWith('.') || str.startsWith('-.') || str === '-'
 }
🧹 Nitpick comments (3)
tests/components/wd-input-number.test.ts (2)

7-70: 辅助函数设计良好,但可以进一步优化类型安全性

辅助函数 createWrapper 设计得很好,支持动态 props 修改。不过建议改进类型定义以提高类型安全性。

-function createWrapper(props: Partial<InputNumberProps> = {}, vModelValue: number | string = 1) {
+function createWrapper(props: Partial<InputNumberProps> = {}, vModelValue: number | string = 1): VueWrapper<any> {

同时,建议为组件 props 添加更严格的类型验证:

-    props: {
+    props: {
       // 定义所有可能的props,这样可以通过setProps动态修改
-      modelValue: { type: [Number, String], default: undefined },
+      modelValue: { type: [Number, String] as PropType<number | string>, default: undefined },

85-102: 辅助函数实现合理,建议增强错误处理

simulateInputsimulateBlur 函数直接调用组件方法,这种方式合理且高效。不过建议增加错误处理以提高测试的健壮性。

 async function simulateInput(wrapper: any, value: string) {
   // 直接调用组件的handleInput方法
   const component = wrapper.findComponent(WdInputNumber)
   if (component.exists()) {
-    component.vm.handleInput(createInputEvent(value))
+    try {
+      component.vm.handleInput(createInputEvent(value))
+    } catch (error) {
+      console.warn('simulateInput error:', error)
+    }
   }
   await nextTick()
 }
src/uni_modules/wot-design-uni/components/wd-input-number/wd-input-number.vue (1)

338-369: 输入处理逻辑实现合理,支持即时和延迟更新

输入处理函数很好地实现了即时更新和延迟更新的双重模式,中间状态处理也比较合理。不过建议优化空值处理逻辑。

建议优化空值处理的判断条件:

     // 空值处理
     if (rawVal === '') {
       inputValue.value = ''
-      if (props.immediateChange && props.allowNull) {
+      if (props.immediateChange) {
+        if (props.allowNull) {
           updateValue('')
+        } else {
+          // 非允许空值时,可考虑延迟处理或保持当前值
+        }
       }
       return
     }
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 00cff04 and 24cf5d4.

📒 Files selected for processing (6)
  • docs/component/input-number.md (3 hunks)
  • docs/en-US/component/input-number.md (3 hunks)
  • src/subPages/inputNumber/Index.vue (6 hunks)
  • src/uni_modules/wot-design-uni/components/wd-input-number/types.ts (2 hunks)
  • src/uni_modules/wot-design-uni/components/wd-input-number/wd-input-number.vue (2 hunks)
  • tests/components/wd-input-number.test.ts (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (4)
  • src/uni_modules/wot-design-uni/components/wd-input-number/types.ts
  • docs/en-US/component/input-number.md
  • docs/component/input-number.md
  • src/subPages/inputNumber/Index.vue
⏰ Context from checks skipped due to timeout of 90000ms (1)
  • GitHub Check: Test Components (wd-input-number)
🔇 Additional comments (4)
tests/components/wd-input-number.test.ts (1)

950-1119: 测试覆盖度很高,边界情况处理得当

这些边界情况测试很全面,包括负数步进、小数精度累积误差、极端值稳定性等。测试设计考虑周到,能够有效验证组件的健壮性。

特别赞赏的测试场景:

  • 小数精度累积误差处理 (lines 976-993)
  • 极端值下的稳定性 (lines 910-927)
  • 组件清理逻辑 (lines 930-949)
src/uni_modules/wot-design-uni/components/wd-input-number/wd-input-number.vue (3)

184-214: 严格步进边界处理实现良好

applyStrictBounds 函数实现了复杂的严格步进边界逻辑,考虑了最小值和最大值的约束,代码逻辑清晰合理。

实现亮点:

  • 正确处理了精度计算避免浮点误差
  • 合理的候选值回退机制
  • 边界情况的完整覆盖

314-322: 步进计算函数设计优秀

addStep 函数很好地处理了浮点精度问题,使用因子计算避免了 JavaScript 浮点运算的精度误差。实现思路值得赞赏。

技术亮点:

  • 动态精度计算
  • 因子法避免浮点误差
  • 标准化处理确保结果合规

276-309: updateValue 函数实现了完整的事件流程

函数很好地整合了值更新、事件发射和拦截器调用,支持了新的 beforeChange 拦截器功能。代码结构清晰,逻辑完整。

设计优点:

  • 完整的空值处理
  • 拦截器模式支持
  • 事件发射的一致性
  • 值比较避免不必要的更新

@github-actions

Copy link
Copy Markdown

组件测试摘要 (H5 平台)

测试时间: Sun Jun 22 03:29:51 UTC 2025

测试结果

组件 状态 覆盖率
wd-input-number ✅ 通过 91.23%

@Moonofweisheng
Moonofweisheng merged commit ff99b22 into master Jun 22, 2025
@Moonofweisheng
Moonofweisheng deleted the feat/input-number-refactor branch June 22, 2025 04:12
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.

2 participants