ui库用的是iview .
radio、radioGroup是咱们很是经常使用的组件。radio有一个特征是选中以后没法取消。现实中取消radio的需求是常见且能够理解的。
因此看到这个需求以后第一尝试 在iview组件之上搞一搞,这一搞就入坑了,如今就来理一理个人入坑之路吧。css
首先咱们来看一下在 vue 中使用原生的radio组件如何使用取消。 原生radio取消选中的文章很是多,随便拎一篇看看就行,好比 取消radio的三种方法。
嗯,原理就是给radio元素的checked属性赋值为 false。
具体在 vue 中使用是这样的:vue
const { name, value } = data; <div> <input class="xxx" type="radio" name={this.id} ref={name} value={value} onClick={(vlaue) => this.radioGroupChange(value, name)} /> {name} </div>; // 方法 radioGroupChange (value, name) { if (this.checked === value) { // 取消选中 this.$refs[name].checked = false; // 当前选中值为空 this.checked = ''; } else { this.checked = value; } }
这样就OK了。大概惟一区别是 在 vue中经过 ref取到真实 dom。vuex
借鉴原生的radio,看来取消也不难嘛,监听radio或者 radio的change事件嘛。然而你会发现,重复点选某一个 radio的时候,iview中的on-change函数跟本木有响应。这是为何呢? 去 iview 源码中看一看浏览器
先上代码为敬:
先看下 radio.vue的 templateiview
<template> <label :class="wrapClasses"> <span :class="radioClasses"> <span :class="innerClasses"></span> <input type="radio" :class="inputClasses" :disabled="disabled" :checked="currentValue" :name="groupName" @change="change" @focus="onFocus" @blur="onBlur"> </span><slot>{{ label }}</slot> </label> </template>
再看下 change的响应函数dom
change (event) { // debugger if (this.disabled) { return false; } const checked = event.target.checked; this.currentValue = checked; const value = checked ? this.trueValue : this.falseValue; this.$emit('input', value); if (this.group) { if (this.label !== undefined) { this.parent.change({ value: this.label, checked: this.value }); } } else { this.$emit('on-change', value); this.dispatch('FormItem', 'on-form-change', value); } },
一开始怀疑 change事件中对 value作了处理,只有 不同的时候才函数
emit,仔细看,change函数中并无这部分处理。
问题在于 input 这里监听的 change 事件而不是 click事件,因此反复点击同一个 radio的时候没有 响应是正常的。布局
看到上面是否是就想 我在 radio上绑定一个click 事件就能够了;事实证实是不能够的,想一下就知道了,由于 iview并无监听click事件天然也没有把click事件 emit到父组件,因此是没法监听click的。
既然 Radio 不支持click,那就想办法在能让元素响应 click 呗测试
这里的思路是在 RadioGroup的Radio 外包裹一层 div/span,在这个元素上绑定 click 函数,这个元素确定会响应 click,在响应函数中判断 当前 选中的 value(这个变量一般会维护在data中,暂且用 this.value 表示) 和点击元素包裹的 value 值是否相同,相同则将 this.value 置为空,则能够达到取消的效果。
通过实践,该方法是可行的。 值得注意的是这种状况下须要取消RadioGroup的on-change事件监听,不然radio改变了this.value,会触发RadioGroup的on-change事件,致使没法取消。 还有一个弊端是 须要给 Radio增长一个包裹元素,可能还须要对元素写个样式,不要影响到原Radio 元素布局, 那么还有没有更好的方法呢?ui
vue中提供了监听原生事件的修饰符,在jsx形式的vue监听原生事件的写法以下:
<Radio nativeOnClick={this.handleRadioClick.bind(this, value)} label={value} disabled={disabled} > <span>{label}</span> </Radio>
因此咱们不用增长元素也能监听到click事件,接下里就能够在响应函数中 处理取消/选中的逻辑了。
嗯, 终于找到一个很好的绑定 click的方法,然而测试的时候,却发现 点击一次却响应了 两次点击函数,百思不得其解吗? 这时候 baidu 或者google给了咱们答案: 一个文章说的特别好,解释了两次的缘由:
以下文章连接:
触发的事件源分别为input和label;
触发条件很简单:
一、监听的是label和input的上层元素click事件
二、label和input关联(for或者input在label下)
问题缘由::
点击label的时候,事件冒泡一次,同时会触发关联的input的click事件,致使事件再次冒泡。
解决办法:
方法有很中拉,
有了上面的分析,下面咱们完整是总结一下 让radio能够取消的步骤:
注意: 我下面写的是 vue的jsx 形式,因此若是是vue形式,请自行修改。
首先: template
<RadioGroup onOn-change={this.sync.bind(this)} value={this.value} type={this.mode} size={this.size} style={this.css} class={this.theme} > <Radio nativeOnClick={this.handleRadioClick.bind(this, value)} label={value} disabled={disabled} > <span>{label}</span> </Radio> <Radio nativeOnClick={this.handleRadioClick.bind(this, value)} label={value} disabled={disabled} > <span>{label}</span> </Radio> </RadioGroup>
data 和 methods:
data() { return { value: '' } } methods: { handleRadioClick (value) { let now = +new Date(); if (now- this.evTimeStamp < 100) { return; } this.evTimeStamp = now; value = this.value === value ? '' : value; this.update(value); // 能够理解为vuex 通知更新 this.value }, }
限于自己实现还有其余关联部分,这里没有加上 更新 this.value具体代码,可是我相信看到这里应该已经知在使用 ui 库的状况如何 是 radio 能够取消了。
遇到问题欢迎评论提问,不足之处也欢迎指正。