Vue组件-列表形式穿梭框
组件:公共 ShuttleBox

<!---------------------------------------------------------------------------- @description:列表形式穿梭框 @author:王浩 @date:Created in 2022/1/20 11:46 @modified By: @version: 1.0.0 ----------------------------------------------------------------------------><template> <div class="shuttle-box" :style="{ height }"> <div class="shuttle-box-left"> <p>{{ titleObj.leftTitle }}</p> <div class="shuttle-box-content"> <slot name="left" /> </div> </div> <div class="shuttle-box-center"> <sg-button @click="toRight" :disabled="disabledLeft" type="primary" size="mini" icon="sg-icon-d-arrow-left" /> <sg-button @click="toLeft" type="primary" size="mini" icon="sg-icon-d-arrow-right" /> </div> <div class="shuttle-box-right"> <p>{{ titleObj.rightTitle }}</p> <div class="shuttle-box-content"> <slot name="right" /> </div> </div> </div></template><script>export default { name: "ShuttleBox", props: { /** * @description:穿梭框的高度 */ height: { type: String, default: "460px", }, /** * @description:禁用到到右去按钮 */ disabledLeft: { type: Boolean, default: false, }, /** * @description:禁用到到左去按钮 */ disabledRight: { type: Boolean, default: false, }, /** * @description:左右两侧标题 */ titleObj: { type: Object, default: () => { return { leftTitle: "选择数据", rightTitle: "已选择数据", }; }, }, }, data() { return {}; }, methods: { toRight() { this.$emit("toRight"); }, toLeft() { this.$emit("toLeft"); }, },};</script><style scoped lang="scss">$_WIDTH_100: 100%;.shuttle-box { width: $_WIDTH_100; background-color: rgba(255, 255, 255, 1); display: flex; &-left { width: calc((#{$_WIDTH_100} - 90px) / 2); } &-center { width: 200px; display: flex; flex-direction: column; justify-content: center; align-items: center; button:first-child { margin-bottom: 20px; } /deep/ .sg-button { margin-left: 0; color: #ffffff; font-size: 20px; font-weight: 900; } } &-right { width: calc((#{$_WIDTH_100} - 400px) / 2); } .shuttle-box-left, .shuttle-box-right { width: 100%; border-radius: 8px; box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.08); padding-left: 10px; padding-right: 10px; p { height: 40px; line-height: 40px; margin-block-start: 0; margin-block-end: 0; margin-inline-start: 0; margin-inline-end: 0; } .shuttle-box-content { width: 100%; margin-top: 12px; height: calc(100% - 40px - 12px - 12px); } }}</style>
在组件中引用:shuttle_box.vue
<template> <div> <div> <div class="level"> <!-- 左边框框 --> <div class="transferbox"> <div class="topbox"> <span style="color:#1E90FF;font-size:16px;font-weight: 550;">待选设备</span> </div> <div class="level searchbox"> <el-input v-model="input" placeholder="请输入内容" style="width:300px" /> <el-button type="primary" style="margin:0 0 0 20px">搜索</el-button> </div> <el-table ref="multipleTable" :data="currentPageData" highlight-current-row tooltip-effect="dark" height="460" style="width: 100%;height:460px;cursor:pointer;" :row-style="setColor" @current-change="lineClick" > <el-table-column label="日期" width="430" > <template slot-scope="scope">{{ scope.row.date }}</template> </el-table-column> </el-table> <!-- 分页 --> <el-pagination :current-page="listForm.currentPage" :page-sizes="[5,10,25,50,100,200]" :page-size="listForm.pageSize" layout="total, sizes, prev, pager, next, jumper" :total="totalSize" style="margin-bottom:10px;margin-top:16px" @size-change="handleSizeChange" @current-change="handleCurrentChange" /> </div> <!-- 中间按钮 --> <div class="vertical center3 centrebtn"> <el-button type="primary" icon="el-icon-arrow-right" @click="singleSel()" /> <el-button type="primary" style="margin:20px 0 0 0" icon="el-icon-d-arrow-right" @click="mutiSel()" /> </div> <!-- 右边框框 --> <div class="transferbox"> <div class="topbox"> <span style="color:#1E90FF;font-size:16px;font-weight: 550;">已选设备</span> </div> <el-table ref="multipleTable" :data="yxData" tooltip-effect="dark" height="500" style="width: 100%;height:500px;cursor:pointer;" > <el-table-column label="日期" width="360" > <template slot-scope="scope">{{ scope.row.date }}</template> </el-table-column> <el-table-column label="操作" width="70"> <template slot-scope="scope"> <div> <span class="look" style="color: #FF0000" title @click="deletedetails(scope.row)">删除</span> </div> </template> </el-table-column> </el-table> </div> </div> <div class="dialog-btn"> <el-button>取消</el-button> <el-button type="primary">确定</el-button> </div> </div> </div></template><script>export default { data() { return { // 分页 listForm: { name: '', type: '', currentPage: 1, pageSize: 25, placeName: '', eui: '' }, totalSize: 0, input: '', currentPageData: [{ date: '2016-05-03' }, { date: '2016-05-02' }, { date: '2016-05-04' }, { date: '2016-05-01' }, { date: '2016-05-04' }, { date: '2016-05-01' } ], multipleSelection: [], currentRowData: null, yxData: [] } }, // 生命周期 - 挂载完成(可以访问DOM元素) mounted() { }, methods: { // 页容量改变 handleSizeChange(val) { console.log(val) this.listForm.pageSize = val this.deviceList() }, // 改变当前页 handleCurrentChange(val) { console.log(val) this.listForm.currentPage = val this.deviceList() }, // 选中 lineClick(val) { console.log(val) this.currentRowData = val }, // 单选 singleSel() { if (this.currentRowData !== null) { if (JSON.stringify(this.yxData).indexOf(JSON.stringify(this.currentRowData)) === -1) { this.yxData.push(this.currentRowData) } } }, // 选择整个页面 mutiSel() { if (this.currentRowData !== null) { this.currentPageData.forEach((item, index) => { if (JSON.stringify(this.yxData).indexOf(JSON.stringify(item)) === -1) { this.yxData.push(item) this.setColor(item, index) } }) } }, // 删除 deletedetails(row) { if (JSON.stringify(this.yxData).indexOf(JSON.stringify(row)) !== -1) { var index = this.yxData.indexOf(row) this.yxData.splice(index, 1) } }, // 选中之后设置颜色 setColor({ row, rowIndex }) { if (JSON.stringify(this.yxData).indexOf(JSON.stringify(row)) !== -1) { return { color: 'red' } } } }}</script><style lang="scss" scoped> .transferbox{ height: 600px; width: 36%;//右边盒子的宽占比 border: 3px solid #009cde; .topbox{ margin: 10px 10px; } .searchbox{ margin: 0 0 0 10px; } } .centrebtn{ width: 80px; height: 600px; margin: 0 10px 0 10px; background-color: #009cde; background-image: radial-gradient(circle farthest-side at left bottom,#009cde,#004687c7 125%); color: #ffff; } /* 水平居中 */ .center1{ display: flex; justify-content: center; } /* 垂直居中 */ .center2{ display: flex; align-items: center; } /* 垂直水平居中 */ .center3{ display: flex; align-items: center; justify-content: center; } /* 水平布局 */ .level{ display: flex; flex-direction: row; } // 垂直布局 .vertical{ display: flex; flex-direction: column; }</style>
demo

<!-- * @description: * @author: wanghao * @Date: 2022-01-24 14:19:20 * @Modified By: * @version: 1.0.0--><template><div class="hello"> <div class="one"> <p v-for="msg in message" @click="clickP(msg)" :key="msg">{{ msg.name }}</p> </div> <div class="two"> <p v-for="data in newdatas" @click="deleteP(data)" :key="data">{{ data.name }}</p> </div> </div></template><script> export default { data() { return { msg: "哈哈", hh: "呵呵", message: [ { id: 1, name: "第一个" }, { id: 2, name: "第二个" }, ], datas: [], newdatas: [], }; }, mounted: function () {}, methods: { clickP: function (msg) { this.datas.push(msg); this.newdatas = this.unique(this.datas); }, deleteP: function (data) { for (let i = 0; i < this.newdatas.length; i++) { console.log("输出"); console.log(this.newdatas[i]); if (this.newdatas[i].id == data.id) { this.newdatas.splice(i, 1); this.datas.splice(0, this.datas.length); } } }, // 除重 unique: function (a) { let res = []; for (let i = 0, len = a.length; i < len; i++) { let item = a[i]; res.indexOf(item) === -1 && res.push(item); } return res; }, }, };</script><!-- Add "scoped" attribute to limit CSS to this component only --><style scoped> .hello { display: flex; justify-content: center; } .one, .two { width: 300px; height: 400px; outline: 1px solid red; }</style>
Vue组件-版本号输入框
组件:公共 VersionNumber
<!---------------------------------------------------------------------------- @description:版本号输入框 @author:张时友 @date:Created in 2022/3/3 16:51 @modified By: @version: 1.0.0 ----------------------------------------------------------------------------><template> <div class="version-number" :class="disabled ? 'is-disabled' : ''"> <span class="separator" v-if="showV">V</span> <sg-input v-model.trim="viewList[0]" oninput="value=value.replace(/[^\d]/g,'')" :disabled="disabled" v-bind="$attrs" ></sg-input> <span class="separator">{{ separator }}</span> <sg-input v-model.trim="viewList[1]" oninput="value=value.replace(/[^\d]/g,'')" :disabled="disabled" v-bind="$attrs" ></sg-input> <span class="separator">{{ separator }}</span> <sg-input v-model.trim="viewList[2]" oninput="value=value.replace(/[^\d]/g,'')" :disabled="disabled" v-bind="$attrs" ></sg-input> <div class="icon" v-if="showClear" @click="clear()"> <i class="sg-icon-circle-close"></i> </div> </div></template><script>export default { name: "versionNumber", props: { /** * @description: v-model绑定的值 * @param {string} * @default: 1.2.2 * */ value: { type: String, default: "", }, /** * @description: 每个数字之间的分隔符 * @param {string} * @default: . * */ separator: { type: String, default: ".", }, /** * @description: 是否显示前面的字母V * @param {boolean} * @default:true * */ showV: { type: Boolean, default: true, }, /** * @description: 是否禁用 * @param {boolean} * @default:false * */ disabled: { type: Boolean, default: false, }, /** * @description: 是否显示清空按钮 * @param {boolean} * @default:true * */ clearable: { type: Boolean, default: false, }, }, data() { return { viewList: [], blackValue: "", isHasV: false, }; }, computed: { showClear() { console.log(this.viewList.length); if (this.clearable && this.viewList.length > 1) { return true; } else { return false; } }, }, created() { this.init(); }, methods: { /** * @description:初始化数据 * @param , * @returns null **/ init() { this.viewList = ["", "", ""]; this.blackValue = this.value; const _C = this.blackValue.charCodeAt(0); if ((_C >= 65 && _C <= 90) || (_C >= 97 && _C <= 122)) { this.blackValue = this.blackValue.substring(1); this.isHasV = true; } this.viewList = this.blackValue.split(this.separator); }, /** * @description:处理数据给父元素 * @param , * @returns null **/ valueHandler() { let list = this.viewList; if (this.isHasV) { return "V" + list.join(this.separator); } return list.join(this.separator); }, /** * @description:清空事件 * @param , * @returns null **/ clear() { this.viewList = []; }, }, watch: { value() { this.init(); }, /** * @description:将数据绑定给v-model * @param , * @returns null **/ viewList: { deep: true, handler() { this.$emit("input", this.valueHandler()); }, }, },};</script><style scoped lang="scss">.version-number { width: 100%; border: 1px solid #d9d9d9; display: flex; background-color: #ffffff; /deep/ .sg-input__inner { border: 0; border-radius: 0; } .separator { padding: 0 10px; } .icon { box-sizing: content-box; padding: 0 12px; visibility: hidden; }}.version-number:hover .icon { visibility: visible; cursor: pointer;}.is-disabled { background-color: #eee;}</style>
在组件中引用:other.vue

<!---------------------------------------------------------------------------- @description:小功能性组件 @author:王浩 @date:Created in 2022/3/4 09:28 @modified By: @version: 1.0.0 ----------------------------------------------------------------------------><template> <div class="other"> <sg-row> <sg-col :span="8"> <div>{{ form }}</div> <sg-form :rules="rules" ref="ruleForm" :model="form" label-width="100px"> <sg-form-item label="版本号" prop="vn"> <VersionNumber v-model="form.vn" clearable :disabled="false" /> </sg-form-item> <sg-form-item> <sg-button type="primary" @click="submitForm('ruleForm')">立即创建</sg-button> </sg-form-item> </sg-form> </sg-col> </sg-row> </div></template><script>import VersionNumber from "_c/VersionNumber/index";import * as valid from "@/utils/rules";export default { name: "Other", components: { VersionNumber, }, data() { return { form: { vn: "0.0.3", }, rules: { vn: [ { required: true, message: "请输入活动名称", trigger: "blur" }, { validator: valid.numberValidUppers, message: "不允许输入特殊字符", trigger: "blur" }, ], }, }; }, methods: { submitForm(formName) { this.$refs[formName].validate((valid) => { if (valid) { console.log("submitForm"); // alert("submit!"); } else { console.log("error submit!!"); return false; } }); }, },};</script><style scoped lang="scss"></style>
Vue-穿梭框组件
附件:代码
<template> <div class="usereq"> <el-row :gutter="10"> <el-col :span="14"><div class="grid-content">全部设备</div></el-col> <el-col :span="2"><div class="grid-content"></div></el-col> <el-col :span="8"><div class="grid-content">已选设备</div></el-col> </el-row> <el-row :gutter="10"> <el-col :span="14"> <div class="left_content"> <el-row :gutter="10"> <el-col :span="7"> <el-select v-model="condition_equipment" multiple placeholder="全部设备"> <el-option v-for="item in condition_equipmentArr" :key="item.value" :label="item.label" :value="item.value" ></el-option> </el-select> </el-col> <el-col :span="7"> <el-select v-model="condition_area" multiple placeholder="全部区域"> <el-option v-for="item in condition_areaArr" :key="item.value" :label="item.label" :value="item.value" ></el-option> </el-select> </el-col> <el-col :span="10"> <el-input style="border-radius:5px;" v-model="equipment[2]" placeholder="搜索" prefix-icon="el-icon-search"></el-input> </el-col> </el-row> <el-row :gutter="10" style="padding:20px 0;margin-bottom:0;border-top:1px solid #323541;border-bottom:1px solid #323541;"> <el-col class="center" :span="3"><el-checkbox class="grid-content able_checkbox" :indeterminate="isIndeterminate" v-model="checkAll" @change="handleCheckAllChange">全选</el-checkbox></el-col> <el-col :span="1"><div class="grid-content"></div></el-col> <el-col :span="7"><div class="grid-content">设备编号</div></el-col> <el-col :span="6"><div class="grid-content">设备类型</div></el-col> <el-col :span="2"><div class="grid-content">区域</div></el-col> <el-col :span="5"><div class="grid-content"></div></el-col> </el-row> <el-checkbox-group v-model="checkedleft" @change="handleCheckedLeftChange"> <el-row v-for="(equipmentInfos, index) in equipmentInfo" :key="index" :gutter="10" style="margin:0;padding:10px 0;border-bottom:1px solid #323541;"> <div v-if="equipmentInfos.warn"> <el-col class="center" :span="3"> <el-checkbox class="prohibit_checkbox" disabled :label="equipmentInfos" :key="equipmentInfos.number"></el-checkbox> </el-col> <el-col :span="1"><div class="grid-content grid-Prohibit">{{index+1}}</div></el-col> <el-col :span="7"><div class="grid-content grid-Prohibit">{{equipmentInfos.number}}</div></el-col> <el-col :span="6"><div class="grid-content grid-Prohibit">{{equipmentInfos.type}}</div></el-col> <el-col :span="2"><div class="grid-content grid-Prohibit">{{equipmentInfos.area}}</div></el-col> <el-col :span="5"><div class="grid-content grid-Prohibit">{{equipmentInfos.warn}}</div></el-col> </div> <div v-else> <el-col class="center" :span="3"> <el-checkbox class="able_checkbox" :label="equipmentInfos" :key="equipmentInfos.number"></el-checkbox> </el-col> <el-col :span="1"><div class="grid-content">{{index+1}}</div></el-col> <el-col :span="7"><div class="grid-content">{{equipmentInfos.number}}</div></el-col> <el-col :span="6"><div class="grid-content">{{equipmentInfos.type}}</div></el-col> <el-col :span="2"><div class="grid-content">{{equipmentInfos.area}}</div></el-col> </div> </el-row> </el-checkbox-group> </div> </el-col> <el-col :span="2"> <div class="center_content"> <div class="center_content_r"> <div class="rule_btn rule_btn_left" icon="el-icon-plus" type="warning" @click="PutDataToRight()"> <img src="./img/left.png"> </div> <div style="margin-top:20px" class="rule_btn rule_btn_right" icon="el-icon-plus" type="warning" @click="PutDataToLeft()"> <img src="./img/left.png"> </div> </div> </div> </el-col> <el-col :span="8"> <div class="left_content"> <el-row :gutter="10" style="padding:20px 0;margin-bottom:0;border-bottom:1px solid #323541;"> <el-col class="center" :span="6"><el-checkbox class="grid-content able_checkbox" :indeterminate="risIndeterminate" v-model="rcheckAll" @change="rhandleCheckAllChange">全选</el-checkbox></el-col> <el-col :span="4"><div class="grid-content"></div></el-col> <el-col :span="14"><div class="grid-content">设备编号</div></el-col> </el-row> <el-checkbox-group v-model="rcheckedleft" @change="rhandleCheckedLeftChange"> <el-row v-for="(requipmentInfos, index) in requipmentInfo" :key="index" :gutter="10" style="margin:0;padding:10px 0;border-bottom:1px solid #323541;"> <el-col class="center" :span="6"> <el-checkbox class="able_checkbox" :label="requipmentInfos" :key="requipmentInfos.number"></el-checkbox> </el-col> <el-col :span="4"><div class="grid-content">{{index+1}}</div></el-col> <el-col :span="14"><div class="grid-content">{{requipmentInfos.number}}</div></el-col> </el-row> </el-checkbox-group> </div> </el-col> </el-row> </div></template><script>export default { data() { return { equipment: ['', '', ''], // 查询条件 checkAll: false, isIndeterminate: true, checkedleft: [], rcheckAll: false, risIndeterminate: true, rcheckedleft: [], condition_equipment: '', condition_area: '', condition_equipmentArr: [], // 查询条件code condition_areaArr: [], equipmentInfo: [ { number: 'AHU-L28-01', type: 'AHU', area: 'L55' }, { number: 'AHU-L28-02', type: 'AHU', area: 'L55', warn: '数据不足' }, { number: 'AHU-L28-03', type: 'AHU', area: 'L55' } ], requipmentInfo: [ { number: 'AHU-L28-05', type: 'AHU', area: 'L55' } ] } }, methods: { handleCheckAllChange(val) { this.checkedleft = val ? this.equipmentInfo : [] this.isIndeterminate = false }, handleCheckedLeftChange(v) { const checkedCount = v.length this.checkAll = checkedCount === this.equipmentInfo.length this.isIndeterminate = checkedCount > 0 && checkedCount < this.equipmentInfo.length }, rhandleCheckAllChange(val) { this.rcheckedleft = val ? this.requipmentInfo : [] this.risIndeterminate = false }, rhandleCheckedLeftChange(v) { const checkedCount = v.length this.rcheckAll = checkedCount === this.requipmentInfo.length this.risIndeterminate = checkedCount > 0 && checkedCount < this.requipmentInfo.length }, PutDataToRight() { console.log(JSON.parse(JSON.stringify(this.checkedleft))) this.requipmentInfo = this.handleConcatArr(this.requipmentInfo, this.checkedleft) this.handleRemoveTabList(this.checkedleft, this.equipmentInfo) console.log(this.equipmentInfo) this.checkedleft = [] }, PutDataToLeft() { this.equipmentInfo = this.handleConcatArr(this.equipmentInfo, this.rcheckedleft) this.handleRemoveTabList(this.rcheckedleft, this.requipmentInfo) this.rcheckedleft = [] }, handleConcatArr(selectArr, nowSelectData) { let arr = [] arr = arr.concat(selectArr, nowSelectData) return arr }, handleRemoveTabList(checkArr, originalArr) { for (const item of checkArr) { if (originalArr.indexOf(item) > -1) { this.$nextTick(() => { originalArr.splice(originalArr.indexOf(item), 1) }) } } } }}</script><style lang="scss" scoped>.usereq{ .el-row{ margin: 20px 0 !important; } .grid-content,.grid-Prohibit { text-align: center; color: #fff; font-size: 16px; border-radius: 4px; min-height: 36px; } .grid-Prohibit { color: #414346; } .grid-content /deep/.el-checkbox__label{ font-size:16px; } .left_content{ height:500px; padding:0 20px 20px 20px; overflow-y: auto; background: #020913; border-radius:5px; } .center_content{ height:500px; display: flex; justify-content: center; align-items: center; border-radius:5px; } .el-select,/deep/ .el-input--small .el-input__inner{ color:#616B80; width:100%; background: #152841; border-color:#152841; border-radius: 5px; } /deep/ .el-checkbox-group .el-checkbox__label{ display: none; } .able_checkbox /deep/ .el-checkbox__inner { border-color: #868692; background: #020913; } .prohibit_checkbox /deep/.el-checkbox__inner{ border-color: #414346; background: #020913; } .center{ text-align: center; } .center_content_r{ width:75%; height:180px; } .rule_btn{ width:100%; height:60px; background:#152841; float:left; border:none; } .rule_btn_left, .rule_btn_right{ background: #152841; display: flex; align-items: center; justify-content: center; cursor: pointer; border-radius:3px; } .rule_btn_left img{ transform:rotate(180deg); } .rule_btn_left:hover, .rule_btn_right:hover{ background:#1E3A5F }}</style>