uniapp中自动滚动tabs的实现

301 阅读1分钟

uniapp中自动滚动tabs的实现

<template>
  <view class="tabBlock" v-if="type.length > 0">
    <scroll-view
      scroll-x="true"
      scroll-with-animation
      :scroll-left="tabsScrollLeft"
      @scroll="scroll"
    >
      <view class="tab" id="tab_list">
        <view
          v-for="(item, index) in type"
          :key="index"
          :class="[
            'tab__item',
            { 'tab__item--active': currentIndex === index },
          ]"
          :style="{ color: currentIndex === index ? `${itemColor}` : '' }"
          id="tab_item"
          @click="select(item, index)"
        >
          <view class="tab__item-title">
            {{ item.title }}
          </view>
        </view>
      </view>
      <view
        class="tab__line"
        :style="{
          background: lineColor,
          width: lineStyle.width,
          transform: lineStyle.transform,
          transitionDuration: lineStyle.transitionDuration,
        }"
      >
      </view>
    </scroll-view>
  </view>
</template>
<script>
export default {
  props: {
    value: [Number, String],
    type: {
      // 传值
      type: Array,
      default: () => {
        return [];
      },
    },
    itemColor: String,
    lineColor: String,
    lineAnimated: {
      type: Boolean,
      default: true,
    },
  },
  data() {
    return {
      currentIndex: 0,
      lineStyle: {},
      scrollLeft: 0,
      tabsScrollLeft: 0,
      duration: 0.3,
    };
  },
  watch: {
    type() {
      this.setTabList();
    },
    value() {
      this.currentIndex = this.value;
      this.setTabList();
    },
  },
  mounted() {
    this.currentIndex = this.value;
    this.setTabList();
    if (!this.lineAnimated) {
      this.duration = 0;
    }
  },
  methods: {
    select(item, index) {
      this.$emit("input", index);
    },
    setTabList() {
      this.$nextTick(() => {
        if (this.type.length > 0) {
          this.setLine();
          this.scrollIntoView();
        }
      });
    },
    setLine() {
      let lineWidth = 0,
        lineLeft = 0;
      this.getElementData(`#tab_item`, (data) => {
        let el = data[this.currentIndex];
        lineWidth = el.width / 2;
        lineLeft = el.width / 2 + -data[0].left + el.left;
        this.lineStyle = {
          width: `${lineWidth}px`,
          transform: `translateX(${lineLeft}px) translateX(-50%)`,
          transitionDuration: `${this.duration}s`,
        };
      });
    },
    scrollIntoView() {
      // item滚动
      let lineLeft = 0;
      this.getElementData("#tab_list", (data) => {
        let list = data[0];
        this.getElementData(`#tab_item`, (data) => {
          let el = data[this.currentIndex];
          lineLeft =
            el.width / 2 +
            -list.left +
            el.left -
            list.width / 2 -
            this.scrollLeft;
          this.tabsScrollLeft = this.scrollLeft + lineLeft;
        });
      });
    },
    getElementData(el, callback) {
      uni
        .createSelectorQuery()
        .in(this)
        .selectAll(el)
        .boundingClientRect()
        .exec((data) => {
          callback(data[0]);
        });
    },
    scroll(e) {
      this.scrollLeft = e.detail.scrollLeft;
    },
  },
};
</script>
<style lang="scss">
.tabBlock {
  position: relative;
  background: #fff;
  .tab {
    position: relative;
    display: flex;
    font-size: 28rpx;
    padding-bottom: 15rpx;
    white-space: nowrap;
    &__item {
      flex: 1;
      text-align: center;
      line-height: 90rpx;
      color: #666666;
      &--active {
        color: #e43130;
      }
      &-title {
        margin: 0 20rpx;
      }
    }
  }
  .tab__line {
    display: block;
    height: 6rpx;
    position: absolute;
    bottom: 25rpx;
    left: 0;
    z-index: 1;
    border-radius: 3rpx;
    position: relative;
    border-radius: 32rpx;
    background-color: #e43130;
  }
}
</style>