vue自定义穿梭框支持远程滚动加载的实现方法

 更新时间:2023年08月16日 09:03:42   作者:SunnyRun!  
这篇文章主要介绍了vue自定义穿梭框支持远程滚动加载,iview是全局注入,基本使用原先的类名进行二次创建公共组件,修改基础js实现逻辑,本文结合实例代码介绍的非常详细,需要的朋友可以参考下

*分享一个使用比较久的🪜

技术框架公司的选型(老项目):vue2 + iview-ui方案的实现思路是共性的,展现UI样式需要你们自定义进行更改;因为iview是全局注入,基本使用原先的类名进行二次创建公共组件,修改基础js实现逻辑;

需求分析:实现远程滚动加载数据的穿梭框
1、创建自定义穿梭框,分左侧和右侧数据
2、依赖后端接口,左侧是左侧数据,右侧是右侧数据
3、定义好出入参数,支持回显内容及选中内容的去重处理
4、绑定对应的v-model数据响应
5、滚动加载数据,区分左右区域;添加自定义指令进行监听
6、滚动加载数据,不丢失已选中的数据,或去重已选中数据
7、支持左右侧的远程搜索功能,左右互不影响,检索数据放组件外部进行

在这里插入图片描述

1、代码信息

创建ivu-transfer.vue文件;依赖iviewUI请依据自己的样式进行拷贝;

1.1 自定义滚动监听指令

/** 远程滚动加载 */
import Vue from 'vue'
Vue.directive("loadTransfer", {
  bind(el, binding) {
    const select_dom = el.querySelectorAll('.ivu-transfer-list .ivu-transfer-list-content');
    select_dom.forEach((item, index) => {
      item.addEventListener('scroll', function () {
        const height = this.scrollHeight - this.scrollTop - 1 <= this.clientHeight;
        if (height) {
          binding.value(index)
        }
      })
    })
  }
})

1.2 自定义穿梭框代码

<template>
  <div class="ivu-transfer">
    <div
      class="ivu-transfer-list"
      :style="{
        width: listStyle.width,
        height: listStyle.height
      }"
    >
      <div class="ivu-transfer-list-header">
        <Checkbox
          :value="checkLeftAll"
          @on-change="handleAllLeftCheck"
        ></Checkbox>
        <span class="ivu-transfer-list-header-title">源列表</span>
        <span class="ivu-transfer-list-header-count">
          {{ leftDataSource.length }}
        </span>
      </div>
      <div class="ivu-transfer-list-body">
        <div class="ivu-transfer-list-content">
          <CheckboxGroup v-model="checkLeftAllGroup">
            <Checkbox
              :key="index"
              :label="item.value"
              class="ivu-transfer-list-content-item"
              v-for="(item, index) in leftDataSource"
              >{{
                item.label +
                  `${item.description ? ` - ${item.description}` : ""}`
              }}</Checkbox
            >
          </CheckboxGroup>
          <div
            v-if="!leftDataSource.length"
            class="ivu-transfer-list-content-not-found"
          >
            列表为空
          </div>
        </div>
      </div>
    </div>
    <div class="ivu-transfer-operation">
      <Button
        size="small"
        type="primary"
        icon="ios-arrow-back"
        @click="handleClickArrowBack"
        :disabled="!checkRightAllGroup.length"
      ></Button>
      <Button
        size="small"
        type="primary"
        icon="ios-arrow-forward"
        @click="handleClickArrowForward"
        :disabled="!checkLeftAllGroup.length"
      ></Button>
    </div>
    <div
      class="ivu-transfer-list"
      :style="{
        width: listStyle.width,
        height: listStyle.height
      }"
    >
      <div class="ivu-transfer-list-header">
        <Checkbox
          :value="checkRightAll"
          @on-change="handleAllRightCheck"
        ></Checkbox>
        <span class="ivu-transfer-list-header-title">目的列表</span>
        <span class="ivu-transfer-list-header-count">
          {{ rightDataSource.length }}
        </span>
      </div>
      <div class="ivu-transfer-list-body">
        <div class="ivu-transfer-list-content">
          <CheckboxGroup v-model="checkRightAllGroup">
            <Checkbox
              :key="index"
              :label="item.value"
              class="ivu-transfer-list-content-item"
              v-for="(item, index) in rightDataSource"
              >{{
                item.label +
                  `${item.description ? ` - ${item.description}` : ""}`
              }}
            </Checkbox>
          </CheckboxGroup>
          <div
            v-if="!rightDataSource.length"
            class="ivu-transfer-list-content-not-found"
          >
            列表为空
          </div>
        </div>
      </div>
    </div>
  </div>
</template>
<script>
const methods = {
  // 点击左侧全选
  handleAllLeftCheck() {
    this.checkLeftAll = !this.checkLeftAll;
    if (this.checkLeftAll) {
      this.checkLeftAllGroup = this.leftDataSource.map(item => item.value);
    } else {
      this.checkLeftAllGroup = [];
    }
  },
  // 点击右侧全选
  handleAllRightCheck() {
    this.checkRightAll = !this.checkRightAll;
    if (this.checkRightAll) {
      this.checkRightAllGroup = this.rightDataSource.map(item => item.value);
    } else {
      this.checkRightAllGroup = [];
    }
  },
  // 点击向右数据
  handleClickArrowBack() {
    this.moveCheckedData("left");
  },
  // 点击向左数据
  handleClickArrowForward() {
    this.moveCheckedData("right");
  },
  moveCheckedData(direction) {
    const newLeftDataSource = [];
    const newRightDataSource = [];
    const dataSource =
      direction === "left" ? this.rightDataSource : this.leftDataSource;
    dataSource.forEach(item => {
      const index =
        direction === "left"
          ? this.checkRightAllGroup.indexOf(item.value)
          : this.checkLeftAllGroup.indexOf(item.value);
      if (index !== -1) {
        direction === "left"
          ? newLeftDataSource.push(item)
          : newRightDataSource.push(item);
      } else {
        direction === "left"
          ? newRightDataSource.push(item)
          : newLeftDataSource.push(item);
      }
    });
    this.leftDataSource =
      direction === "left"
        ? [...this.leftDataSource, ...newLeftDataSource]
        : newLeftDataSource;
    this.rightDataSource =
      direction === "left"
        ? newRightDataSource
        : [...this.rightDataSource, ...newRightDataSource];
    this.checkLeftAll = false;
    this.checkRightAll = false;
    this.checkLeftAllGroup = [];
    this.checkRightAllGroup = [];
    this.$emit("on-change", this.leftDataSource, this.rightDataSource, direction);
  },
  filterDataMethods() {
    const rightValues = new Set(this.rightDataSource.map(opt => opt.value));
    this.leftDataSource = this.leftDataSource.filter(
      item => !rightValues.has(item.value)
    );
    this.$nextTick(() => {
      const leftValues = new Set(this.leftDataSource.map(opt => opt.value));
      this.rightDataSource = this.rightDataSource.filter(
        opt => !leftValues.has(opt.value)
      );
    });
  }
};
export default {
  props: {
    listStyle: {
      type: Object,
      default: () => ({
        width: "250px",
        height: "380px"
      })
    },
    leftData: {
      type: Array,
      require: true,
      default: () => []
    },
    rightData: {
      type: Array,
      require: true,
      default: () => []
    }
  },
  data() {
    return {
      checkLeftAll: false,
      checkRightAll: false,
      checkRightAllGroup: [],
      checkLeftAllGroup: [],
      leftDataSource: [],
      rightDataSource: []
    };
  },
  watch: {
    leftData(newVal) {
      this.leftDataSource = newVal;
      this.filterDataMethods();
    },
    rightData(newVal) {
      this.rightDataSource = newVal || [];
      this.filterDataMethods();
    }
  },
  mounted() {
    this.$nextTick(() => {
      this.$emit("on-change", this.leftDataSource, this.rightDataSource);
    })
  },
  methods
};
</script>
<style lang="less" scoped>
.ivu-transfer-list-content-item {
  width: 100%;
  margin-left: -0.3em;
}
.ivu-transfer-list-content-not-found {
  display: block;
}
</style>

2、内容使用api介绍

1、树形结构入参:dataSource=[{label: '测试',value: 1, description: '拼接内容' }],
2、标签引用:<IvuTransfer :leftData="dataSource" :rightData="targetKeys" @on-change="handleChange" v-loadTransfer="handleLoadMore" />
3、相关api说明文档在文章底部

<template>
 <div class="customSearch">
    <Input
      search
      clearable
      v-model="formLeftInput"
      placeholder="请输入搜索内容"
      @on-clear="handleOnLeftInput"
      @on-search="handleOnLeftInput"
    />
    <div style="width: 50px"></div>
    <Input
      search
      clearable
      v-model="formRightInput"
      placeholder="请输入搜索内容"
      @on-clear="handleOnRightInput"
      @on-search="handleOnRightInput"
    />
    </div>
    <IvuTransfer
      :leftData="dataSource"
      :rightData="targetKeys"
      @on-change="handleChange"
      v-loadTransfer="handleLoadMore"
    />
 </template>
// 远程滚动加载
  handleLoadMore(index) {
    if (index === 0 && this.dataLeftHasMore && !this.isShowLoading) {
      this.curLeftPage++;
      this.getLeftMockData();
    }
    if (index === 1 && this.dataRightHasMore && !this.rightLoading) {
      this.curRightPage++;
      this.getRightTargetKeys();
    }
  },
  // 触发选中移动
  handleChange(newLeftTargetData, newRightTargetKeys, direction) {
    this.dataSource = [...newLeftTargetData];
    this.targetKeys = [...newRightTargetKeys];
    if (direction === "right") {
      return this.remoteCheckPage();
    }
    if (direction === "left") {
      return this.remoteRightCheckPage();
    }
  },
getLeftData() {},
getRightData() {}
参数说明类型默认值必填项
leftData[{}]-label,value结构Array[][]
rightData[{}]-label,value结构Array[][]
on-change数据变更触发newLeft,newRight, direction

到此这篇关于vue自定义穿梭框支持远程滚动加载的文章就介绍到这了,更多相关vue远程滚动加载内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • 在vue项目中正确使用iconfont的方法

    在vue项目中正确使用iconfont的方法

    今天小编就为大家分享一篇在vue项目中正确使用iconfont的方法,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2018-09-09
  • 在vue-cli3中使用axios获取本地json操作

    在vue-cli3中使用axios获取本地json操作

    这篇文章主要介绍了在vue-cli3中使用axios获取本地json操作,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2020-07-07
  • 使用Vue.observable()进行状态管理的实例代码详解

    使用Vue.observable()进行状态管理的实例代码详解

    这篇文章主要介绍了使用Vue.observable()进行状态管理的实例代码,本文通过代码给大家介绍的非常详细,具有一定的参考借鉴价值,需要的朋友可以参考下
    2019-05-05
  • 前端Vue手机号校验以及后端Java手机号校验例子

    前端Vue手机号校验以及后端Java手机号校验例子

    接收一个输入的手机号,判断输入的手机号是否正确是一个很常见的功能,这篇文章主要给大家介绍了关于前端Vue手机号校验以及后端Java手机号校验的相关资料,需要的朋友可以参考下
    2023-11-11
  • vue中路由router配置步骤详解

    vue中路由router配置步骤详解

    vue的主要思想是组件化开发,路由用来配置组件对应展示路径,本文给大家介绍vue中路由router配置步骤,创建路由文件——使用路由——配置路由出口,使路由配置内容展示在页面上,感兴趣的朋友跟随小编一起看看吧
    2023-12-12
  • vue中i18n的安装与几种使用方式详解

    vue中i18n的安装与几种使用方式详解

    在一些网站经常可以看到切换语言包,将网站转化成多种语言版本的情况,下面这篇文章主要给大家介绍了关于vue中i18n的安装与几种使用方式的相关资料,需要的朋友可以参考下
    2022-09-09
  • Vue-component全局注册实例

    Vue-component全局注册实例

    今天小编就为大家分享一篇Vue-component全局注册实例,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2018-09-09
  • vue2.0 路由不显示router-view的解决方法

    vue2.0 路由不显示router-view的解决方法

    下面小编就为大家分享一篇vue2.0 路由不显示router-view的解决方法,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2018-03-03
  • vue基本使用--refs获取组件或元素的实例

    vue基本使用--refs获取组件或元素的实例

    今天小编就为大家分享一篇vue基本使用--refs获取组件或元素的实例,具有很好的参考价值,希望对大家有所帮助。一起个跟随小编过来看看吧
    2019-11-11
  • vue如何使用媒体查询实现响应式

    vue如何使用媒体查询实现响应式

    这篇文章主要介绍了vue如何使用媒体查询实现响应式,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2022-09-09

最新评论