開局一張圖,內容全靠編
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>
完事了,上圖
線的寬度、過渡的時間、樣式什么的自己調一調,改一改就行了