通过查找资料将elementui组件增加了部分功能

1、分页(注意分页使用的是先查询出全部数据,再使用js进行算法分页,因为如果一次渲染数据过多,穿梭框加载会有延迟,不太友好)

2、左侧勾选并穿梭后,整个分页相关内容自动更新

3、增加自定义搜索框和筛选策略

4、右侧栏增加了最大数量限制

子组件:

<template>
  <!-- 创建模块 -->
  <Modal v-model="isShow" @on-cancel="cancle" title="创建自定义模块" width="720">
    <Row>
      <Col span="4" style="height: 32px; line-height: 32px;">
        <Code>*</Code> <span class="model_name_tip">模块名称</span>
      </Col>
      <Col span="20">
        <Input v-model="model_name" maxlength="8" show-word-limit placeholder="输入模块名称(最多输入8个字" />
      </Col>
    </Row>
    <Row style="padding-top: 20px;">
      <Col span="12">
        <el-input placeholder="请输入搜索关键字" v-model="keyword" class="input-with-select" size="small">
          <el-button slot="append" icon="el-icon-search" @click="filterChange"></el-button>
        </el-input>
      </Col>
    </Row>
    <Row>
      <el-transfer
        target-order="unshift"
        v-model="formDatas.river"
        @change="transferChange"
        @left-check-change="leftCheckChange"
        :titles="['可选列表', '已选中']"
        :data="currentPageDatas"
        :format="{noChecked: '${total}',hasChecked: '${checked}/${total}'}"
        class="el-transfer_cus" >
        <el-pagination
          small
          slot="left-footer"
          align="right"
          @current-change="handleCurrentChange"
          :current-page="page.pageNo"
          :page-size="page.pageSize"
          :total="page.total"
          :pager-count="5"
          layout="prev, pager, next"
        ></el-pagination>
      </el-transfer>
    </Row>
  </Modal>
  <div slot="footer">
      <!-- 有表单提交,需要验证输入,所以使用自定底部按钮 -->
      <Button type="text" @click="cancle">取消</Button>
      <Button type="primary" @click="submitData">确定</Button>
    </div>
</template>

<script>
  export default {
    data(){
      return {
        isShow:this.attrShow,
        model_name:"",
        currentPageDatas: [], // 当前页数据
        currentDatas: [], // 当前数据
        sourceDatas: [], // 源数据,用于临时筛选数据
        currentChecks:[], // 左侧框当前已勾选的键数组
        page: { pageNo: 1, pageSize: 30, total: 0 },
        formDatas:{
          river:[] // 已勾选数据
        },
        numTotal:30, // 最多只能选渠30个
        keyword:'' // 搜索关键字
      }
    },
    created() {
      this.init()
    },
    props:{
      attrShow:{
        type:Boolean,
        default:false
      }
    },
    methods:{
      // 关闭对话框
      cancle(){
        this.$emit("updateStatusData",false)
      },

      // 提交数据
      submitData(){

      },

      // 提交成功时清空数据
      clearData(){
        this.formDatas.river = []
        this.model_name = ""
        this.keyword = ""
        this.page.pageNo=1
      },

      // 初始化数据
      init() {
        let listData = [
            {id:1,name:"你好1"},
            {id:2,name:"你好2"},
            {id:3,name:"你好3"},
        ]

           // 处理字段别名
            var currentDatas = listData.map((value, index) => {
              return {
                label: value.name,
                key: value.id,
                obj: value,
              };
            });
            // 总数
            let arrLength = currentDatas.length;
            this.page.total = arrLength;
            // 初始化数据
            this.currentDatas = currentDatas;
            this.sourceDatas = currentDatas;
            // 初始化20条数据给当前第一页的变量
            this.currentPageDatas = this.currentDatas.slice(0, this.page.pageSize);
      },

      // 分页change
      handleCurrentChange(page_cur) {
        this.page.pageNo = page_cur

        // 先将选中的从当前数据过滤掉
        this.currentDatas = this.currentDatas.filter(
          function (value) {
            return !this.formDatas.river.includes(value.key);
          }.bind(this)
        );

        // 再将过滤好的当前数据选出指定页
        this.currentPageDatas = this.groupFunc(page_cur);

         // 再将选中的目标数组补给当前页变量,从而保证之前选的数据能在右边显示
        this.currentPageDatas = this.currentPageDatas.concat(
          this.sourceDatas.filter(
            function (val) {
              return this.formDatas.river.includes(val.key);
            }.bind(this)
          )
        );
      },

      // 监听勾选的数组
      leftCheckChange(checks,nochecks){
        this.currentChecks = checks
      },

      // 穿梭change
      transferChange(current, direction, move) {
        // 为了保证数据的一致性,目标数组还回来之后要插进当前数据变量
        if (direction == "left") {
          this.currentDatas = this.sourceDatas.filter(
            function (val) {
              return !current.includes(val.key);
            }.bind(this)
          );
          let arrLength = this.currentDatas.length;
          this.page.total = arrLength
        } else {
          if(this.formDatas.river.length > this.numTotal){
            this.$message({
              showClose: true,
              message: '抱歉,自定义模块游戏不能超过30个',
              type: 'warning'
            });

            this.formDatas.river = this.formDatas.river.filter(
              function (val){
                return !this.currentChecks.includes(val)
              }.bind(this)
            )

            return
          }
        }
        this.handleCurrentChange(this.page.pageNo)
      },

      // 穿梭搜索
      filterChange() {
        // 自定义搜索,从当前数组变量中过滤,再渲染回组件
        var currentDatas = this.sourceDatas.filter(
          function (val) {
            return (
              val.obj.name.indexOf(this.keyword) > -1 &&
              !this.formDatas.river.includes(val.key)
            );
          }.bind(this)
        );

        if (currentDatas.length != this.currentDatas.length) {
          this.currentDatas = currentDatas;
          this.handleCurrentChange(1);
        }
      },

      // 数组分页函数,返回当前页数据
      groupFunc(page_cur) {
        var currentDatas = [];
        let arrLength = this.currentDatas.length;
        if(arrLength <=0){
          return []
        }
        this.page.total = arrLength;
        let num = this.page.pageSize;
        let pageTotal = 1;

        // 最后一页全部勾选时
        let total = arrLength / num
        if(arrLength % num === 0){
          pageTotal = total
        } else {
          pageTotal = total + 1
        }
        if(page_cur > pageTotal){
          page_cur = pageTotal
        }

        let index = 0;
        for (let i = 0; i < arrLength; i++) {
          if (i % num === 0 && i !== 0) {
            currentDatas.push(this.currentDatas.slice(index, i));
            index = i;
          }
          if (i + 1 === arrLength) {
            currentDatas.push(this.currentDatas.slice(index, i + 1));
          }
        }
        return currentDatas[page_cur - 1];
      }
    },
    watch:{
      // 监听对话框状态变化
      attrShow:function(){
        this.isShow = this.attrShow
      },
      keyword:function(){
        this.filterChange()
      }
    }
  }
</script>

<style>
  .model_name_tip{
    font-size: 14px;
    font-weight: 700;
  }
  .input-with-select {
    background-color: #fff;
    width: 284px;
  }

  .input-with-select .el-input-group__append{
    padding: 0px 10px;
  }

  .input-with-select .el-input__inner{
    border: 1px solid #DCDFE6 !important;
  }
  .el-transfer_cus{
    width: 720px;
  }
  .el-transfer_cus .el-transfer__buttons{
    width: 120px !important;
  }

  .el-transfer_cus .el-transfer__buttons :nth-child(2){
    margin-left: 0px !important;
  }

  .el-transfer_cus .el-transfer-panel {
    width: 284px;
    height: 450px;
  }

  .el-transfer_cus  .el-transfer-panel__list{
    height: 450px;
  }


</style>

主组件:

<template>
  <div class="moduleCompile">
      <div class="moduleCompile_title">
          模块编辑
      </div>
      <div class="moduleCompile_content">
        <div class="content_leftBox">
            左边模块
        </div>
        <div class="content_rightBox">
            <div class="module_btn">
                <el-button @click="addModelShow" size="mini">+ APP模块</el-button>
            </div>
        </div>
      </div>
      <addModel :attrShow="addShow" @updateStatusData="updateStatusData"></addModel>
  </div>
</template>

<script>
import addModel from './addModel'
export default {
    components:{
        addModel
    },
    data(){
        return{
            addShow:false
        }
    },
    methods:{
        // 显示添加框
        addModelShow(){
          this.addShow = true
        },
        // 绑定状态更改,子组件通过$emit传入参数
        updateStatusData(e){
           this.addShow = e
        }
    }
}
</script>

<style lang="less" scoped>
.moduleCompile_title{
    font-size: 18px;
    font-weight: 600;
    background-color: #e1e1e186;
    text-align: left;
    padding: 10px 19px;
}
.moduleCompile_content{
    // padding:0 20px;
    display: flex;
    height:calc(100vh - 100px);
    .content_leftBox{
        width: 20%;
        background-color: burlywood;
    }
    .content_rightBox{
        width: 80%;
        // background-color: rgba(100, 148, 237, 0.288);
        display: flex;
        padding: 20px 35px;
        .content_nav{
            width: 82%;
        }
    }
}
</style>

最终效果:

element穿梭框内容是表格 element ui穿梭框分页_数据

组件库:iview + elementui