赞
踩
效果图:
子组件:
HTML
-
- <template>
- <div class="treeTransfer">
- <!-- 左边 -->
- <div class="leftTree">
- <div class="list">
- <div class="left_lowline">
- <el-checkbox v-model="checkedLeft" :disabled="leftTreeData.length < 1" label="" size="large"
- style="margin-right: 12px" @change="leftAllCheck" />
- <p class="left_title">{{ props.title[0] }}</p>
- </div>
- <!-- 搜索 -->
- <div class="left_input">
- <el-input v-model.trem="leftSearchText" class="w-50 m-2" placeholder="请输入部门人员名称" clearable
- prefix-icon="el-icon-search" @clear="onSearchLeft" @keyup.enter="onSearchLeft"
- @change="onSearchLeft" />
- </div>
- <el-tree ref="leftTreeRef" :filter-node-method="filterNode" :data="leftTreeData" show-checkbox
- :node-key="props.nodeKey" :props="props.defaultProps" v-slot="{ node, data }" accordion
- @check="onCheckLeft" default-expand-all>
- <div>
- {{ data.corgName }}
- </div>
- <div>
- {{ data.label }}
- </div>
- </el-tree>
- </div>
- </div>
- <!-- 中间按钮 -->
- <div class="btnDiv">
- <div class="mg10">
- <el-button @click="toRight()" size="small" icon="el-icon-right" circle :disabled="leftOperation.length < 1"/>
- </div>
- <div class="mg10">
- <el-button @click="toLeft()" size="small" icon="el-icon-back" circle :disabled="rightOperation.length < 1"/>
- </div>
- </div>
- <!-- 右边 -->
- <div class="rightTree">
- <div class="list">
- <div class="left_lowline">
- <el-checkbox v-model="checkedRight" :disabled="rightTreeData.length < 1" label="" size="large"
- style="margin-right: 12px" @change="rightAllCheck" />
- <p class="left_title">{{ props.title[1] }}</p>
- </div>
- <!-- 搜索 -->
- <div class="left_input">
- <el-input v-model.trem="rightSearchText" class="w-50 m-2" placeholder="请输入部门人员名称" clearable
- prefix-icon="el-icon-search" @clear="onSearchRight" @keyup.enter="onSearchRight"
- @change="onSearchRight" />
- </div>
-
- <el-tree ref="rightTreeRef" :data="rightTreeData" show-checkbox :node-key="props.nodeKey"
- :props="props.defaultProps" v-slot="{ node, data }" accordion @check="onCheckRight" default-expand-all>
- <div>
- {{ data.corgName }}
- </div>
- <div>
- {{ data.label }}
- </div>
- </el-tree>
- </div>
- </div>
- </div>
- </template>
script:
- <script setup lang="ts">
- //@ts-nocheck 解决ts类型报红
- import { ref, onMounted, watch } from 'vue';
- import lodash from 'lodash'
- const props = defineProps(['nodeKey', 'fromData', 'toData', 'defaultProps', 'title']);
-
- const checkedLeft = ref(false)
- const checkedRight = ref(false)
- const leftSearchText = ref('');
- const rightSearchText = ref('');
- const leftOperation = ref<any[]>([])
- const rightOperation = ref<any[]>([])
-
- // 定义emit
- const emits = defineEmits(['change']);
- const leftTreeRef = ref();
- const rightTreeRef = ref();
-
- // 左侧数据
- const leftTreeData = ref([]);
- // 右侧数据
- const rightTreeData = ref([]);
-
- watch(
- props,
- newVal => {
- leftTreeData.value = lodash.cloneDeep(newVal.fromData)
- rightTreeData.value = lodash.cloneDeep(newVal.toData)
- },
- { immediate: true }
- )
-
- watch(leftSearchText, val => {
- rightTreeRef.value?.filter(val)
- })
- watch(rightSearchText, val => {
- leftTreeRef.value?.filter(val)
- })
- defineExpose({
- leftTreeData,
- rightTreeData
- })
-
- onMounted(() => {
- leftSearchText.value = ''
- rightSearchText.value = ''
- })
-
- const removeChecked = (rightList, allCheckedKeys) => {
- rightList.forEach((e, index) => {
- if (allCheckedKeys.indexOf(e.id) == -1) {
- rightList.splice(index, 1)
- }
- if (e.children) {
- removeChecked(e.children, allCheckedKeys)
- }
- })
- return rightList
- }
- const recursionTree = (parents, allCheckedKeys) => {
- parents.forEach(e => {
- const list = lodash.filter(e.children, child => allCheckedKeys.indexOf(child.id) >= 0)
- e.children = list
- if (e.children.length !== 0) {
- recursionTree(e.children, allCheckedKeys)
- }
- })
- return parents
- }
- const handleData = (rightNodes, leftTree, allCheckedKeys) => {
- rightNodes.forEach(item => {
- if (item.children) {
- let parent = leftTree.getNode(item.pid)
- let node = item
- if (!leftTree.getNode(item.id) && allCheckedKeys.indexOf(item.id) > 0) {
- const copyNode = lodash.cloneDeep(node)
- copyNode.children = []
- leftTree.append(copyNode, parent)
- }
- handleData(item.children, leftTree, allCheckedKeys)
- } else {
- let parent = leftTree.getNode(item.pid)
- let node = item
- if (!leftTree.getNode(item.id) && allCheckedKeys.indexOf(item.id) > 0) {
- leftTree.append(node, parent)
- }
- }
- })
- }
- // // 去右边
- const toRight = async () => {
- const leftTree = leftTreeRef.value;
- checkedLeft.value = false
- if (!leftTree) {
- return
- }
- const leftNodes = leftTree.getCheckedNodes(false, true)
- const parents = leftNodes.filter(
- el => el.children && el.children.length > 0 && el.pid == '0'
- )
- const checkedKeys = leftTree.getCheckedKeys(false)
- const halfCheckedKeys = leftTree.getHalfCheckedKeys()
- const allCheckedKeys = halfCheckedKeys.concat(checkedKeys)
- const rightTree = rightTreeRef.value
- if (!rightTree) {
- let rightList = parents.map(parent => {
- const obj = lodash.omit(parent, ['children'])
- obj.children = lodash.filter(parent.children, child => allCheckedKeys.indexOf(child.id) >= 0)
- return obj
- })
-
- let copyRightList = lodash.cloneDeep(rightList)
- removeChecked(copyRightList, allCheckedKeys)
- rightTreeData.value.push(...copyRightList)
- } else {
- let isExist = false
- rightTree.data.forEach(e => {
- if (parents[0].id === (e as any).id) isExist = true
- })
- if (!isExist) {
- const overall = lodash.cloneDeep(parents)
- let rightList = await recursionTree(overall, allCheckedKeys)
- let copyRightList = lodash.cloneDeep(rightList)
- removeChecked(copyRightList, allCheckedKeys)
- rightTreeData.value.push(...copyRightList)
- } else {
- handleData(leftNodes, rightTree, allCheckedKeys)
- }
- }
- // 移过去之后要删除原本的值
- leftNodes.forEach(node => {
- leftTree.setChecked(node, false, false)
- if (checkedKeys.indexOf(node.id) >= 0) {
- leftTree.remove(node)
- }
- })
-
- leftOperation.value = formatTree(leftTree.getCheckedNodes(false) || [], 'pid', 'id');
- // emits('change', leftTreeData.value, rightTreeData.value)
- emits('change', checkedKeys)
- setTimeout(() => {
- rightTree?.setCheckedNodes(leftNodes);
- rightOperation.value = formatTree(rightTree.getCheckedNodes(false) || [], 'pid', 'id')
- }, 500)
- };
- // // 去左边
- const toLeft = async () => {
- checkedRight.value = false
- const rightTree = rightTreeRef.value
- if (!rightTree) {
- return
- }
- const rightNodes = rightTree.getCheckedNodes(false, true)
- const checkedKeys = rightTree.getCheckedKeys(false)
- const halfCheckedKeys = rightTree.getHalfCheckedKeys()
- const allCheckedKeys = halfCheckedKeys.concat(checkedKeys)
-
- const parents = lodash.filter(
- rightNodes,
- item => item.children && item.children.length > 0 && item.pid == '0'
- )
- const leftTree = leftTreeData.value.length ? leftTreeRef.value : null
- if (!leftTree) {
- let leftList = parents.map(parent => {
- const obj = lodash.omit(parent, ['children'])
- obj.children = lodash.filter(parent.children, child => allCheckedKeys.indexOf(child.id) >= 0)
- return obj
- })
- let copyLeftList = lodash.cloneDeep(leftList)
- removeChecked(copyLeftList, allCheckedKeys)
- leftTreeData.value.push(...copyLeftList)
- } else {
- let isExist = false
- leftTree.data.forEach(e => {
- if (parents[0].id === (e as any).id) isExist = true
- })
- if (!isExist) {
- const overall = lodash.cloneDeep(parents)
- let leftList = await recursionTree(overall, allCheckedKeys)
- let copyLeftList = lodash.cloneDeep(leftList)
- removeChecked(copyLeftList, allCheckedKeys)
- rightTreeData.value.push(...copyLeftList)
- } else {
- handleData(rightNodes, leftTree, allCheckedKeys)
- }
- }
- console.log(leftTreeData.value, 'slf-leftTreeData');
-
- rightNodes.forEach(node => {
- rightTree.setChecked(node, false, false)
- if (checkedKeys.indexOf(node.id) >= 0) {
- rightTree.remove(node)
- }
- })
-
- rightOperation.value = formatTree(rightTree.getCheckedNodes(false) || [], 'pid', 'id')
- // emits('change', leftTreeData.value, rightTreeData.value)
- emits('change', checkedKeys)
- };
-
- //左侧选中(移除原本值用)
- const onCheckLeft = () => {
- leftOperation.value = formatTree(
- leftTreeRef.value?.getCheckedNodes(false) || [],
- 'pid',
- 'id'
- )
- }
- // 右侧选中
- const onCheckRight = () => {
- rightOperation.value = formatTree(
- rightTreeRef.value!.getCheckedNodes(false) || [],
- 'pid',
- 'id'
- )
- }
-
- const formatTree = (tree: any[], parentKey: string = 'pid', idKey: string = 'id') => {
- // 格式化选择的树:清除全选下面的子节点
- let swap,
- parentIds: string[] = []
- // 先找出有children的id集合,再把所有的数据做对比,只要pid和其中一个对上,就把该数据删除;
- tree.forEach((item, index) => {
- if (item.children) {
- parentIds.push(item[idKey])
- }
- })
- swap = tree.filter((item, index) => {
- if (parentIds.indexOf(item[parentKey]) == -1) {
- return item
- }
- })
- return swap
- }
-
- const leftAllCheck = () => {
- const leftTree = leftTreeRef.value;
- if (checkedLeft.value) {
- leftTree?.setCheckedNodes(leftTreeData.value)
- checkedLeft.value = true;
- } else {
- leftTree?.setCheckedNodes([])
- checkedLeft.value = false
- }
- }
- const onSearchLeft = () => {
- leftTreeRef.value?.filter(leftSearchText.value)
- }
-
- const rightAllCheck = () => {
- const rightTree = rightTreeRef.value
- if (checkedRight.value) {
- rightTree?.setCheckedNodes(rightTreeData.value)
- checkedRight.value = true
- } else {
- rightTree?.setCheckedNodes([])
- checkedRight.value = false
- }
- }
- const onSearchRight = () => {
- rightTreeRef.value!.filter(rightSearchText.value)
- }
- const filterNode = (value: string, data: any) => {
- if (!value) return true
- return data.label.includes(value)
- }
父组件引用:
- <TreeTransfer ref="treeTransferRef" node-key="id" :fromData="fromData" :toData="toData"
- :defaultProps="transferProps" @change="treeChange" :title="['选择人员', '已选择人员']">
- </TreeTransfer>
- let treeTransferRef = ref(); // 树形穿梭框
- let fromData = ref([
- {
- id: "1",
- pid: 0, //自定义pid的参数名,默认为"pid" 必填:false
- label: "一级 1",
- children: [
- {
- id: "1-1",
- pid: "1",
- label: "二级 1-1",
- children: []
- },
- {
- id: "1-2",
- pid: "1",
- label: "二级 1-2",
- children: [
- {
- id: "1-2-1",
- pid: "1-2",
- children: [],
- label: "二级 1-2-1"
- },
- {
- id: "1-2-2",
- pid: "1-2",
- children: [],
- label: "二级 1-2-2"
- },
- {
- id: "1-2-3",
- pid: "1-2",
- children: [],
- label: "二级 1-2-3"
- }
- ]
- }
- ]
- }
- ]); // 树形数据
- let toData = ref([]); // 选中的ids数据
- const transferProps = ref({
- label: 'label',
- children: 'children',
- disabled: 'disabled',
- });
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。