vue3 组件之穿梭框2.0
如图所示,没有传统穿梭框中间的箭头,操作更加方便,左侧选择后进入到右侧,并且可以对右侧所选项进行删除,从而左侧勾选也会对应取消。并且带搜索框。
代码如下:
(涉及到深拷贝的一些知识)
<template> <div style="display: inline-block"> <!-- 下拉选择 --> <el-select class="search-input" v-model="peopleVal" placeholder="请选择" ref="selectPeople" @focus="openDialog" > </el-select> <!--弹窗 --> <el-dialog v-model="dialog" :title="title" @open="openFn" width="630px"> <el-form label-width="70px"> <div class="transfer-view"> <div class="item-label">选择人员</div> <div class="checked-box"> <div class="search-box"> <el-input v-model.trim="searchName" placeholder="请输入关键词" :prefix-icon="Search" @input="searchFn" clearable ></el-input> </div> <el-checkbox v-show="!searchName" :indeterminate="isIndeterminate" v-model="checkAll" @change="handleCheckAllChange" >全选</el-checkbox > <el-checkbox-group @change="handleChecked" v-model="checkList"> <el-checkbox class="checkbox-item" v-for="v in personList" :label="v.id" :key="v.id" > {{ v.realName }} </el-checkbox> </el-checkbox-group> </div> <div class="select-checked-box"> <div class="search-box"> <span class="selected">已选:{{ checkList.length }}人</span> </div> <div class="select-perosn" v-for="v in checkPerson" :key="v.id"> <span> {{ v.realName }} </span> <i class="iconfont icon-a-zujian18719 icon-error" @click="handleRemove(v)" ></i> </div> </div> </div> </el-form> <template #footer> <span class="dialog-footer"> <el-button @click="dialog = false">取消</el-button> <el-button type="primary" @click="submitFn">提交</el-button> </span> </template> </el-dialog> </div> </template>
<script> import { reactive, toRefs, watch } from "vue"; import { Close, Search } from "@element-plus/icons"; import { sysUserApi } from "@/http/projectManagement/underMaintenance.js"; //获取人员列表的接口,自行替换 export default { emits: ["handleCancel", "handleSure"], components: { Close }, props: { dialogFormVisible: { type: Boolean, default: false, }, title: { type: String, require, }, }, setup(props, { emit }) { const data = reactive({ dialog: false, // 弹窗 checkList: [], // 左侧已选数据Id checkPerson: [], // 右侧已选的数据 searchName: "", // 搜索数据 checkAll: false, // 全选 isIndeterminate: false, personList: [], allPersonList: [], // 所有人员 }); watch( () => data.personList, (newVal, oldVal) => { if (data.checkAll) { if (newVal.length > oldVal.length) { data.checkAll = false; data.isIndeterminate = true; } } console.log(newVal, oldVal); } ); //打开弹窗 const openFn = () => { sysUserApi({}).then((res) => { if (res.data.code === 200) { data.personList = res.data.data; data.allPersonList = res.data.data; } }); }; // 选择复选框 const handleChecked = (val) => { handleCheck(data.checkList); let checkedCount = data.checkList.length; data.checkAll = checkedCount === data.personList.length; data.isIndeterminate = checkedCount > 0 && checkedCount < data.personList.length; }; // 深拷贝 const handleCheck = (val) => { let arr = []; val.forEach((v) => { let a = data.allPersonList.filter((item) => item.id === v); if (a.length) { arr.push(...a); } }); data.checkPerson = arr; }; // 全选 const handleCheckAllChange = (val) => { let arr = data.personList.map((v) => v.id); data.checkList = val ? arr : []; val ? handleCheck(arr) : handleCheck([]); data.isIndeterminate = false; }; // 删除 const handleRemove = (val) => { data.checkPerson.forEach((item, index) => { if (item.id === val.id) { data.checkPerson.splice(index, 1); data.checkList.splice(index, 1); } }); if (!data.checkList.length) { data.checkAll = false; data.isIndeterminate = false; } }; // 搜索 const searchFn = () => { let list = []; data.allPersonList.map((item) => { if (item.realName.indexOf(data.searchName) > -1) { list.push(item); } }); data.personList = list; }; // 下拉框信息 const selectInfo = reactive({ selectPeople: null, // 选人dom peopleVal: "", openDialog() { selectInfo.selectPeople.blur(); data.dialog = true; }, }); // 弹窗确定 const submitFn = () => {
data.dialog = false;
let box = [];
data.checkPerson.map((item) => {
box.push(item.realName);
});
selectInfo.peopleVal = box.join(",");
}; return { ...toRefs(data), ...toRefs(selectInfo), // 下拉框信息 openFn, //打开弹窗 submitFn, // 确定 handleCheck, handleCheckAllChange, // 全选事件 handleChecked, // 选择复选框 handleRemove, // 删除 searchFn, // 搜索 Search, // 搜索图标 }; }, }; </script>
<style lang="scss" scoped> /deep/ .el-radio__label { color: #888ea2; } .transfer-view { width: 100%; height: 25rem; display: flex; margin-top: 1rem; .checked-box, .select-checked-box { width: 15rem; height: 25rem; border: 1px solid #eeeeee; border-radius: 8px; padding: 1.31rem; box-sizing: border-box; overflow-y: auto; overflow-x: hidden; } .search-box { font-family: Source Han Sans CN; font-weight: 400; display: flex; height: 2.4rem; justify-content: space-between; align-items: center; color: #fff; margin-bottom: 0.8rem; .selected { color: #888ea2; } } .checked-box { margin-right: 1.25rem; } .item-label { width: 60px; margin-right: 12px; height: 100%; text-align: right; font-weight: 400; } .el-input { width: 12.5rem; height: 2.38rem; /deep/ .el-input__inner { width: 100%; height: 100%; } } .checkbox-item { display: block; margin-top: -5px; line-height: 40px; margin-left: 15px; } .select-perosn { color: #888ea2; display: flex; align-items: center; justify-content: space-between; padding-right: 1rem; box-sizing: border-box; > span { display: inline-block; max-width: 14rem; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; } .icon-error { font-size: 14px; line-height: 14px; cursor: pointer; } } } // /*滚动条里面轨道*/ ::-webkit-scrollbar-track { border-radius: 3px; background: #3d609100; } </style>
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· Manus爆火,是硬核还是营销?
· 终于写完轮子一部分:tcp代理 了,记录一下
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 别再用vector<bool>了!Google高级工程师:这可能是STL最大的设计失误
· 单元测试从入门到精通