uniapp 小程序 tabs切换 有筛选

<template>
  <view class="tabs" :style="{ height }">
    <scroll-view
      id="scrollContainer"
      :scroll-x="scroll"
      :scroll-left="scroll ? scrollLeft : 0"
      :scroll-with-animation="scroll"
      :style="{ position: fixed ? 'fixed' : 'relative', zIndex: 100, width: isFilter ? 'calc(100% - 100rpx)' : '100%' }"
			@dragend="scrollEnd"
    >
      <view
        class="tabs_container"
        :style="{
          display: scroll ? 'inline-flex' : 'flex',
          whiteSpace: scroll ? 'nowrap' : 'normal',
          background: bgColor,
          height,
          padding
        }"
      >
        <view
          class="item"
          v-for="(item, i) in tabs"
          :key="i"
          :style="{
            color: current == i ? activeColor : color,
            fontSize: current == i ? fontSize : fontSize,
            fontWeight: bold && current == i ? 'bold' : '',
            justifyContent: !scroll ? 'center' : '',
            flex: scroll ? '' : 1,
						padding: paddingItem
          }"
          @click="change(i)"
        >
          {{ filed ? item[filed] : item }}
        </view>
        <view
          v-if="!pills"
          :class="['line', {animation: lineAnimation}]"
          :style="{
            background: lineColor,
            width: lineWidth + 'px',
            height: lineHeight,
            borderRadius: lineRadius,
            left: lineLeft + 'px',
						bottom: lineBottom,
            transform: `translateX(-${lineWidth / 2}px)`
          }"
        ></view>
        <view
          v-else
          :class="['pills', {animation: lineAnimation}]"
          :style="{
            background: pillsColor,
            borderRadius: pillsBorderRadius,
            left: pillsLeft + 'px',
            width: currentWidth + 'px',
            height
          }"
        ></view>
      </view>
    </scroll-view>
    <view v-if="isFilter" class="tabs-filter" @click="filter" :style="{ height: height, padding, background: bgColor,  position: fixed ? 'fixed' : 'absolute', }">
			<img class="bg" src="/static/common/tabs_bg.png" alt="">
			<img src="/static/common/icon_filter.png" alt="" class="filter-img">
		</view>
  </view>
</template>

<script>
/**
 * v-tabs
 * @property {Number} value 选中的下标
 * @property {Array} tabs tabs 列表
 * @property {String} bgColor = '#fff' 背景颜色
 * @property {String} color = '#262626' 默认颜色
 * @property {String} activeColor = '#1890FF' 选中文字颜色
 * @property {String} fontSize = '28rpx' 默认文字大小
 * @property {String} activeFontSize = '28rpx' 选中文字大小
 * @property {Boolean} bold = [true | false] 选中文字是否加粗
 * @property {Boolean} scroll = [true | false] 是否滚动
 * @property {String} height = '84rpx' tab 的高度
 * @property {String} lineHeight = '8rpx' 下划线的高度
 * @property {String} lineColor = '#1890FF' 下划线的颜色
 * @property {Number} lineScale = 0.5 下划线的宽度缩放比例
 * @property {String} lineRadius = '4rpx' 下划线圆角
 * @property {String} lineBottom = '8rpx' 下划线位置
 * @property {Boolean} pills = [true | false] 是否胶囊样式
 * @property {String} pillsColor = '#1890FF' 胶囊背景色
 * @property {String} pillsBorderRadius = '10rpx' 胶囊圆角大小
 * @property {String} filed 如果是对象,显示的键名
 * @property {Boolean} fixed = [true | false] 是否固定
 * @property {String} paddingItem = '0 22rpx' 选项的边距
 * @property {Boolean} lineAnimation = [true | false] 下划线是否有动画
 * @property {Boolean} isFilter = [true | false] 是否有搜索
 * @event {Function(current)} change 改变标签触发
 * @event {Function()} filter 改变标签触发
 */
export default {
  props: {
    value: {
      type: Number,
      default: 0
    },
    tabs: {
      type: Array,
      default () {
        return []
      }
    },
    bgColor: {
      type: String,
      default: '#fff'
    },
    padding: {
      type: String,
      default: '0'
    },
    color: {
      type: String,
      default: '#000000'
    },
    activeColor: {
      type: String,
      default: '#1890FF'
    },
    fontSize: {
      type: String,
      default: '28rpx'
    },
    activeFontSize: {
      type: String,
      default: '28rpx'
    },
    bold: {
      type: Boolean,
      default: true
    },
    scroll: {
      type: Boolean,
      default: true
    },
    height: {
      type: String,
      default: '84rpx'
    },
    lineColor: {
      type: String,
      default: '#1890FF'
    },
    lineHeight: {
      type: String,
      default: '8rpx'
    },
    lineScale: {
      type: Number,
      default: 0.5
    },
    lineRadius: {
      type: String,
      default: '4rpx'
    },
		lineBottom: {
			type: String,
			default: '8rpx',
		},
    pills: {
      type: Boolean,
      default: false
    },
    pillsColor: {
      type: String,
      default: '#1890FF'
    },
    pillsBorderRadius: {
      type: String,
      default: '10rpx'
    },
    filed: {
      type: String,
      default: ''
    },
    fixed: {
      type: Boolean,
      default: false
    },
		paddingItem: {
		  type: String,
		  default: '0 24rpx'
		},
    lineAnimation: {
      type: Boolean,
      default: true
    },
		isFilter: {
			type: Boolean,
			default: false,
		}
  },
  data () {
    return {
      lineWidth: 30,
      currentWidth: 0, // 当前选项的宽度
      lineLeft: 0, // 滑块距离左侧的位置
      pillsLeft: 0, // 胶囊距离左侧的位置
      scrollLeft: 0, // 距离左边的位置
      containerWidth: 0, // 容器的宽度
      current: 0 // 当前选中项
    }
  },
  watch: {
    value (newVal) {
      this.current = newVal
      this.$nextTick(() => {
        this.getTabItemWidth()
      })
    },
    current (newVal) {
      this.$emit('input', newVal)
    },
    tabs (newVal) {
      this.$nextTick(() => {
        this.getTabItemWidth()
      })
    }
  },
  methods: {
    // 切换事件
    change (index) {
      if (this.current !== index) {
        this.current = index

        this.$emit('change', index)
      }
    },
		// 点击筛选
		filter() {
			this.$emit('filter')
		},
    // 获取左移动位置
    getTabItemWidth () {
      let query = uni
        .createSelectorQuery()
        // #ifndef MP-ALIPAY
        .in(this)
      // #endif
      // 获取容器的宽度
      query
        .select(`#scrollContainer`)
        .boundingClientRect((data) => {
          if (!this.containerWidth && data) {
            this.containerWidth = data.width
          }
        })
        .exec()
      // 获取所有的 tab-item 的宽度
      query
        .selectAll('.item')
        .boundingClientRect((data) => {
          if (!data) {
            return
          }
          let lineLeft = 0
          let currentWidth = 0
          if (data) {
            for (let i = 0; i < data.length; i++) {
              if (i < this.current) {
                lineLeft += data[i].width
              } else if (i == this.current) {
                currentWidth = data[i].width
              } else {
                break
              }
            }
          }
          // 当前滑块的宽度
          this.currentWidth = currentWidth
          // 缩放后的滑块宽度
          this.lineWidth = currentWidth * this.lineScale * 0.6
          // 滑块作移动的位置
          this.lineLeft = lineLeft + currentWidth / 2
          // 胶囊距离左侧的位置
          this.pillsLeft = lineLeft
          // 计算滚动的距离左侧的位置
          if (this.scroll) {
            this.scrollLeft = this.lineLeft - this.containerWidth / 2
          }
        })
        .exec()
    }
  },
  mounted () {
    this.current = this.value
    this.$nextTick(() => {
      this.getTabItemWidth()
    })
  }
}
</script>

<style lang="scss" scoped>
.tabs {
	position: relative;
  width: 100%;
	display: flex;
	justify-content: space-between;
  box-sizing: border-box;
  overflow: hidden;
  ::-webkit-scrollbar {
    display: none;
  }
  .tabs_container {
    min-width: 100%;
    position: relative;
    display: inline-flex;
    align-items: center;
    white-space: nowrap;
    overflow: hidden;
    .item {
      display: flex;
      align-items: center;
      height: 100%;
      position: relative;
      z-index: 10;
      transition: all 0.3s;
      white-space: nowrap;
			font-weight: bold;
    }
    .line {
      position: absolute;
    }

    .pills {
      position: absolute;
      z-index: 9;
    }
    .line,
    .pills {
      &.animation {
        transition: all 0.3s linear;
      }
    }
  }
}
.tabs-filter {
	position: absolute;
	right: 0;
	width: 100rpx;
	height: 84rpx;
	flex-shrink: 0;
	z-index: 101;
	.bg {
		width: 100%;
		height: 100%;
	}
	.filter-img {
		position: absolute;
		top: 26rpx;
		left: 42rpx;
		width: 32rpx;
		height: 32rpx;
	}
}
</style>

调用

// 可以滚动多个 有筛选的情况下
<Tabs v-model="selectScrollIndex" :tabs="selectScrollList" @change="changeselectScroll" filed="name" isFilter @filter="filterTabs"></Tabs>
// 不可滚动 几个的情况下无筛选
<Tabs v-model="summarizeIndex" :scroll="false" :tabs="SummarizeList" @change="changeSummarize" filed="name" ></Tabs>

data() {
	return {
		selectScrollIndex: 0, // tab切换下标
		selectScrollList: [{ // tab切换数据
			name: '数据概述',
		}, {
			name: '营业趋势图'
		}, {
			name: '菜类流水图'
		}, {
			name: '菜品销售图'
		}, {
			name: '营业详情',
		}, {
			name: '业务构成'
		}, {
			name: '堂食详情'
		}, {
			name: '外卖详情'
		}, {
			name: '用户习惯'
		}, {
			name: '用户结构'
		}, {
			name: '会员&普通用户&复购'
		}, {
			name: '订单分布'
		}],
		summarizeIndex: 0, // 数据概览下标
		SummarizeList: [{ // 数据概览列表
			name: '营收汇总'
		}, {
			name: '堂食订单'
		}, {
			name: '外卖订单'
		}],
	}
},
method: {
	changeselectScroll(index) {
	// 点击返回index
	},
	filterTabs() {
	//点击筛选按钮
	}
}

tabs切换 (参数都在代码里了,懒的写)

在这里插入图片描述

  • 2
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
好的,下面是一个简单的示例代码,用于实现基本的tabs切换: ``` <template> <view class="container"> <view class="tabs"> <view class="tab" :class="{ active: activeTab === 'tab1' }" @tap="switchTab('tab1')">Tab 1</view> <view class="tab" :class="{ active: activeTab === 'tab2' }" @tap="switchTab('tab2')">Tab 2</view> <view class="tab" :class="{ active: activeTab === 'tab3' }" @tap="switchTab('tab3')">Tab 3</view> </view> <view class="content"> <view v-if="activeTab === 'tab1'">Tab 1 Content</view> <view v-if="activeTab === 'tab2'">Tab 2 Content</view> <view v-if="activeTab === 'tab3'">Tab 3 Content</view> </view> </view> </template> <script> export default { data() { return { activeTab: 'tab1' } }, methods: { switchTab(tab) { this.activeTab = tab } } } </script> <style> .container { display: flex; flex-direction: column; height: 100vh; } .tabs { display: flex; justify-content: center; align-items: center; height: 60px; background-color: #eee; } .tab { margin-right: 10px; padding: 10px; font-size: 16px; cursor: pointer; } .tab.active { color: #fff; background-color: #333; } .content { flex: 1; display: flex; justify-content: center; align-items: center; } </style> ``` 这段代码定义了三个tab,分别为Tab 1、Tab 2和Tab 3。当用户点击某个tab时,通过`switchTab`方法来切换当前激活的tab,从而显示相应的内容。在代码中,使用了Vue的条件渲染技术,通过`v-if`指令来根据当前激活的tab来决定哪个tab内容需要被显示。最后,使用CSS来美化页面,使其更加美观。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值