302 lines
6.5 KiB
Vue
302 lines
6.5 KiB
Vue
|
<template>
|
||
|
<view
|
||
|
class="ui-radio ss-flex ss-col-center"
|
||
|
@tap="onRaido"
|
||
|
:class="[{ disabled: disabled }, { img: src }, ui]"
|
||
|
:style="[customStyle]"
|
||
|
>
|
||
|
<slot name="leftLabel"></slot>
|
||
|
<view
|
||
|
v-if="!none"
|
||
|
class="ui-radio-input"
|
||
|
:class="[isChecked ? 'cur ' + bg : unbg, src ? 'radius' : 'round']"
|
||
|
></view>
|
||
|
<image class="ui-radio-img radius" v-if="src" :src="src" mode="aspectFill"></image>
|
||
|
<view class="ui-radio-content" v-else>
|
||
|
<slot>
|
||
|
<view class="ui-label-text" :style="[labelStyle]">{{ label }}</view>
|
||
|
</slot>
|
||
|
</view>
|
||
|
<view
|
||
|
v-if="ui.includes('card')"
|
||
|
class="ui-radio-bg round"
|
||
|
:class="[isChecked ? 'cur ' + bg : '']"
|
||
|
></view>
|
||
|
</view>
|
||
|
</template>
|
||
|
|
||
|
<script setup>
|
||
|
/**
|
||
|
* 单选 - radio
|
||
|
*
|
||
|
*
|
||
|
* property {Object} customStyle - 自定义样式
|
||
|
* property {String} ui - radio样式Class
|
||
|
* property {String} modelValue - 绑定值
|
||
|
* property {Boolean} disabled - 是否禁用
|
||
|
* property {String} bg - 选中时背景Class
|
||
|
* property {String} unbg - 未选中时背景Class
|
||
|
* property {String} src - 图片选中radio
|
||
|
* property {String} label - label文本
|
||
|
* property {Boolean} none - 是否隐藏raido按钮
|
||
|
*
|
||
|
* @slot default - 自定义label样式
|
||
|
* @event {Function} change - change事件
|
||
|
*
|
||
|
*/
|
||
|
import { computed, reactive, watchPostEffect, getCurrentInstance } from 'vue';
|
||
|
const vm = getCurrentInstance();
|
||
|
|
||
|
// 组件数据
|
||
|
const state = reactive({
|
||
|
currentValue: false,
|
||
|
});
|
||
|
|
||
|
// 定义事件
|
||
|
const emits = defineEmits(['change', 'update:modelValue']);
|
||
|
|
||
|
// 接收参数
|
||
|
const props = defineProps({
|
||
|
customStyle: {
|
||
|
type: Object,
|
||
|
default: () => ({}),
|
||
|
},
|
||
|
ui: {
|
||
|
type: String,
|
||
|
default: 'check', //check line
|
||
|
},
|
||
|
modelValue: {
|
||
|
type: [String, Number, Boolean],
|
||
|
default: false,
|
||
|
},
|
||
|
disabled: {
|
||
|
type: Boolean,
|
||
|
default: false,
|
||
|
},
|
||
|
bg: {
|
||
|
type: String,
|
||
|
default: 'ui-BG-Main',
|
||
|
},
|
||
|
unbg: {
|
||
|
type: String,
|
||
|
default: 'borderss',
|
||
|
},
|
||
|
src: {
|
||
|
type: String,
|
||
|
default: '',
|
||
|
},
|
||
|
label: {
|
||
|
type: String,
|
||
|
default: '',
|
||
|
},
|
||
|
labelStyle: {
|
||
|
type: Object,
|
||
|
default: () => ({}),
|
||
|
},
|
||
|
none: {
|
||
|
type: Boolean,
|
||
|
default: false,
|
||
|
},
|
||
|
});
|
||
|
|
||
|
watchPostEffect(() => {
|
||
|
state.currentValue = props.modelValue;
|
||
|
emits('update:modelValue', state.currentValue);
|
||
|
});
|
||
|
|
||
|
// 是否选中
|
||
|
const isChecked = computed(() => state.currentValue);
|
||
|
|
||
|
// 点击
|
||
|
const onRaido = () => {
|
||
|
if (props.disabled) return;
|
||
|
state.currentValue = !state.currentValue;
|
||
|
emits('update:modelValue', state.currentValue);
|
||
|
emits('change', {
|
||
|
label: props.label,
|
||
|
value: state.currentValue,
|
||
|
});
|
||
|
};
|
||
|
</script>
|
||
|
|
||
|
<style lang="scss" scoped>
|
||
|
.ui-radio {
|
||
|
display: flex;
|
||
|
align-items: center;
|
||
|
margin: 0 0.5em 0 0;
|
||
|
height: 18px;
|
||
|
.ui-radio-input {
|
||
|
margin: 0 0.5em 0 0;
|
||
|
display: inline-block;
|
||
|
width: 18px;
|
||
|
height: 18px;
|
||
|
vertical-align: middle;
|
||
|
line-height: 18px;
|
||
|
|
||
|
&::before {
|
||
|
content: '';
|
||
|
position: absolute;
|
||
|
width: 0;
|
||
|
height: 0;
|
||
|
background-color: currentColor;
|
||
|
border-radius: 18px;
|
||
|
@include position-center;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
.ui-radio-input.cur {
|
||
|
position: relative;
|
||
|
|
||
|
&::before {
|
||
|
width: 10px;
|
||
|
height: 10px;
|
||
|
transition: $transition-base;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
&:last-child {
|
||
|
margin: 0 0.14286em;
|
||
|
}
|
||
|
|
||
|
&.check {
|
||
|
.ui-radio-input {
|
||
|
&::before {
|
||
|
font-family: 'colorui';
|
||
|
content: '\e69f';
|
||
|
width: 18px;
|
||
|
height: 18px;
|
||
|
font-size: 0;
|
||
|
background-color: transparent;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
.ui-radio-input.cur {
|
||
|
&::before {
|
||
|
width: 18px;
|
||
|
height: 18px;
|
||
|
font-size: 1em;
|
||
|
transform: scale(0.8);
|
||
|
text-align: center;
|
||
|
line-height: 18px;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
&.line {
|
||
|
.ui-radio-input.cur {
|
||
|
&::before {
|
||
|
width: calc(100% - 2px);
|
||
|
height: calc(100% - 2px);
|
||
|
background-color: var(--ui-BG);
|
||
|
}
|
||
|
|
||
|
&::after {
|
||
|
content: '';
|
||
|
position: absolute;
|
||
|
width: 10px;
|
||
|
height: 10px;
|
||
|
background-color: inherit;
|
||
|
border-radius: 50%;
|
||
|
@include position-center;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
&.lg {
|
||
|
.ui-radio-input {
|
||
|
font-size: 18px;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
&.img {
|
||
|
position: relative;
|
||
|
margin: 0 0.28572em 0;
|
||
|
|
||
|
.ui-radio-input {
|
||
|
width: 42px;
|
||
|
height: 42px;
|
||
|
border-radius: 0px;
|
||
|
position: absolute;
|
||
|
margin: 0;
|
||
|
left: -1px;
|
||
|
top: -1px;
|
||
|
|
||
|
&::before {
|
||
|
width: 40px;
|
||
|
height: 40px;
|
||
|
border-radius: $radius;
|
||
|
}
|
||
|
|
||
|
&.cur {
|
||
|
width: 44px;
|
||
|
height: 44px;
|
||
|
top: -2px;
|
||
|
left: -2px;
|
||
|
border-radius: 7px !important;
|
||
|
opacity: 0.8;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
.ui-radio-img {
|
||
|
width: 40px;
|
||
|
height: 40px;
|
||
|
display: block;
|
||
|
overflow: hidden;
|
||
|
border-radius: 10px;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
&.card {
|
||
|
display: flex;
|
||
|
margin: 30rpx;
|
||
|
padding: 30rpx;
|
||
|
position: relative;
|
||
|
border-radius: $radius !important;
|
||
|
flex-direction: row-reverse;
|
||
|
justify-content: space-between;
|
||
|
|
||
|
.ui-radio-bg {
|
||
|
content: '';
|
||
|
position: absolute;
|
||
|
width: 200%;
|
||
|
height: 200%;
|
||
|
transform: scale(0.5);
|
||
|
border-radius: #{$radius * 2} !important;
|
||
|
z-index: 0;
|
||
|
left: 0;
|
||
|
top: 0;
|
||
|
transform-origin: 0 0;
|
||
|
background-color: var(--ui-BG);
|
||
|
}
|
||
|
|
||
|
.ui-radio-input {
|
||
|
position: relative;
|
||
|
z-index: 1;
|
||
|
margin-right: 0;
|
||
|
}
|
||
|
|
||
|
.ui-radio-bg::after {
|
||
|
content: '';
|
||
|
position: absolute;
|
||
|
width: calc(200% - 16px);
|
||
|
height: calc(200% - 16px);
|
||
|
transform: scale(0.5);
|
||
|
transform-origin: 0 0;
|
||
|
background-color: var(--ui-BG) !important;
|
||
|
left: 4px;
|
||
|
top: 4px;
|
||
|
border-radius: #{$radius * 2 + 8} !important;
|
||
|
z-index: 0;
|
||
|
}
|
||
|
|
||
|
.ui-radio-content {
|
||
|
position: relative;
|
||
|
z-index: 1;
|
||
|
display: flex;
|
||
|
align-items: center;
|
||
|
flex: 1;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
</style>
|