【vue+el-transfer】穿梭框实现及遇到的bug,已解决

昨晚加班写的穿梭框组件,一边写一边遇到bug,果然只有bug才会让你印象更深刻,更值得记录

封装成组件FreezeTransfer

效果如下:

在这里插入图片描述

主要参考了官网上可搜索的这个示例

在这里插入图片描述
先说遇到的bug,然后贴完整的代码

1、el-transfer数据源绑定之后不展示,filterMethod不对的原因
2、点单个复选框,所有项都被选中,数据被处理后,不需要再 使用props转换
:props=“{
key: ‘id’,
label: ‘cnName’
}”
转换
3、未选择的时候,中间按钮的左右箭头不显示
4、行没有占全
5、每次打开弹窗的时候,初始化
6、change事件的使用
7、清空某个面板的搜索关键词

1、先说第一个绑数据源,按官网给的示例,这个和treeselect的示例差不多,需要将格式转换成它要求的格式
在这里插入图片描述
在这里插入图片描述
正常从接口获取数据就行,我这里是组件,所以在父页面获取到之后,传到子组件就行,在子组件里监听数据源,处理数据之后给treansfer绑定的data

 dataSource: {
    
    
      handler(newVal) {
    
    
        this.source = newVal.map(item => {
    
    
          let obj = {
    
    
            key: item.code,
            code: item.code,
            label: item.cnName,
            disabled: false,
          }

          return obj
        })
        this.$emit('getCode', [])
      },
      deep: true,
      immediate: true,
    },

这里遇到的bug就是左侧的数据源已经有了,但就是什么都不展示,一片空白
这个坑就是filter-method引起的,因为我是可搜索的穿梭框,从官方示例拿过来的时候,先定义了这个方法,但是啥都没写,真的是不踩一下根本不知道这还会影响数据源的展示

:filter-method="filterMethod"
filterMethod(query, item) {
    
    
//模糊查询,不区分英文大小写
      return item.key.toUpperCase().indexOf(query.toUpperCase()) > -1 || item.label.indexOf(query) > -1
    },

2、点单个复选框,所有项都被选中,可能的原因就是id都绑了一样的,但我排查了不是这个原因,这也是个坑,就是数据源处理过了之后,不需要再写props转换了
在这里插入图片描述
不需要

  :props="{
      key: 'id',
      label: 'cnName'
    }"

3、未选择的时候,中间按钮的左右箭头不显示
官网未选择的时候
在这里插入图片描述
我这里没有中间的箭头,可能是样式受影响了
在这里插入图片描述

/deep/ .el-button.el-button--primary.is-disabled {
    
    
  color: #fff !important;
}

4、行没有占全

/deep/ .el-transfer-panel__item.el-checkbox {
    
    
  width: 100%;
}

5、每次打开弹窗的时候,初始化
因为是放在弹窗中展示的,每次打开弹窗要初始化数据
父组件上定义initTransarr数组,在确认及取消事件中置为空

  :initTransarr="initTransarr"
  initTransarr:[]
      /** 弹框确认取消 */
    dialogSure(flag) {
    
    
      if (flag === 'sure') {
    
    

          this.$emit('handleSure', this.custCodearr)
        }
      } else {
    
    
        this.$emit('handleCancel')
      }
      this.initTransarr = []
      this.$emit('update:visible', false)
    },

6、change事件的使用
这里说下,left-check-change和right-check-change,分别在左侧和右侧勾选复选框的时候触发,我这里因为需求的调整,没用到,但还是保留了
在这里插入图片描述

change事件三个参数,当前值、数据移动的方向(‘left’ / ‘right’)、发生移动的数据 key 数组,就是中间左右箭头的事件

7、清空某个面板的搜索关键词
在这里插入图片描述

父组件

    <FreezeTransfer
      v-if="isTransfer"
      ref="freezeTransfer"
      :visible="visible"
      :dataSource="dataSource"
      :initTransarr="initTransarr"
      @getCode="getCode"
    ></FreezeTransfer>
    
  data() {
    
    
    return {
    
    
    visible:false,
      custCodearr: [],
      initTransarr: [],
    }
  },
    getCode(arr) {
    
    
      this.custCodearr = arr
    },
 /** 弹框确认取消 */
    dialogSure(flag) {
    
    
      if (flag === 'sure') {
    
    

          this.$emit('handleSure', this.custCodearr)
        }
      } else {
    
    
        this.$emit('handleCancel')
      }
      this.initTransarr = []
      this.$emit('update:visible', false)
    },

子组件

<template>
  <div class="transfer">
    <el-transfer
      v-if="visible"
      ref="transfer"
      filterable
      :filter-method="filterMethod"
      :filter-placeholder="$t('placeholderName.enter')"
      v-model="value"
      :data="source"
      :titles="['可选择', '已选择']"
      @change="handleChange"
      @left-check-change="leftcheckChange($event)"
      @right-check-change="rightcheckChange($event)"
    >
      <span slot-scope="{ option }">{
    
    {
    
     option.code }} - {
    
    {
    
     option.label }}</span>
    </el-transfer>
  </div>
</template>

<script>
export default {
    
    
  name: 'FreezeTransfer',
  props: {
    
    
    // 列表显示隐藏
    visible: {
    
    
      type: Boolean,
      default: false,
    },
    // 列表数据
    dataSource: {
    
    
      type: Array,
      default: () => {
    
    
        return []
      },
    },
    // 初始化右侧数据
    initTransarr: {
    
    
      type: Array,
      default: () => {
    
    
        return []
      },
    },

  },
  data() {
    
    
    return {
    
    
      source: [], // 总数据
      value: [],
    }
  },
  watch: {
    
    

    initTransarr: {
    
    
      handler(newVal) {
    
    
        this.value = newVal
      },
      deep: true,
    },
    dataSource: {
    
    
      handler(newVal) {
    
    
        this.source = newVal.map(item => {
    
    
          let obj = {
    
    
            key: item.code,
            code: item.code,
            label: item.cnName,
            disabled: false,
          }

          return obj
        })
        this.$emit('getCode', [])
      },
      deep: true,
      immediate: true,
    },
  },
  mounted() {
    
    },
  methods: {
    
    
    filterMethod(query, item) {
    
    
      return item.key.toUpperCase().indexOf(query.toUpperCase()) > -1 ||         	item.label.indexOf(query) > -1
    },
    //当前值、数据移动的方向('left' / 'right')、发生移动的数据 key 数组
    handleChange(value, direction, movedKeys) {
    
    
      if (direction == 'right') {
    
    
        this.$nextTick(() => {
    
    
          this.$refs.transfer.clearQuery('left')
        })
      } else if (direction == 'left') {
    
    
        this.$nextTick(() => {
    
    
          this.$refs.transfer.clearQuery('right')
        })
      }
      var arr = []
      value.forEach(item => {
    
    
        arr.push({
    
     code: item })
      })
      this.$emit('getCode', arr)
    },
    leftcheckChange(e) {
    
    
      //   console.log(e,'left------');
    },
    rightcheckChange(e) {
    
    
    //   console.log(e,'right------');
    },



  },
}
</script>

<style scoped lang="scss">
.transfer {
    
    
  width: 100%;
  /deep/ .el-transfer-panel {
    
    
    width: 45%;
  }
}
/deep/ .el-button.el-button--primary.is-disabled {
    
    
  color: #fff !important;
}
/deep/ .el-transfer-panel__item.el-checkbox {
    
    
  width: 100%;
}
/deep/ .el-transfer-panel__list {
    
    
  height: 480px !important;
}
/deep/ .el-transfer-panel__body {
    
    
  height: 480px !important;
}
</style>

猜你喜欢

转载自blog.csdn.net/weixin_49668076/article/details/131303141
今日推荐