123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301 |
- <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>
|