uniapp下單選框的實(shí)現(xiàn)方法詳解
uniapp官方雖然提供了uni-data-checkbox,含括了單選和多選框功能。但是它功能實(shí)在不能滿足需求:
- 單選框不支持再次點(diǎn)擊取消
- 無法與父組件的數(shù)據(jù)源進(jìn)行聯(lián)動(dòng),無法實(shí)現(xiàn)如多規(guī)格選擇的那種聯(lián)動(dòng)
- 源碼每次點(diǎn)擊都是對數(shù)據(jù)源進(jìn)行拷貝,然后再進(jìn)行json解析等操作,看著就很不靠譜,數(shù)據(jù)量大必然有性能問題。
其實(shí)我放棄uni-data-checkbox,選擇自己實(shí)現(xiàn)也是因?yàn)樯唐芬?guī)格展示是比較復(fù)雜的,不自己實(shí)現(xiàn)的話無法達(dá)到目的:

看圖中,三組規(guī)格選項(xiàng)是要相互聯(lián)動(dòng)的,選擇了其中一個(gè)后,就得判斷其余的是否可選。然后我認(rèn)為也可以將已選中的取消。所以得自己實(shí)現(xiàn),好根據(jù)業(yè)務(wù)定制。
代碼如下:
<template>
<!-- uniapp內(nèi)置的單選組件,見https://uniapp.dcloud.io/component/radio.html -->
<radio-group class="checklist-group" @change="change">
<label
class="checklist-box is--tag"
v-for="item in radioData.option"
:class="[radioData.selected === item.id ? 'is-checked' : '', item.disable ? 'is-disable' : '']">
<radio
class="hidden"
:disabled="item.disable"
:value="String(item.id)"
:checked="radioData.selected === item.id" />
<view class="checklist-content">
<text class="checklist-text">{{ item.text }}</text>
</view>
</label>
</radio-group>
</template>
<script setup lang="ts">
const props = defineProps({
// 該id設(shè)計(jì)的目的是為了應(yīng)對數(shù)組,記錄數(shù)組的下標(biāo),這樣父類就不需要遍歷查找了。當(dāng)然也可以根據(jù)業(yè)務(wù)用于其他方面,不需要就不用即可。
id: {
type: [Number, String],
},
/*數(shù)據(jù)源,它的數(shù)據(jù)結(jié)構(gòu)應(yīng)該:{selected:,option:[{id:,disable:,text:,}...]}
其中selected 的值應(yīng)取自option的id。
*/
radioData: {
type: Object,
required: true,
},
});
// 點(diǎn)擊后回調(diào)父類的change方法
const emit = defineEmits(["change"]);
// 點(diǎn)擊后觸發(fā)
function change(e: any) {
// 參數(shù):tag的id;props.id
emit("change", e.detail.value, props.id);
}
</script>
<style lang="scss">
$checked-color: #2979ff;
$border-color: #dcdfe6;
$disable: 0.4;
@mixin flex {
/* #ifndef APP-NVUE */
display: flex;
/* #endif */
}
.checklist-group {
@include flex;
flex-direction: row;
flex-wrap: wrap;
.checklist-box {
@include flex;
flex-direction: row;
align-items: center;
position: relative;
margin: 5px 0;
margin-right: 25px;
.hidden {
position: absolute;
opacity: 0;
}
// 文字樣式
.checklist-content {
@include flex;
flex: 1;
flex-direction: row;
align-items: center;
justify-content: space-between;
.checklist-text {
font-size: 14px;
color: #666;
margin-left: 5px;
line-height: 14px;
}
}
// 單選樣式
.radio__inner {
@include flex;
/* #ifndef APP-NVUE */
flex-shrink: 0;
box-sizing: border-box;
/* #endif */
justify-content: center;
align-items: center;
position: relative;
width: 16px;
height: 16px;
border: 1px solid $border-color;
border-radius: 16px;
background-color: #fff;
z-index: 1;
.radio__inner-icon {
width: 8px;
height: 8px;
border-radius: 10px;
opacity: 0;
}
}
// 標(biāo)簽樣式
&.is--tag {
margin-right: 10px;
padding: 5px 10px;
border: 1px $border-color solid;
border-radius: 3px;
background-color: #f5f5f5;
.checklist-text {
margin: 0;
color: #666;
}
// 禁用
&.is-disable {
/* #ifdef H5 */
cursor: not-allowed;
/* #endif */
opacity: $disable;
}
&.is-checked {
background-color: $checked-color;
border-color: $checked-color;
.checklist-text {
color: #fff;
}
}
}
}
}
</style>
其實(shí)代碼本身內(nèi)容很少,是樣式的代碼多,我樣式是直接照抄uni-data-checkbox的。
傳入的數(shù)據(jù)結(jié)構(gòu)應(yīng)該是:
interface radio{
selected: number;
option: {
id: number;
text: string;
disable: boolean;
}[];
}
selected和id可以是別的類型,但selected是取值于id
這里得注意,數(shù)據(jù)源必須是響應(yīng)式的,考慮這里肯定是個(gè)對象,那么就是要用reactive去包圍數(shù)據(jù),使其具有響應(yīng)性,否則頁面不會(huì)更新,例如下面:
const radioData= reactive(radio);
PS1:由于vue3規(guī)范建議:子組件不修改父組件的數(shù)據(jù)源,否則會(huì)導(dǎo)致數(shù)據(jù)的變化難以理解。所以change方法中沒有做任何修改數(shù)據(jù)的動(dòng)作。比如將selected直接修改也是完全可以的,但是我這里還是交由父組件去決定如何修改。
PS2:咋一看change方法僅傳遞了當(dāng)前選擇的選項(xiàng),并沒有告知之前的選項(xiàng)是什么,如果要對比前后的時(shí)候不是沒有辦法?其實(shí)selected就是存儲(chǔ)的之前的選項(xiàng),在修改它之前用它作比較即可。
PS3:由于radio本身是不支持選中之后再取消的,我們這里采用將selected賦值為一個(gè)不存在的id,這樣就會(huì)取消選擇了。但是會(huì)報(bào)錯(cuò):
uni-shared.es.js:470 Uncaught TypeError: Cannot destructure property 'id' of 'el' as it is null.
at normalizeTarget (uni-shared.es.js:470:13)
at createNativeEvent (uni-h5.es.js:1260:13)
at $nne (uni-h5.es.js:1234:15)
at HTMLElement.invoker (vue.runtime.esm.js:9397:19)
但是不影響功能哈。
PS4:目前僅在H5下測試功能時(shí)正常的。
總結(jié)
到此這篇關(guān)于uniapp下單選框?qū)崿F(xiàn)的文章就介紹到這了,更多相關(guān)uniapp下單選框?qū)崿F(xiàn)內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
ECharts實(shí)現(xiàn)數(shù)據(jù)超出Y軸最大值max但不隱藏
這篇文章主要為大家介紹了ECharts實(shí)現(xiàn)數(shù)據(jù)超出Y軸最大值max但不隱藏實(shí)現(xiàn)示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-10-10
JavaScript設(shè)計(jì)模式之策略模式實(shí)現(xiàn)原理詳解
這篇文章主要介紹了JavaScript設(shè)計(jì)模式之策略模式實(shí)現(xiàn)原理詳解,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-05-05
javascript適合移動(dòng)端的日期時(shí)間拾取器
這篇文章主要介紹了javascript適合移動(dòng)端的日期時(shí)間拾取器,提供了友好的日期和時(shí)間選擇操作界面,需要的朋友可以參考下2015-11-11
javascript通過元素id和name直接取得元素的方法
這篇文章主要介紹了javascript通過元素id和name直接取得元素的方法,涉及javascript獲取元素的相關(guān)技巧,非常具有實(shí)用價(jià)值,需要的朋友可以參考下2015-04-04
echarts柱狀圖坐標(biāo)軸內(nèi)容顯示不全的兩種解決辦法
本文主要介紹了echarts柱狀圖坐標(biāo)軸內(nèi)容顯示不全的兩種解決辦法,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2023-05-05

