二次封装多选框组件

<CheckListWithIcon v-model="checkList" :options="industryOptions" />

const checkList = ref(\[\]);

const industryOptions = ref([

{ value: '0', label: '带发货' },

{ value: '1', label: '运输中' },

{ value: '2', label: '已到货' }

]);

<template>

<div class="checklist-with-icon">

<el-checkbox-group v-model="innerValue" class="checkbox-group">

<div v-for="option in options" :key="option.value" class="checkbox-item" @click="toggleOption(option.value)">

<component :is="loadImageAsset(

innerValue.includes(option.value)

? 'multipleselectio.png'

: 'multiplechoice.png'

)" class="icon" />

<span class="custom-label">{{ option.label }}</span>

</div>

</el-checkbox-group>

</div>

</template>

<script setup>

import { ref, watch } from 'vue'

import { loadImageAsset } from '@/utils/loadImageAsset.js'

const props = defineProps({

modelValue: {

type: Array,

default: () => \[\]

},

options: {

type: Array,

default: () => \[\]

}

})

const emit = defineEmits('update:modelValue')

// 内部值,用于双向绑定

const innerValue = ref(Array.isArray(props.modelValue) ? ...props.modelValue : \[\])

// 监听内部值变化,同步到父组件

watch(innerValue, (newVal) => {

emit('update:modelValue', newVal)

}, { deep: true }) // 数组内部变化也能监听到

// 监听外部值变化

watch(() => props.modelValue, (newVal) => {

if (Array.isArray(newVal)) {

innerValue.value = ...newVal

}

}, { deep: true })

// 切换选项的选中状态(核心方法)

const toggleOption = (value) => {

const index = innerValue.value.indexOf(value)

if (index > -1) {

// 已选中,移除

innerValue.value = innerValue.value.filter(item => item !== value)

} else {

// 未选中,添加

innerValue.value = ...innerValue.value, value

}

}

</script>

<style scoped>

.checklist-with-icon {

display: flex;

align-items: center;

gap: 16px;

flex-wrap: nowrap;

/* 防止换行 */

}

.checkbox-item {

display: flex;

align-items: center;

gap: 8px;

cursor: pointer;

user-select: none;

/* 防止文字被选中 */

}

.icon {

width: 40px;

height: 40px;

flex-shrink: 0;

}

/* 自定义标签样式,替代原生复选框标签 */

.custom-label {

margin: 20px 30px;

padding: 0;

line-height: 1;

font-size: 40px;

cursor: pointer;

font-weight: 400;

color: #656C83;

line-height: 21px;

text-align: left;

font-style: normal;

text-transform: none;

/* margin-left: 20px; */

}

.checkbox-group {

display: flex;

}

</style>

<style>

.el-checkbox__input {

cursor: pointer;

display: inline-flex;

outline: none;

position: relative;

display: none;

white-space: nowrap;

}

</style>

相关推荐
u0111026754 分钟前
Vue 3 统一右侧编辑面板:布局、滚动与底部操作区设计
javascript·vue.js·ecmascript
change_fate6 分钟前
Vue 3 Composable 函数指南
前端·javascript·vue.js
tryCbest9 分钟前
Vue3——第 9 篇:组件通信全攻略(下)——Provide / Inject 与事件总线
前端·javascript·vue.js
lichenyang45311 分钟前
技术穿刺怎么做?以企业知识库问答为例,验证风险、方案和投入
前端·后端
PedroQue9935 分钟前
uni-app x工程化实战:从页面堆到可维护架构
前端·uni-app
开开心心_Every1 小时前
免费压缩软件WinRAR无弹窗、广告干扰
java·开发语言·前端·spring·智能手机·word·winrar
特立独行的猫A1 小时前
用仓颉语言写桌面应用:cj-tauri 框架与 AI 笔记软件 cjnote 实战
前端
特立独行的猫A1 小时前
我为什么推荐用仓颉语言的cj-tauri 写桌面应用(附 cjnote 最小的markdown笔记AI软件)
前端
纸片人1 小时前
牛一越界,大屏 3 秒飞到它身边:我用真实卫星数据 + Three.js 做了个 3D 智慧牧场
前端
cc_瀚海知行1 小时前
工具调用 6|助手什么时候该停下来?
java·服务器·前端·人工智能·python·ai