uniapp 制作一個可復用的segmented-control(tab選項卡)


開局一張圖,內容全靠編

1.開局一張圖(先上效果圖)

2.內容全靠編

 開始編寫復用組件:

 segmented-control.vue

<template>
  <view id="segmented" class="segmented" :style="{top:stickyTopData+'px'}">
    <view class="line" :style="{transform:'translateX('+offsetLeft+'px)',width:lineWidth+'px'}"></view>
    <view class="segmented-control">
        <view :id="'sc-'+index" :data-index="index" v-for="(item, index) in values" class="segmented-control-item" :key="index" :class="index === current ? 'active' : ''"
            @click="onClick">
            {{item}}
        </view>
    </view>
  </view>
    
</template>

<script>
export default {
  name: 'segmented-control',
  props: {
    values: { // 要顯示的數組
      type: Array,
      default() {
        return [];
      }
    },
    stickyTop:{ // 距離頭部多少px將其固定
      type: Number,
      default(){
        return 0;
      }
    },
    current: { // 當前選中第幾個
      type: Number,
      default(){
        return 1;
      }
    }
  },
  data() {
    return {
      lineWidth: 0, // 線的寬度
      offsetLeft: 0 // 相對左邊的距離
    };
  },
  methods: {
    /**
     * 點擊事件
     */
    onClick(e) {
      let index = parseInt(e.mp.target.dataset.index);
      let that = this;
      let id = e.mp.target.id;
      if (that.current !== index) {
        that.$emit('clickItem', index); // 父級組件回調方法
      }
    }
  },
  mounted() {
    let that = this;
    if (that.values) {
      if (that.values && that.values[that.current]) {
        that.lineWidth = 0;
        setTimeout(() => { // 延時獲取線的寬度和左邊距離
          const query = uni.createSelectorQuery();
          query.select('#sc-' + that.current).boundingClientRect();
          query.exec(res => {
            that.offsetLeft = res[0].left + 16;
            that.lineWidth = res[0].width - 70;
          });
        }, 500);
      }
    }
  },
  computed:{
    stickyTopData:function(){
      return uni.upx2px(this.stickyTop); // 頂部固定顯示距離
    }
  },
  watch: {
      current(newValue, oldValue) {
      let that = this;
          setTimeout(() => { // 監聽當前選擇的item變化,重新計算線的寬和左邊的距離
            const query = uni.createSelectorQuery();
            query.select('#sc-' + newValue).boundingClientRect();
            query.exec(res => {
              that.offsetLeft = res[0].left + 16;
              that.lineWidth = res[0].width - 70;
            });
          }, 200);
      }
  },
};
</script>

<style lang="less">
.segmented {
  position: sticky;
}
.segmented-control {
  display: flex;
  background: #ffffff; 
  align-items: center;
  padding: 20upx;
  border-bottom: 1px solid #f6f6f6;
  .segmented-control-item {
    width: 178upx;
    font-size: 32upx;
    color: #999;
  }
  .active {
    color: #333;
  }
}
.line {
  height: 6upx;
  border-radius: 3upx;
  background-color: #E5A600;
  position: absolute;
  top: 80upx;
  left: 0;
  transition: all 0.3s;
}
</style>

開始編寫父級組件來調用復用組件

list.vue

<template>
  <view>
    <segmented-control
      id="tabbar"
      :values="items"
      :stickyTop="108"
      :current="current"
      @clickItem="onClickItem"
    ></segmented-control>
    <view class="list" id="list">{{ current }}</view>
  </view>
</template>

<script>
import segmentedControl from '@/components/segmented-control';

export default {
  components: {
    segmentedControl
  },
  data() {
    return {
      items: ['已完成', '已拒絕', '已取消'],
      current: 0
    };
  },
  methods: {
    /**
     * 點擊segmentedControl 事件回調
     */
    onClickItem(index) {
      if (this.current !== index) {
        this.current = index;
      }
    }
  }
};
</script>

<style lang="less">
@import '../../css/list.less';
</style>

完事了,上圖

 

線的寬度、過渡的時間、樣式什么的自己調一調,改一改就行了

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM