实现移动端的tabs标签页,可滑动,可点击

<template>
  <div class="total_wrap">
    <div class="segment" ref="segment">
      <div
        v-for="(item, index) in segments"
        :key="index"
        :class="{ active: activeIndex === index }"
        @click="handleClick(index)"
      >
        {{ item }}
      </div>
    </div>
    <div class="content" ref="content">
      <div class="page" :style="{ transform: `translateX(-${offsetPx}px)` }">
        <div v-for="(item, index) in segments" :key="index" class="page-item">
          {{ item }} Content
        </div>
      </div>
    </div>
  </div>
</template>

<script>
export default {
  data() {
    return {
      segments: ["Segment 1", "Segment 2", "Segment 3"],
      activeIndex: 0,
      startX: 0,
      offset: 0,
      offsetPx: 0,
      segmentOffset: 0,
    };
  },
  mounted() {
    this.$refs.content.addEventListener("touchstart", this.handleTouchStart);
    this.$refs.content.addEventListener("touchmove", this.handleTouchMove);
    this.$refs.content.addEventListener("touchend", this.handleTouchEnd);
  },
  methods: {
    handleClick(index) {
      this.activeIndex = index;
      this.offsetPx = this.activeIndex * this.$refs.content.clientWidth;
      this.segmentOffset =
        (this.activeIndex * this.$refs.segment.clientWidth) /
        this.segments.length;
      this.$refs.segment.style.setProperty(
        "--segmentOffset",
        `${this.segmentOffset}px`
      );
    },
    handleTouchStart(event) {
      this.startX = event.touches[0].clientX;
      this.offset = 0;
    },
    handleTouchMove(event) {
      this.offset = event.touches[0].clientX - this.startX;
      if (
        this.offsetPx >
          (this.segments.length - 1) * this.$refs.content.clientWidth ||
        this.segmentOffset >
          (this.$refs.segment.clientWidth / this.segments.length) *
            (this.segments.length - 1) ||
        this.segmentOffset < 0
      ) {
        return;
      }
      this.offsetPx =
        this.activeIndex * this.$refs.content.clientWidth -
        this.offset +
        window
          .getComputedStyle(this.$refs.content)
          .paddingLeft.replace("px", "") *
          2;
      this.segmentOffset =
        (this.activeIndex * this.$refs.segment.clientWidth - this.offset) /
        this.segments.length;
      this.$refs.segment.style.setProperty(
        "--segmentOffset",
        `${this.segmentOffset}px`
      );
    },
    handleTouchEnd() {
      const threshold = this.$refs.segment.offsetWidth / 4;
      if (this.offset > threshold && this.activeIndex > 0) {
        this.activeIndex--;
      } else if (
        this.offset < -threshold &&
        this.activeIndex < this.segments.length - 1
      ) {
        this.activeIndex++;
      }
      this.offsetPx =
        this.activeIndex * this.$refs.content.clientWidth
      this.segmentOffset =
        (this.activeIndex * this.$refs.segment.clientWidth) /
        this.segments.length;
      this.$refs.segment.style.setProperty(
        "--segmentOffset",
        `${this.segmentOffset}px`
      );
    },
  },
};
</script>

<style>
.segment {
  width: 100%;
  display: flex;
  background-color: #ecf0f1;
  justify-content: space-around;
  transition: transform 0.3s ease-out;
  transform: translateX(0);
  overflow: hidden;
}

.segment div {
  padding: 6px 12px;
  cursor: pointer;
  position: relative;
  box-sizing: content-box;
  margin: 4px 8px;
}
.segment div:nth-child(1):after {
  position: absolute;
  content: "";
  width: 100%;
  height: 100%;
  top: 0;
  left: 0;
  background-color: #fefefe;
  z-index: -1;
  transform: translateX(var(--segmentOffset));
  transition: 0.25s ease-out;
  border-radius: 4px;
}

/* .segment div.active {
  background-color: #e0e0e0;
} */
.content {
  width: 100%;
  overflow: hidden;
}

.page {
  display: flex;
  transition: transform 0.3s ease-out;
}

.page-item {
  width: 100%;
  height: 500px;
  flex-shrink: 0;
  padding: 20px;
  background-color: #f0f0f0;
  text-align: center;
  font-size: 24px;
  box-sizing: border-box;
}
</style>
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值