1. 程式人生 > 其它 >vue3 元件之穿梭框2.0

vue3 元件之穿梭框2.0

如圖所示,沒有傳統穿梭框中間的箭頭,操作更加方便,左側選擇後進入到右側,並且可以對右側所選項進行刪除,從而左側勾選也會對應取消。並且帶搜尋框。

程式碼如下:

(涉及到深拷貝的一些知識)

 

<template>
  <div style="display: inline-block">
    <!-- 下拉選擇 -->
    <el-select
      class="search-input"
      v-model="peopleVal"
      placeholder="請選擇"
      ref="selectPeople"
@focus="openDialog" > </el-select> <!--彈窗 --> <el-dialog v-model="dialog" :title="title" @open="openFn" width="630px"> <el-form label-width="70px"> <div class="transfer-view"> <div class="item-label">選擇人員</div> <
div class="checked-box"> <div class="search-box"> <el-input v-model.trim="searchName" placeholder="請輸入關鍵詞" :prefix-icon="Search" @input="searchFn" clearable ></el-input
> </div> <el-checkbox v-show="!searchName" :indeterminate="isIndeterminate" v-model="checkAll" @change="handleCheckAllChange" >全選</el-checkbox > <el-checkbox-group @change="handleChecked" v-model="checkList"> <el-checkbox class="checkbox-item" v-for="v in personList" :label="v.id" :key="v.id" > {{ v.realName }} </el-checkbox> </el-checkbox-group> </div> <div class="select-checked-box"> <div class="search-box"> <span class="selected">已選:{{ checkList.length }}人</span> </div> <div class="select-perosn" v-for="v in checkPerson" :key="v.id"> <span> {{ v.realName }} </span> <i class="iconfont icon-a-zujian18719 icon-error" @click="handleRemove(v)" ></i> </div> </div> </div> </el-form> <template #footer> <span class="dialog-footer"> <el-button @click="dialog = false">取消</el-button> <el-button type="primary" @click="submitFn">提交</el-button> </span> </template> </el-dialog> </div> </template>

 

 

<script>
import { reactive, toRefs, watch } from "vue";
import { Close, Search } from "@element-plus/icons";
import { sysUserApi } from "@/http/projectManagement/underMaintenance.js"; //獲取人員列表的介面,自行替換
export default {
  emits: ["handleCancel", "handleSure"],
  components: { Close },
  props: {
    dialogFormVisible: {
      type: Boolean,
      default: false,
    },
    title: {
      type: String,
      require,
    },
  },
  setup(props, { emit }) {
    const data = reactive({
      dialog: false, // 彈窗
      checkList: [], // 左側已選資料Id
      checkPerson: [], // 右側已選的資料
      searchName: "", // 搜尋資料
      checkAll: false, // 全選
      isIndeterminate: false,
      personList: [],
      allPersonList: [], // 所有人員
    });
    watch(
      () => data.personList,
      (newVal, oldVal) => {
        if (data.checkAll) {
          if (newVal.length > oldVal.length) {
            data.checkAll = false;
            data.isIndeterminate = true;
          }
        }
        console.log(newVal, oldVal);
      }
    );
    //開啟彈窗
    const openFn = () => {
      sysUserApi({}).then((res) => {
        if (res.data.code === 200) {
          data.personList = res.data.data;
          data.allPersonList = res.data.data;
        }
      });
    };
    // 選擇複選框
    const handleChecked = (val) => {
      handleCheck(data.checkList);
      let checkedCount = data.checkList.length;
      data.checkAll = checkedCount === data.personList.length;
      data.isIndeterminate =
        checkedCount > 0 && checkedCount < data.personList.length;
    };
    // 深拷貝
    const handleCheck = (val) => {
      let arr = [];
      val.forEach((v) => {
        let a = data.allPersonList.filter((item) => item.id === v);
        if (a.length) {
          arr.push(...a);
        }
      });
      data.checkPerson = arr;
    };
    // 全選
    const handleCheckAllChange = (val) => {
      let arr = data.personList.map((v) => v.id);
      data.checkList = val ? arr : [];
      val ? handleCheck(arr) : handleCheck([]);
      data.isIndeterminate = false;
    };
    // 刪除
    const handleRemove = (val) => {
      data.checkPerson.forEach((item, index) => {
        if (item.id === val.id) {
          data.checkPerson.splice(index, 1);
          data.checkList.splice(index, 1);
        }
      });
      if (!data.checkList.length) {
        data.checkAll = false;
        data.isIndeterminate = false;
      }
    };
    // 搜尋
    const searchFn = () => {
      let list = [];
      data.allPersonList.map((item) => {
        if (item.realName.indexOf(data.searchName) > -1) {
          list.push(item);
        }
      });
      data.personList = list;
    };
    // 下拉框資訊
    const selectInfo = reactive({
      selectPeople: null, // 選人dom
      peopleVal: "",
      openDialog() {
        selectInfo.selectPeople.blur();
        data.dialog = true;
      },
    });
    // 彈窗確定
    const submitFn = () => {
      data.dialog = false;
      selectInfo.peopleVal = data.checkList.map((item) => item.realName);
      // emit('handleSure', data.form);
    };
    return {
      ...toRefs(data),
      ...toRefs(selectInfo), // 下拉框資訊
      openFn, //開啟彈窗
      submitFn, // 確定
      handleCheck,
      handleCheckAllChange, // 全選事件
      handleChecked, // 選擇複選框
      handleRemove, // 刪除
      searchFn, // 搜尋
      Search, // 搜尋圖示
    };
  },
};
</script>

 

<style lang="scss" scoped>
/deep/ .el-radio__label {
  color: #888ea2;
}
.transfer-view {
  width: 100%;
  height: 25rem;
  display: flex;
  margin-top: 1rem;
  .checked-box,
  .select-checked-box {
    width: 15rem;
    height: 25rem;
    border: 1px solid #eeeeee;
    border-radius: 8px;
    padding: 1.31rem;
    box-sizing: border-box;
    overflow-y: auto;
    overflow-x: hidden;
  }
  .search-box {
    font-family: Source Han Sans CN;
    font-weight: 400;
    display: flex;
    height: 2.4rem;
    justify-content: space-between;
    align-items: center;
    color: #fff;
    margin-bottom: 0.8rem;
    .selected {
      color: #888ea2;
    }
  }
  .checked-box {
    margin-right: 1.25rem;
  }
  .item-label {
    width: 60px;
    margin-right: 12px;
    height: 100%;
    text-align: right;
    font-weight: 400;
  }
  .el-input {
    width: 12.5rem;
    height: 2.38rem;
    /deep/ .el-input__inner {
      width: 100%;
      height: 100%;
    }
  }
  .checkbox-item {
    display: block;
    margin-top: -5px;
    line-height: 40px;
    margin-left: 15px;
  }
  .select-perosn {
    color: #888ea2;
    display: flex;
    align-items: center;
    justify-content: space-between;
    padding-right: 1rem;
    box-sizing: border-box;
    > span {
      display: inline-block;
      max-width: 14rem;
      overflow: hidden;
      text-overflow: ellipsis;
      white-space: nowrap;
    }
    .icon-error {
      font-size: 14px;
      line-height: 14px;
      cursor: pointer;
    }
  }
}

// /*滾動條裡面軌道*/
::-webkit-scrollbar-track {
  border-radius: 3px;
  background: #3d609100;
}
</style>