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>