vue3 tree樹形穿梭框(封裝組件)

效果圖
代碼
  • 子組件
// 封裝組件
<template>
  <div class="treeTransfer">
    <!-- 左邊 -->
    <div class="leftTree">
      <div class="list">
        <div class="left_lowline">
          <p class="left_title">用戶列表</p>
        </div>
        <!-- 搜索 -->
        <div class="left_input">
          <el-input
            v-model="leftSearch"
            class="w-50 m-2"
            placeholder="搜索"
            clearable
            :prefix-icon="Search"
          />
        </div>
        <el-tree
          ref="treeRef"
          :data="props.fromData"
          show-checkbox
          :node-key="props.nodeKey"
          highlight-current
          :props="props.defaultProps"
          v-slot="{ node, data }"
        >
          <div>
            {{ data.corgName }} // 父節(jié)點(diǎn)
          </div>
          <div>
            {{ data.userName }}  // 子節(jié)點(diǎn)
          </div>
        </el-tree>
      </div>
    </div>
    <!-- 中間按鈕 -->
    <div class="btnDiv">
      <div class="mg10" @click="toRight()">
        <el-button :icon="Right" circle />
      </div>
      <div class="mg10" @click="toLeft()">
        <el-button :icon="Back" circle />
      </div>
    </div>
    <!-- 右邊 -->
    <div class="rightTree">
      <div class="list">
        <div class="left_lowline">
          <p class="left_title">已選列表</p>
        </div>
        <!-- 搜索 -->
        <div class="left_input">
          <el-input
            v-model="rightSearch"
            class="w-50 m-2"
            placeholder="搜索"
            clearable
            :prefix-icon="Search"
          />
        </div>

        <div
          class="right_item"
          :class="['item', { active: item.active }]"
          v-for="(item, index) in toData"
          :key="index"
          @click="checkNode(item)"
        >
          {{ item[props.defaultProps.label] }}
          <!-- 下拉框 -->
          <div>
            <el-select
              v-model="item.priority"
              class="m-2"
              placeholder="請(qǐng)選擇"
              style="width: 100px"
            >
              <el-option
                v-for="item2 in options"
                :key="item2.value"
                :label="item2.label"
                :value="item2.value"
              />
            </el-select>
          </div>
        </div>
      </div>
    </div>
  </div>
</template>

<script setup lang="ts">
//@ts-nocheck    解決ts類型報(bào)紅
import { ref, onMounted } from 'vue';
import { Search } from '@element-plus/icons-vue';
import { useMainStore } from '@/store/index';
import { Right, Back } from '@element-plus/icons-vue';

const mainStore = useMainStore();
const props = defineProps(['nodeKey', 'fromData', 'toData', 'defaultProps']);

const leftSearch = ref('');
const rightSearch = ref('');
const options = [
  {
    value: '3',
    label: '高',
  },
  {
    value: '2',
    label: '中',
  },
  {
    value: '1',
    label: '低',
  },
];

// 定義emit
const emit = defineEmits(['checkVal']);
const treeRef = ref();

// 右側(cè)數(shù)據(jù)
const toData = ref([]);

onMounted(() => {
  if (props.toData.length > 0) {
    toData.value = treeRef.value.getCheckedNodes(false, false);
    treeRef.value.setCheckedKeys([], false);
  }
});

// 去右邊
const toRight = () => {
  const checkNodes = treeRef.value.getCheckedNodes(false, false);

  const newArr = toData.value.concat(checkNodes);
  let obj = {};
  let peon = newArr.reduce((cur, next) => {
    obj[next[props.nodeKey]]
      ? ''
      : (obj[next[props.nodeKey]] = true && cur.push(next));
    return cur;
  }, []); // 設(shè)置cur默認(rèn)類型為數(shù)組,并且初始值為空的數(shù)組

  toData.value = peon;
  treeRef.value.setCheckedKeys([], false);
  checkVal();

  props.fromData.forEach((item: any) => {
    item.children.forEach((left: any) => {
      toData.value.forEach((right) => {
        if (left.userId == right.userId) {  // 已選的不可重復(fù)勾選
          left.disabled = true;
        }
      });
    });
  });
};
// 去左邊
const toLeft = () => {
  for (var i = 0; i < toData.value.length; i++) {
    if (toData.value[i].active) {
      toData.value[i].active = false;
      toData.value.splice(i, 1);
      i -= 1;
    }
  }
  checkVal();

  props.fromData.forEach((item: any) => {
    item.children.forEach((left: any) => {
      left.disabled = false;
      toData.value.forEach((right) => {
        if (left.userId == right.userId) {
          left.disabled = true;
        }
      });
    });
  });
};
// 右側(cè)item點(diǎn)擊
const checkNode = (item: any) => {
  item.active = !item.active;
};
// 返回父組件
const checkVal = () => {
  emit('checkVal', toData.value);
};
</script>
  • 父組件
<div>
   <p class="select_meb">選擇固定成員:</p>
            <div class="shuttle_frame">
              <tree-transfer
                ref="treeTransferRef"
                node-key="userId"
                :fromData="fromData"
                :toData="toData"
                :defaultProps="transferProps"
                @checkVal="checkVal"
              >
              </tree-transfer>
            </div>
            <!-- 底部按鈕 -->
            <div class="modfiy_but">
              <el-button @click="saveModfiyManageMeb" type="primary"
                >確認(rèn)</el-button
              >
              <el-button @click="cancelModfiyManage">取消</el-button>
            </div>
</div>
import { ref, onMounted } from 'vue';

let treeTransferRef = ref(); // 樹形穿梭框
let fromData = ref([]); // 樹形數(shù)據(jù)
let toData = ref([]); // 選中的ids數(shù)據(jù)
const transferProps = ref({
  label: 'userName',
  children: 'children',
  disabled: 'disabled',
});

// 子組件樹形穿梭框返回
const checkVal = (val: any) => {
  toData.value = val;
};

// 獲取左側(cè)用戶列表
async function getUserList() {
  let params = {
    userId: '',
  };
  const res = await getCompanyListById(params);
  if (res.code == 200) {
    if (res.data.result == 1) {
      fromData.value = res.data.returnMsg;
      // 根據(jù)返回?cái)?shù)據(jù)處理.....
    } else {
      ElMessage.error(res.message);
    }
  }
}

********************************************************************
// 后端要求傳參格式
[{"userId":"28586","priority":"2"},{"userId":"28588","priority":"3"}]

// 確認(rèn)
function saveModfiyManageMeb() {
  let rightList: any[] = [];
  toData.value.forEach((element) => {
    let param = { userId: '', priority: '' }; 
    param.userId = element.userId;
    param.priority = element.priority;
    rightList.push(param);
  });
  var existUserStr = JSON.stringify(rightList);
  let params = {
    groupId: '',
    userDataStr: existUserStr,
  };
  saveAndModifyUserOfGroup(params).then((res) => {
    if (res.code == 200) {
      ElMessage.success('修改成功');
    } else {
      ElMessage.error(res.message);
    }
  });
}

參考了一位大佬的,當(dāng)時(shí)忘記復(fù)制鏈接了。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容