问题
构建到了radio组件的部分了,写一篇文章记录一下构建的过程
原理
看着el-radio思考了一下原理,是要利用@input来实现了
- 构建组件,写好样式
- 向构建组件传递v-model,label,change等
- 内部组件获取v-model的value,再将value双向绑定到原生input节点上
- 隐藏原生节点
- 判断value与label值是否相等,相等则触发自定义input的选中样式
- 当点击自定义input选中时,触发
input事件,会被外层的v-model检测到并改变最外其绑定值 - 条件判断是否具有
radio-group来分支选中类型
代码
自定义radio
value ---> v-model值 label ---> 标识值 disable ---> 是否禁用
<template>
<label ref="props" :for="label" :class="{ 'ty-radio': true, 'select_radio': select, 'disable': forbidden }">
<div class="main">
<span class="border">
<span class="fill"></span>
<input :id="label" type="radio" :value="label" style="display: none;" v-model="radioValue">
</span>
<div class="text">
<slot></slot>
</div>
</div>
</label>
</template>
<script>
export default {
name: 'ty-radio',
props: {
// 外层的v-model值
value: {
type: [String, Number]
},
// 外层标识值
label: {
type: [String, Number]
},
disable: {
type: Boolean,
default: false
},
// 选中label时触发
change: {
type: Function
}
},
data() {
return {
// 禁用按钮
forbidden: false
}
},
watch: {
disable: {
handler(newV) {
if (typeof newV == 'boolean') {
this.forbidden = newV
}
}, immediate: true
},
// 判断是否选中, 选中则展示选中效果
select: {
handler(newV) {
if (newV) this.$emit('change', this.label);
}
}
},
computed: {
// 设置给隐藏input的值
radioValue: {
get() {
// 判断是否是有分组 有分组则设置为来自分组的value , 没有则设置来自radio的value
return this.isGroup ? this.$parent.$attrs.value : this.value
},
set(newValue) {
if (this.isGroup) {
// 有分组则设置为来自分组的vmodel值
this.$parent.$emit('input', newValue)
} else {
// 无分组设置为当前radio的vmodel值
this.$emit('input', newValue)
}
}
},
// 是否选中
select: {
get() {
return this.$props.label === this.radioValue;
}
},
// 是否是分组
isGroup: {
get() {
return this.$parent.$attrs.value ? true : false
}
},
}
}
</script>
<style lang='less' scoped>
@import '../../../css/radio.less';
</style>
自定义radioGroup
只起到一个传递值的作用
<template>
<div class="ty-radio-group">
<slot></slot>
</div>
</template>
<script>
export default {
name: 'ty-radio-group',
}
</script>
- 测试
<template>
<div class='testRadio'>
<p>基本使用</p>
<ty-radio v-model="value" label="1">选项1</ty-radio>
<ty-radio v-model="value" label="2">选项2</ty-radio>
<ty-radio v-model="value" label="3">选项3</ty-radio>
<p>禁用效果</p>
<ty-radio v-model="valueA" label="a">选项1</ty-radio>
<ty-radio v-model="valueA" label="b" :disable="true">选项2</ty-radio>
<ty-radio v-model="valueA" label="c">选项3</ty-radio>
<p>单选框组</p>
<ty-radio-group v-model="address">
<ty-radio label="China">中国</ty-radio>
<ty-radio label="America">美国</ty-radio>
<ty-radio label="Russia">俄罗斯</ty-radio>
<ty-radio label="Japan" :disable="true">日本</ty-radio>
<ty-radio label="Korea" :disable="true">韩国</ty-radio>
</ty-radio-group>
<p>change值变化事件</p>
<ty-radio v-model="valueB" label="4" @change="change">选项1</ty-radio>
<ty-radio v-model="valueB" label="5" @change="change">选项2</ty-radio>
<ty-radio v-model="valueB" label="6" @change="change">选项3</ty-radio>
</div>
</template>
<script>
export default {
name: 'testRadio',
data() {
return {
value: '1',
valueA: 'c',
valueB: '4',
valueC: '3',
address: 'China'
}
},
methods: {
change(n) {
this.$tyMessage({
message: n,
type: 'success'
})
}
}
}
</script>
<style lang='less' scoped>
.testRadio {
padding: 20px;
width: 100%;
height: 100%;
p {
margin: 10px 0;
}
.ty-radio {
margin: 10px;
}
}
</style>
效果
其他
后续发现可使用
provide和inject来实现group稍微方便一些