van 自定义组件_van-field 组件数值类型限制最大值的使用及思考

本文介绍了在使用Vant的van-field组件时,如何在自定义组件中限制数值类型的输入最大值,讨论了事件传递法存在的问题,并提出了解耦事件法的解决方案,通过在组件内部创建一个独立的数据`testValue`,减少组件间的相互依赖,实现了平滑无卡顿的输入限制。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

在使用Vant组件 van-field时需要限制数值类型的最大值,尝试了两种方法,最终确定了一种最优方案

版本说明 "vue": "^2.6.8" "vant": "^2.9.0"

因为在组件van-field外面有嵌套了一层作为自定义组件,方便写一些公共的业务逻辑,就是因为嵌套了一层才导致我最初使用的方法有性能问题和不能准确限制最大值的问题

而且使用的是数字,所以设置type='digit' Tips: digit 类型从 2.4.2 版本开始支持

我们先来看第一种方法

事件传递法

取这个名字的原因是因为所有都是通过事件来完成的,并且是连续的事件。

定义自定义组件

c-input

label=""

:value="value"

type="digit"

@input="inputHandler"

/>

export default {

name: 'c-input',

props: {

value: {

default: '',

type: [Number, String],

},

max: {

default: 0,

type: [Number, String],

},

},

methods: {

inputHandler (value) {

value = this.max > 0 ? Math.min(value, this.max || 0) : value

this.$emit('input', value)

},

}

}

使用自定义组件

首先输入1,可以正常显示1;我们再次输入1,这时显示11;我们继续输入1,这时显示50,但是已经能看到我们由111变成50的过程。

我们继续输入1,这时显示501,而且不会变成50,查看vue-devtools中events的事件都发送成功,

image.png

image.png

只有在输入框失去焦点的时候才能变成50

image.png

分析

想了一下可能是因为自定义组件c-input中的value值始终没有改变,导致van-field中的值不会改变

尝试一

既然没有改变,是否可以使用setTimeout,在开始改变的时候先改变值为其它值,然后再改变成我们期望的值。

inputHandler (value) {

value = this.max > 0 ? Math.min(value, this.max || 0) : value

this.$emit('input', Date.now())

setTimeout(() => {

this.$emit('input', value)

}, 0)

},

这种做法会导致事件的死循环,发送第一次input事件会触发vant-field的input事件,然后继续发送第一次input事件,导致死循环

这时如果修改第一次input事件的值为空字符串,也还是没达到目的。

这里我很想说先发送第一次input事件,再发送第二次input事件,然后就开始死循环,也许是我没有深入研究,结果就是每次触发vant-field组件input事件的值都是第一次input事件的值。有知道了麻烦在评论区回复一下

尝试二

尝试在computed中增加一个model,作为vant-field的v-model,同时去掉组件上:value数据和input事件监听

model: {

get () {

return this.value

},

set (val) {

this.inputHandler(val)

},

},

其实效果和尝试一是一样的

思来想去只能使用最后一个方法,解耦事件(当然代码要多写一点点,也就是一点点而已)

解耦事件法

在c-input组件内定一个data数据叫testValue(这个变量在自定义组件外部是看不到的),同时vant-field增加v-model='testValue'并去掉:value属性

还是要继续监听vant-field的input事件,在事件处理函数中将处理好的数据赋值给testValue(这时vant-field的值的变化是肉眼看不到的),还是要继续发送input事件,使c-input组件使用者知道自定义组件内部值是多少。

但是还有个问题,如果组件外部值变化,c-input组件内部不知道值的变化,这时就需要监听value了然后赋值给testValue

watch: {

value (newVal) {

this.testValue = newVal

},

},

同时如果创建创建的时候有初始值也需要赋值操作

created () {

this.testValue = this.value

},

运行效果杠杠的,而且当连续按住键盘不放的时候不会出现卡顿的现象。

这个处理逻辑最主要的是把:value="value" 变成了v-model="textValue",把组件值的改变由事件传递解耦,变成了各个组件各自内部的逻辑,减少了相互的依赖。

其实还是那四个字,单一原则

完整代码

label=""

v-model="testValue"

type="digit"

@input="inputHandler"

/>

export default {

name: 'c-input',

props: {

value: {

default: '',

type: [Number, String],

},

max: {

default: 0,

type: [Number, String],

},

},

data () {

return {

testValue: '',

}

},

watch: {

value (newVal) {

this.testValue = newVal

},

},

created () {

this.testValue = this.value

},

methods: {

inputHandler (value) {

value = this.max > 0 ? Math.min(value, this.max || 0) : value

this.testValue = value

this.$emit('input', value)

},

},

}

看到这里有人可能会问最后发送了input事件,必然会触发value的watch,导致给textValue赋值,最后还是会触发vant-field的input事件,导致死循环。

其实是不会的,触发value的watch后赋值的value和textValue是相同的,不会触发vant-field的input事件导致死循环。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值