You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

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>