vue项目开发 实现自定义Transfer穿梭框效果(结合el-tree)

10 篇文章 0 订阅
3 篇文章 0 订阅
本文展示了如何在Vue项目中实现一个自定义的Transfer穿梭框功能,结合el-tree组件,提供了搜索、全选、单选和多选操作。通过监听树节点和checkbox的变化,动态更新已选择和未选择的数据。用户可以进行业务分组并保存通道配置。
摘要由CSDN通过智能技术生成

vue项目开发 实现自定义Transfer穿梭框效果,结合el-tree

效果图

在这里插入图片描述在这里插入图片描述

实现代码

直接上代码:

// An highlighted block
<template>
  <el-dialog
    :visible="true"
    title="业务分组"
    style="font-size: 18px"
    width="900px"
    :close-on-click-modal="false"
    @close="dialogYwfzShowsBtn"
  >
    <div>
      <el-form ref="form" :model="form" :rules="rules" label-width="80px">
        <el-row :gutter="24">
          <el-col :xl="12" :lg="8" :md="12">
            <el-form-item label="分组名称" label-width="80px" prop="groupName">
              <el-input v-model="form.groupName"></el-input>
            </el-form-item>
          </el-col>
        </el-row>
      </el-form>
      <div class="level">
        <!-- 左边框框 -->
        <div class="transferbox">
          <div class="topbox">
            <span>未选择通道</span>
          </div>
          <div class="level searchbox">
            <el-input
              v-model="filter"
              placeholder="请输入内容"
              style="width: 300px"
            />
            <el-button
              type="primary"
              style="margin: 0 0 0 20px"
              @click="searchClick"
              >搜索</el-button
            >
          </div>
          <div class="contont">
            <el-tree
              :data="orgData"
              :load="getOrgs"
              :props="defaultProps"
              :expand-on-click-node="false"
              :highlight-current="true"
              show-checkbox
              node-key="id"
              ref="tree"
              lazy
              @check-change="handleCheckChange"
              v-show="showTree"
            >
              <span class="custom-tree-node" slot-scope="{ node, data }">
                <span>
                {{ node.label }}
                </span>
              </span>
            </el-tree>
            <el-checkbox
              :indeterminate="isIndeterminate"
              v-model="checkAll"
              @change="handleCheckAllChange"
              v-if="showCheck"
              >全选</el-checkbox
            >
            <div style="margin: 15px 0"></div>
            <el-checkbox-group
              v-model="checkedCities"
              @change="handleCheckedCitiesChange"
            >
              <el-checkbox
                v-for="(item, index) in list"
                :label="item.id"
                :key="index"
                >{{ item.channelName }}</el-checkbox
              >
            </el-checkbox-group>
          </div>
        </div>
        <!-- 中间按钮 -->
        <div class="vertical center3 centrebtn">
          <el-button
            type="primary"
            icon="el-icon-caret-right"
            @click="singleSel()"
          />
          <el-button
            type="primary"
            style="margin: 20px 0 0 0"
            icon="el-icon-caret-left"
            @click="mutiSel()"
          />
        </div>
        <!-- 右边框框 -->
        <div class="transferbox">
          <div class="topbox">
            <span>已选择通道</span>
          </div>

          <div style="padding: 10px" class="contont">
            <el-checkbox
              :indeterminate="isIndeterminateThen"
              v-model="checkAllThen"
              @change="handleCheckAllChangeThen"
              >全选</el-checkbox
            >
            <div style="margin: 15px 0"></div>
            <el-checkbox-group
              v-model="checkedCitiesThen"
              @change="handleCheckedCitiesChangeThen"
            >
              <el-checkbox
                v-for="(item, index) in selectedData"
                :label="item.id"
                :key="index"
                >{{ item.channelName }}</el-checkbox
              >
            </el-checkbox-group>
          </div>
        </div>
      </div>
    </div>
    <div class="dialog-footer">
      <el-button class="g-background00BCD4" @click="dialogYwfzShowsBtn"
        >返 回</el-button
      >
      <el-button class="g-background00BCD4" type="primary" @click="onClickSave"
        >保存</el-button
      >
    </div>
  </el-dialog>
</template>

<script>
import _ from "underscore";
import $ from "jquery";
const defaultListQuery = {
  SkipCount: 0,
  MaxResultCount: 20,
};
export default {
  name: "PerformTaskDetailDialog",
  props: {
    visible: Boolean,
    id: String,
  },
  data() {
    return {
      defaultProps: {
        children: "children",
        label: "name",
        isLeaf: (data, node) => {
          return !data.hasChildren;
        },
      },
      checkAllThen: false,
      checkedCitiesThen: [],
      isIndeterminateThen: true,
      checkAllDeatilListThen: [],
      checkAll: false,
      checkedCities: [],
      isIndeterminate: true,
      checkAllDeatilList: [],
      parentId: null,
      listLoading: false,
      list: [],
      listQuery: Object.assign({}, defaultListQuery),
      filter: "",
      orgData: [],
      checkedArr: [],
      showCheck: false,
      showTree: true,
      selectedData: [],
      checkedIDArray: [],
      form: {
        groupName: "",
      },
      //form校验
      rules: {
        groupName: [
          {
            required: true,
            message: "请输入分组名称",
            trigger: "blur",
          },
        ],
      },
    };
  },
  computed: {

  },
  watch: {

  },
  created() {},
  mounted: function () {},
  methods: {
    /* 组织树数据获取*/
    getOrgs(node, resolve) {
      const params = {};
      if (typeof node !== "object") {
        if (node) {
          params["filter"] = node;
        }
      } else if (node.level !== 0) {
        this.parentId = node.data.id;
      }
      setTimeout(() => {
        //接口请求,根据实际开发设置
        this.$api.getUVxxxParentId(this.parentId).then((response) => {
          if (resolve) {
            resolve(response);
          } else {
            this.orgData = response;
          }
        });
      }, 100);
    },
    /* checkbox列表数据获取 */
    getList() {
      this.listLoading = true;
      this.list = [];
      this.listQuery.filter = this.filter;
      this.$api
        .querxxxannels(this.listQuery)
        .then((response) => {
          this.list = [...response.items];
          this.listLoading = false;
        })
        .catch(() => {
          this.listLoading = false;
        });
    },
    searchClick() {
       //如果input输入框有值就显示
      if (this.filter != "") {
        this.showCheck = true;
        this.showTree = false;
        this.getList();
      } else {
        this.showCheck = false;
        this.showTree = true;
        // this.getOrgs();
      }
    },
    //树变化事件
    handleCheckChange() {
      //获取树选中的所以数据
      let res = this.$refs.tree.getCheckedNodes();
      //获取树选中的id
      this.checkedIDArray = this.$refs.tree.getCheckedKeys();
      var nodes = _.filter(res, function (item) {
        return !item.hasChildren;
      });
      this.checkedArr = [];
      nodes.forEach((item) => {
        item.channelName = item.name;
        this.checkedArr.push(item);
      });
    },
    //关闭弹框
    dialogYwfzShowsBtn() {
      this.$emit("onclose");
    },
    // 左移
    singleSel() {
      let self = this;
      let queryAreaIdsList = [];
      if (self.showCheck == true) { //判断如果checkbox列表就移动checkbox选中的数据
        if (this.checkAllDeatilList.length == 0) {
          this.$message({
            message: "请选择通道!",
            type: "warning",
          });
          return;
        }
        this.selectedData = [...this.selectedData, ...this.checkAllDeatilList];
      } else if (self.showTree == true) { //判断如果el-tree就移动el-tree选中的数据
        if (this.checkedIDArray.length == 0) {
          this.$message({
            message: "请选择通道!",
            type: "warning",
          });
          return;
        }
        let params = {
          areaIds: this.checkedIDArray,
        };
        //这是我的项目需求,多调用了一次接口,如果是从树直接获取数据,可以忽略接口请求
        this.$api.getxxxByOrgIds(params).then((response) => {
          queryAreaIdsList = response;
          self.selectedData = [...queryAreaIdsList, ...this.checkedArr];
          self.selectedData = self.fn2(self.selectedData);
        });
      }
      //self.selectedData = [...this.checkedArr];
      //self.selectedData = self.fn2(self.selectedData);
      this.selectedData = self.fn2(self.selectedData);
    },
    //数组去重
    fn2(arr) {
      const res = new Map();
      return arr.filter((arr) => !res.has(arr.id) && res.set(arr.id, arr.id));
    },

    // 右移
    mutiSel() {
      //删除选中的
      for (let i = 0; i < this.selectedData.length; i++) {
        for (let j = 0; j < this.checkedCitiesThen.length; j++) {
          if (this.selectedData[i].id == this.checkedCitiesThen[j]) {
            this.selectedData.splice(i, 1);
          }
        }
      }
      this.isIndeterminateThen = true;
      this.checkedCitiesThen = [];
    },
    //左边未选中
    handleCheckAllChange(val) {
      let checkAll = [];
      if (val) {
        for (let i = 0; i < this.list.length; i++) {
          checkAll.push(this.list[i].id);
        }
      }
      this.checkAllDeatilList = val ? this.list : [];
      this.checkedCities = val ? checkAll : [];
      this.isIndeterminate = false;
    },
    //左边未选中
    handleCheckedCitiesChange(value) {
      this.checkAllDeatilList = [];
      let checkedCount = value.length;
      this.checkedCities = value;
      this.checkAll = checkedCount === this.list.length;
      this.isIndeterminate =
        checkedCount > 0 && checkedCount < this.list.length;
       //将获取的checkbox的值放到一个数组里
      for (let i = 0; i < this.list.length; i++) {
        for (let j = 0; j < this.checkedCities.length; j++) {
          if (this.list[i].id == this.checkedCities[j]) {
            this.checkAllDeatilList.push(this.list[i]);
          }
        }
      }
    },
    //右边已选中通道
    handleCheckAllChangeThen(val) {
      let checkAll = [];
      if (val) {
        for (let i = 0; i < this.selectedData.length; i++) {
          checkAll.push(this.selectedData[i].id);
        }
      }
      this.checkedCitiesThen = val ? checkAll : [];
      this.isIndeterminateThen = false;
    },
    //右边已选中通道
    handleCheckedCitiesChangeThen(value) {
      this.checkAllDeatilListThen = [];
      let checkedCount = value.length;
      this.checkAllThen = checkedCount === this.selectedData.length;
      this.isIndeterminateThen =
        checkedCount > 0 && checkedCount < this.selectedData.length;
    },
    onClickSave() {
      this.$refs.form.validate((valid) => {
        if (valid) {
          if (this.selectedData.length == 0) {
            this.$message({
              message: "通道不能为空!",
              type: "warning",
            });
            return;
          }
          let channelObjIds = [];
          this.selectedData.forEach((item, index) => {
            channelObjIds.push(item.objId);
          });
          let params = {
            groupName: this.form.groupName,
            channelObjIds: channelObjIds,
          };
		   //保存接口,根据实际开发需要定义
          this.$api.createxxxGroup(params).then((response) => {
            if (response.success) {
              this.$message({
                message: "业务分组保存成功。",
                type: "success",
              });
              this.$emit("onclose", true);
            } else {
              this.$message({
                message: response.info,
                type: "warning",
              });
              this.$emit("onclose", false);
            }
          });
        }
      });
    },
  },
};
</script>

<style lang="scss" scoped>
::v-deep .el-dialog {
  margin-top: 4vh !important;
}
::v-deep .el-dialog__body {
  padding: 20px;
}
.detail-row {
  margin-bottom: 25px;

  .detail {
    border-left: solid #ccc 1px;

    ::v-deep .el-form-item {
      margin: 0;
      background: #f7f7f7;

      label {
        padding: 5px 8px;
        border-top: solid #ccc 1px;
      }

      .el-form-item__content {
        padding-left: 8px;
        padding-top: 5px;
        background: white;
        border-left: solid #ccc 1px;
        border-top: solid #ccc 1px;
      }
    }
  }
  .detail.row-end ::v-deep .el-form-item__content {
    border-right: solid #ccc 1px;
  }
  .detail.row-bottom {
    border-bottom: solid #ccc 1px;
  }
}
.dialog-footer {
  padding-top: 20px;
  text-align: right;
  border-top: solid #eee 1px;
}
///@at-root
///

.transferbox {
  height: 600px;
  width: 45%; //右边盒子的宽占比
  border: 1px solid#ebedf2;
  .topbox {
    border-bottom: 1px solid #ebedf2;
    padding: 10px 10px;
    color: #575962;
    font-size: 16px;
    font-weight: 550;
  }
  .searchbox {
    margin: 10px;
  }
}
.centrebtn {
  width: 80px;
  height: 600px;
  margin: 0 10px 0 10px;
  color: #ffff;
}
/* 水平居中 */
.center1 {
  display: flex;
  justify-content: center;
}

/* 垂直水平居中 */
.center3 {
  display: flex;
  align-items: center;
  justify-content: center;
}
/* 水平布局 */
.level {
  display: flex;
  flex-direction: row;
}
// 垂直布局
.vertical {
  display: flex;
  flex-direction: column;
}

.contont {
  padding: 10px;
}
::v-deep .contont .el-checkbox {
  display: block;
}
</style>

这是弹框页面,可以当做组件调用,也可以根据实际开发需求自定义自己的页面。只要树的数据和checkbox的数据自己定义好,就可以直接复用。

  • 5
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值