| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177 |
- <template>
- <view class="ss-onoff-button" :class="{ checked: isChecked }" @click="toggleSelect">
- <text class="button-label">{{ label }}</text>
- <view class="button-mark">
- <text
- class="form-icon"
- :class="isChecked ? 'form-icon-onoffbutton-checked' : 'form-icon-onoffbutton-unchecked'"
- ></text>
- </view>
- </view>
- </template>
- <script setup>
- import { computed, inject, nextTick } from 'vue'
- const props = defineProps({
- // 字段名称,用于表单校验
- name: {
- type: String,
- required: true
- },
- // 显示标签
- label: {
- type: String,
- required: true
- },
- // 按钮的值
- value: {
- type: [String, Number],
- required: true
- },
- // 宽度设置
- width: {
- type: String,
- default: ''
- },
- // v-model 绑定的值
- modelValue: {
- type: [String, Number, Array],
- default: ''
- },
- // 是否多选模式
- multiple: {
- type: Boolean,
- default: false
- }
- })
- const emit = defineEmits(['update:modelValue', 'change'])
- // 从父组件注入校验相关功能
- const validateField = inject('validateField', () => {})
- // 解析 modelValue,支持逗号分隔的字符串和数组
- const parseModelValue = (val) => {
- if (!val) return []
-
- // 如果是数组,直接返回字符串数组
- if (Array.isArray(val)) {
- return val.map(v => v.toString())
- }
-
- // 如果是字符串,按逗号分割
- const cleanValue = val.toString().replace(/^,+/, '') // 去掉开头的逗号
- if (cleanValue.includes('|')) {
- return cleanValue.split('|')
- }
- if (cleanValue.includes(',')) {
- return cleanValue.split(',')
- }
- return cleanValue ? [cleanValue] : []
- }
- // 判断当前按钮是否选中
- const isChecked = computed(() => {
- if (props.multiple) {
- const currentValue = parseModelValue(props.modelValue)
- return currentValue.includes(props.value.toString())
- }
- return props.modelValue === props.value
- })
- // 切换选中状态
- const toggleSelect = () => {
- if (props.multiple) {
- // 多选模式
- const currentValue = parseModelValue(props.modelValue)
- const index = currentValue.indexOf(props.value.toString())
- let newValue
-
- if (index === -1) {
- // 添加选项
- newValue = [...currentValue, props.value.toString()]
- } else {
- // 移除选项
- newValue = currentValue.filter(v => v !== props.value.toString())
- }
-
- // 发送更新事件,使用逗号分隔的字符串格式
- const emitValue = newValue.join(',')
- emit('update:modelValue', emitValue)
- emit('change', emitValue, newValue)
- } else {
- // 单选模式
- emit('update:modelValue', props.value)
- emit('change', props.value)
- }
-
- // 触发校验
- nextTick(() => {
- if (props.name) {
- validateField(props.name)
- }
- })
- }
- </script>
- <style lang="scss" scoped>
- /* 引入iconfont样式 */
- @import '../../static/iconfont/iconfont.css';
- .ss-onoff-button {
- position: relative;
- display: inline-flex;
- align-items: center;
- justify-content: center;
- padding: 10rpx 36rpx;
- border: 2rpx solid #BFC1C6;
- border-radius: 4rpx;
- background-color: #fff;
- color: #C3C6CA;
- font-size: 28rpx;
- cursor: pointer;
- transition: all 0.3s ease;
- // margin-right: 20rpx;
- // margin-bottom: 20rpx;
- // min-width: 120rpx;
- &.checked {
- color: #393D51;
- border-color: #393D51;
- // background-color: #F8F9FA;
- }
- .button-label {
- flex: 1;
- text-align: center;
- line-height: 1.2;
- }
- .button-mark {
- position: absolute;
- bottom: 0rpx;
- right: 0rpx;
- width: 36rpx;
- height: 36rpx;
- display: flex;
- align-items: center;
- justify-content: center;
- color: inherit;
- }
- }
- /* 表单组件icon样式 - 完全按照PC端实现 */
- .form-icon {
- font-size: 36rpx;
- font-family: "iconfont";
- }
- .form-icon-onoffbutton-checked::before {
- content: "\e62d";
- }
- .form-icon-onoffbutton-unchecked::before {
- content: "\e62b";
- }
- </style>
|