左右滑动组件

23 阅读2分钟

开发背景

在智能巡检项目开发中,资产类型的展示为目前未封装过的组件,需要自己进行开发。

需求

image.png

主要思路

  1. 使用el-radio-group组件,实现主要数据渲染
  2. 宽度不够时,显示左右滑动按钮(需要监听容器大小)
  3. 使用绝对定位功能,实现左右滑动逻辑

代码实现

<template>
  <div
    class="property-type-list"
    id="property-type-list-eque"
  >
    <div class="property-type-list-wrapper">
      <el-button
        icon="h-icon-angle_left"
        :disabled="leftBtnDisable"
        class="h-btn left-btn"
        @click="handleMoveFn('left')"
        v-if="moveBtnShow"
      >
      </el-button>
      <div
        class="camera-list"
        id="camera-list"
      >
        <el-radio-group
          class="checkboxgroup"
          id="checkboxgroup"
          v-model="checkedChannel"
          :gutter="8"
        >
          <el-radio-button
            class="camera-item"
            v-for="(item) in channelList"
            :key="item.AssetClassName+'-'+item.AssetClassID"
            :label="item.AssetClassID"
            :max-width="200"
            :title="item.AssetClassName"
          >{{ item.AssetClassName }}
          </el-radio-button>
        </el-radio-group>
      </div>
      <el-button
        icon="h-icon-angle_right"
        class="h-btn right-btn"
        :disabled="rightBtnDisable"
        @click="handleMoveFn('right')"
        v-if="moveBtnShow"
      >
      </el-button>
    </div>
  </div>
</template>

<script>
import eventBus from '@/Common/service/event/eventBus.js';

let that = null;

function debounce(fn, duration = 100) {
  let timer = null;
  return (...arg) => {
    clearTimeout(timer);
    timer = setTimeout(() => {
      fn(...arg);
    }, duration);
  };
}

export default {
  name: '',
  components: {},
  props: {
    assetClassList: {
      type: Array,
      default: () => {
        return [];
      }
    }
  },
  data() {
    return {
      leftBtnDisable: true,
      rightBtnDisable: true,
      moveBtnShow: false,
      checkedChannel: '',
      channelList: [],
      windowWidth: document.body.clientWidth,
      isFinish: true
    };
  },
  computed: {},
  watch: {
    assetClassList: {
      handler(val) {
        this.channelList = JSON.parse(JSON.stringify(val));
        this.channelList.unshift(
          {
            AssetClassName: this.$t('hcp_inspection_all_name'),
            AssetClassID: ''
          }
        );
      },
      deep: true,
      immediate: true
    },
    checkedChannel(val) {
      this.checkedChannelUpdate(val);
    },
    windowWidth() {
      this.checkPage();
    },
    channelList: {
      handler() {
        this.$nextTick(()=>{
          this.checkPage();
        });
      },
      deep: true
    }
  },
  mounted() {
    eventBus.$emit('assetClassChange-inspection', '');
    eventBus.$on('assetClassCheck-inspection', this.checkedChannelUpdate);
    that = this;
    window.onresize = () => {
      return (() => {
        this.windowWidth = document.documentElement.clientWidth; // 宽
      })();
    };
  },
  beforeDestroy() {
    window.onresize = null;
    eventBus.$off('assetClassCheck-inspection');
  },
  methods: {
    checkedChannelUpdate(val) {
      if (val) {
        let item = this.channelList.find(item => item.AssetClassID === val);
        if (item) {
          // 如果是新增,并且一行显示补下,行业栏自动移动到最后
          if (val === this.channelList[this.channelList.length - 1].AssetClassID) {
            this.checkedChannel = val;
            this.$nextTick(()=>{
              this.moveLast();
            });
          } else {
            this.checkedChannel = this.checkedChannel || val;
          }
          return eventBus.$emit('assetClassChange-inspection', item);
        }
      }
      this.checkedChannel = '';
      eventBus.$emit('assetClassChange-inspection', '');
    },
    moveLast() {
      if (!this.moveBtnShow || !this.isFinish) {
        return;
      }
      this.isFinish = false;
      let boxLong = document.getElementById('camera-list').offsetWidth;
      let element = document.getElementById('checkboxgroup');
      let channelLong = element.offsetWidth;
      let left = Number(element.style.left.split('px')[0]);
      let needMove = channelLong - Math.abs(left) - boxLong + 2;
      this.timer = setInterval(() => {
        if (needMove < 50) {
          left = left - needMove;
        } else {
          left = left - 50;
        }
        element.style.left = left === 0 ? '1px' : left + 'px';
        needMove = needMove - 50;
        if (needMove <= 0) {
          this.isFinish = true;
          clearInterval(this.timer);
          this.isFinish = true;
          if (Math.abs(left) + boxLong === channelLong) {
            this.rightBtnDisable = true;
          } else {
            this.rightBtnDisable = false;
          }
          if (Math.abs(left) > 0) {
            this.leftBtnDisable = false;
          } else {
            this.leftBtnDisable = true;
          }
        }
      }, 1);
    },
    // 检测是否显示分页按钮
    checkPage() {
      if (!document.getElementById('camera-list') || !document.getElementById('checkboxgroup')) {
        return;
      }
      // let channelLong = this.channelList.length * 128 - 8;
      let boxLong = document.getElementById('camera-list').offsetWidth;
      let element = document.getElementById('checkboxgroup');
      let channelLong = element.offsetWidth;
      let left = Number(element.style.left.split('px')[0]);
      if (boxLong < channelLong) {
        this.moveBtnShow = true;
      } else {
        element.style.left = '1px';
        this.moveBtnShow = false;
      }
      if (left < 0 && (Math.abs(left) + boxLong === channelLong)) {
        this.rightBtnDisable = true;
      } else {
        this.rightBtnDisable = false;
      }
      if (left < 0) {
        this.leftBtnDisable = false;
      } else {
        this.leftBtnDisable = true;
      }
    },
    handleMoveFn: debounce((direction) => {
      that.handleMove(direction);
    }, 100),
    // 移动通道
    handleMove(direction) {
      let element = document.getElementById('checkboxgroup');
      let channelLong = element.offsetWidth;
      let left = Number(element.style.left.split('px')[0]);
      // let channelLong = this.channelList.length * 128 - 8;
      let boxLong = document.getElementById('camera-list').offsetWidth;
      if (direction === 'right') {
        if (!this.isFinish) {
          return;
        }
        this.isFinish = false;
        let needMove = boxLong;
        if (channelLong - Math.abs(left) - boxLong < boxLong) {
          needMove = channelLong - Math.abs(left) - boxLong + 2;
        }
        this.timer = setInterval(() => {
          if (needMove < 10) {
            left = left - needMove;
          } else {
            left = left - 10;
          }
          element.style.left = left === 0 ? '1px' : left + 'px';
          needMove = needMove - 10;
          if (needMove <= 0) {
            clearInterval(this.timer);
            this.isFinish = true;
            if (Math.abs(left) + boxLong === channelLong) {
              this.rightBtnDisable = true;
            } else {
              this.rightBtnDisable = false;
            }
            if (Math.abs(left) > 0) {
              this.leftBtnDisable = false;
            } else {
              this.leftBtnDisable = true;
            }
          }
        }, 1);
      } else {
        if (!this.isFinish) {
          return;
        }
        this.isFinish = false;
        let needMove = boxLong;
        if (Math.abs(left) < boxLong) {
          needMove = Math.abs(left);
        }
        this.timer = setInterval(() => {
          if (needMove < 10) {
            left = left + needMove;
          } else {
            left = left + 10;
          }
          element.style.left = left === 0 ? '1px' : left + 'px';
          needMove = needMove - 10;
          if (needMove <= 0) {
            clearInterval(this.timer);
            this.isFinish = true;
            if (Math.abs(left) >= channelLong) {
              this.rightBtnDisable = true;
            } else {
              this.rightBtnDisable = false;
            }
            if (left < 0) {
              this.leftBtnDisable = false;
            } else {
              this.leftBtnDisable = true;
            }
          }
        }, 1);
      }
    }
  }
};
</script>
<style lang='less'>
@theme-color: #f00;
.property-type-list {
  .camera-list {
    flex: 1;
    width: 10px;
    height: 32px;
    overflow: hidden;
    position: relative;

    .checkboxgroup {
      top: 0;
      left: 1px;
      display: flex;
      flex-flow: row nowrap;
      position: absolute;
    }
  }
}
</style>
<style lang='less' scoped>
.property-type-list {
  width: 100%;
  height: 100%;

  .property-type-list-wrapper {
    width: 100%;
    height: 32px;
    display: flex;
    align-items: center;
    .h-btn.left-btn,.h-btn.right-btn{
      flex-shrink: 0;
      min-width: 24px;
      max-width: 24px;
    }
    .right-btn{
      margin-left: 10px;
      border: none;
    }
    .left-btn{
      margin-right: 10px;
      border: none;
    }
  }
}
</style>