el-tree和vue结合的穿梭框el-tree-transfer的使用

33 篇文章 0 订阅

首先el-tree-transfer的地址 github文档:https://github.com/hql7/tree-transfer

效果图
在这里插入图片描述
安装及使用

npm install el-tree-transfer --save
 
//或者
 
npm i el-tree-transfer -S
然后在局部引入并注册组件就可以使用了

import treeTransfer from “el-tree-transfer”; // 引入


      <!-- 使用树形穿梭框组件 -->
      <tree-transfer
        :from_data="deptOptions"
        :to_data="toData"
        :defaultProps="{ label: 'label', children: 'children' }"
        @add-btn="add"
        :pid="parentId"
        @remove-btn="remove"
        height="540px"
        filter
        :title="treeTitle"
        :openAll="openAll"
        placeholder="请输入菜单名称"
        class="tarnsfer_tree"
        :key="treeKey"
      >
      </tree-transfer>
   methods:{
          // 切换模式 现有树形穿梭框模式transfer 和通讯录模式addressList
          changeMode() {
            if (this.mode == "transfer") {
              this.mode = "addressList";
            } else {
              this.mode = "transfer";
            }
          },
          // 监听穿梭框组件添加
          add(fromData,toData,obj){
            // 树形穿梭框模式transfer时,返回参数为左侧树移动后数据、右侧树移动后数据、移动的{keys,nodes,halfKeys,halfNodes}对象
            // 通讯录模式addressList时,返回参数为右侧收件人列表、右侧抄送人列表、右侧密送人列表
            console.log("fromData:", fromData);
            console.log("toData:", toData);
            console.log("obj:", obj);
          },
          // 监听穿梭框组件移除
          remove(fromData,toData,obj){
            // 树形穿梭框模式transfer时,返回参数为左侧树移动后数据、右侧树移动后数据、移动的{keys,nodes,halfKeys,halfNodes}对象
            // 通讯录模式addressList时,返回参数为右侧收件人列表、右侧抄送人列表、右侧密送人列表
            console.log("fromData:", fromData);
            console.log("toData:", toData);
            console.log("obj:", obj);
          }
        },
        components:{ treeTransfer } // 注册
      }

注意!!!
一定要定义pid,否则穿梭过去的结构不是树状的!!!而pid是自定义的,我这里是自己定义的parentId
以下是必须做的步骤

  props: {
    // el-tree node-key 必须唯一
    node_key: {
      type: String,
      default: "id",
    },
    // 自定义 pid参数名,因为后端给的参数名为id
    pid: {
      type: String,
      default: "parentId",
    },
  },

data里面定义

 parentId: "parentId",

处理数据

  /** 查询部门树结构 */
    getDeptTreeselect() {
      deptTreeselect().then((response) => {
        this.deptOptions = response.data;
        this.deptOptions.forEach((item) => {
          //el-tree-transfer组件的第一个pid必须为0,二级parentId必须是父级的id
          item.parentId = 0;
          if (item.children) {
            item.children.forEach((val) => {
              val.parentId = item.id;
            });
          }
        });
      });
    },

最后附上全部完整代码

<template>
  <el-dialog
    v-bind="dialogConfig"
    :visible.sync="visibleTmpl"
    :before-close="beforeClose"
    append-to-body
    width="70%"
    custom-class="add_menu_dialog"
  >
    <el-form
      :model="form"
      :label-position="'right'"
      label-width="100px"
      size="small"
      ref="addForm"
    >
      <!-- title部分 -->
      <div class="title_contant">
        <!-- tab栏 -->
        <div class="tabBar">
          <div
            class="tab-item"
            :class="tabType === 1 ? 'active' : ''"
            :style="{
              '--theme': theme,
            }"
            @click="tabType = 1"
          >
            <i class="el-icon-date"> web</i>
          </div>
          <div
            class="tab-item"
            :class="tabType === 2 ? 'active' : ''"
            :style="{
              '--theme': theme,
            }"
            @click="tabType = 2"
          >
            <i class="el-icon-menu"> App1</i>
          </div>
          <div
            class="tab-item"
            :class="tabType === 3 ? 'active' : ''"
            :style="{
              '--theme': theme,
            }"
            @click="tabType = 3"
          >
            <i class="el-icon-menu"> App2</i>
          </div>
        </div>
        <!-- y右侧title -->
        <div class="right_title">已选菜单</div>
      </div>

      <!-- 使用树形穿梭框组件 -->
      <tree-transfer
        :from_data="deptOptions"
        :to_data="toData"
        :defaultProps="{ label: 'label', children: 'children' }"
        @add-btn="add"
        :pid="parentId"
        @remove-btn="remove"
        height="540px"
        filter
        :title="treeTitle"
        :openAll="openAll"
        placeholder="请输入菜单名称"
        class="tarnsfer_tree"
        :key="treeKey"
      >
      </tree-transfer>
      <!-- 功能选择左侧 -->
      <div class="open_check">
        <el-checkbox
          v-model="openAll"
          @change="handleCheckedTreeExpand($event, 'dept')"
          >展开/折叠</el-checkbox
        >
        <el-checkbox
          v-model="form.deptCheckStrictly"
          @change="handleCheckedTreeConnect($event, 'dept')"
          >父子联动</el-checkbox
        >
      </div>
    </el-form>
    <span slot="footer" class="dialog-footer">
      <el-button @click="handleSave" type="primary">保 存</el-button>
      <el-button @click="handleBack">取 消</el-button>
    </span>
  </el-dialog>
</template>

<script>
const defaultDialogProps = {
  title: "菜单选择",
  width: "500px",
};
import { treeselect as deptTreeselect } from "@/api/system/dept";
import { mapState } from "vuex";
import variables from "@/assets/styles/variables.scss";
import treeTransfer from "el-tree-transfer"; // 引入
export default {
  components: {
    treeTransfer,
  },
  data() {
    return {
      // 弹窗显示/隐藏
      visibleTmpl: this.visible,
      form: this.initFormData(),
      isView: true,

      options: {
        specialTypes: [],
        categorys: [], // 专业类别
      },
      dialogTitle: "",
      defaultProps: {
        children: "children",
        label: "label",
      },
      toData: [],
      treeKey: 1,
      // 部门列表
      deptOptions: [],
      openAll: true,
      deptExpand: true,
      deptNodeAll: false,
      deptExpand_right: true, // 右侧选项
      deptNodeAll_right: false, // 右侧选项
      deptOptions_rignt: [], // 已选菜单
      tabType: 1, //tab栏
      selected: [],
      treeTitle: ["全选/不全选", "全选/不全选"],
      parentId: "parentId",
    };
  },
  props: {
    visible: {
      type: Boolean,
      default: false,
    },
    dialogProps: {
      type: Object,
      default: () => {},
    },
    rulesProps: {
      type: Object,
      default: () => {},
    },
    // el-tree node-key 必须唯一
    node_key: {
      type: String,
      default: "id",
    },
    // 自定义 pid参数名,因为后端给的参数名为id
    pid: {
      type: String,
      default: "parentId",
    },
  },
  created() {
    this.getDeptTreeselect();
  },
  methods: {
    // 查询
    searchInfo() {},

    // 初始化表单
    initFormData() {
      return {
        // id: "",
        matterName: "",
        deptCheckStrictly: true,
      };
    },
    // 提交
    handleSave() {
      this.loading = true;

      const msg = this.rulesProps.id ? "编辑" : "新增";
      this.$refs.addForm.validate().then(() => {
        if (this.rulesProps.id) {
          this.$services["spsi/rules"]
            .getUpdateSave({ ...this.form }, { msg: true })
            .then(() => {
              this.$notify.success(msg + "监管规则成功!");
              this.$emit("submit");
              this.$emit("update:visible", false);
              this.loading = false;
            })
            .catch((err) => {
              console.error(err);
            });
        } else {
          this.$services["spsi/rules"]
            .getSave({ ...this.form }, { msg: true })
            .then(() => {
              this.$notify.success(msg + "监管规则成功!");
              this.$emit("submit");
              this.$emit("update:visible", false);
            })
            .catch((err) => {
              console.error(err);
            });
        }
      });
    },
    // 树权限(展开/折叠)
    handleCheckedTreeExpand(value, type) {
      if (!value) {
        this.openAll = false;
      } else {
        this.openAll = true;
      }
      this.treeKey++;
    },

    // 树权限(父子联动)
    handleCheckedTreeConnect(value, type) {
      if (type == "dept_right") {
        this.form.menuCheckStrictly = value ? true : false;
      } else if (type == "dept") {
        this.form.deptCheckStrictly = value ? true : false;
      }
    },
    /** 查询部门树结构 */
    getDeptTreeselect() {
      deptTreeselect().then((response) => {
        this.deptOptions = response.data;
        this.deptOptions.forEach((item) => {
          //el-tree-transfer组件的第一个pid必须为0,二级parentId必须是父级的id
          item.parentId = 0;
          if (item.children) {
            item.children.forEach((val) => {
              val.parentId = item.id;
            });
          }
        });
      });
    },
    // 关闭弹窗
    beforeClose(done) {
      this.$emit("update:visible", false);
      done();
    },
    handleBack() {
      this.$emit("update:visible", false);
    },
    // 搜索节点
    filterNode(value, data) {
      if (!value) return true;
      return data.label.indexOf(value) !== -1;
    },

    // 切换模式 现有树形穿梭框模式transfer 和通讯录模式addressList
    changeMode() {
      if (this.mode == "transfer") {
        this.mode = "addressList";
      } else {
        this.mode = "transfer";
      }
    },
    // 监听穿梭框组件添加
    add(fromData, toData, obj) {
      // 树形穿梭框模式transfer时,返回参数为左侧树移动后数据、右侧树移动后数据、移动的{keys,nodes,halfKeys,halfNodes}对象
      // 通讯录模式addressList时,返回参数为右侧收件人列表、右侧抄送人列表、右侧密送人列表
      console.log("fromData:", fromData);
      console.log("toData:", toData);
      console.log("obj:", obj);
      //追加选中数据ID
      this.selected.concat(obj.keys);
    },
    // 监听穿梭框组件移除
    remove(fromData, toData, obj) {
      //移除删除项数据
      this.selected = this.selected.filter(
        (item) => obj.keys.indexOf(item) == -1
      );
    },
  },
  computed: {
    dialogConfig() {
      return Object.assign({}, defaultDialogProps, this.dialogProps);
    },
    ...mapState(["settings"]),
    theme() {
      return this.$store.state.settings.theme;
    },
    variables() {
      return variables;
    },
  },
  watch: {
    visible(n) {
      this.visibleTmpl = n;
    },
  },
};
</script>

<style lang="scss">
.add_menu_dialog {
  .el-select {
    width: 100%;
  }
  .el-dialog__header {
    border-bottom: 1px solid #e5e6e7;
  }
  .title_contant {
    display: flex;
    flex-flow: row nowrap;
    justify-content: space-between;

    .tabBar {
      height: 50px;
      border-radius: 2px;
      display: flex;
      align-items: center;
      border-bottom: 1px solid #f6f6f6;
      padding-left: 20px;
      .tab-item {
        padding: 0 26px;
        font-size: 16px;
        font-weight: 400;
        height: 50px;
        line-height: 50px;
        box-sizing: border-box;
        cursor: pointer;
        &.active {
          // color: #1890ff;
          border-bottom: 2px solid #{"var(--theme)"} !important;
          color: #{"var(--theme)"} !important;
        }
      }
    }
    .right_title,
    .tabBar {
      border: 1px solid #e5e6e7;
      border-bottom: none;
      width: 46%;
    }
    .right_title {
      font-size: 16px;
      font-family: PingFangSC-Regular, PingFang SC;
      color: #262626;
      line-height: 50px;
      padding-left: 12px;
    }
  }

  .wl-transfer {
    .transfer-title {
      font-size: 14px;
      background: none;
    }
    .transfer-left,
    .transfer-right {
      width: 46%;
      border-radius: 0;
    }
    .transfer-right {
      border-top: 0;
    }
  }

  .open_check {
    position: absolute;
    top: 147px;
    left: 153px;
  }
}
</style>

  • 2
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 6
    评论
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值