249 lines
7.0 KiB
JavaScript
249 lines
7.0 KiB
JavaScript
"use strict";
|
|
const common_vendor = require("../../common/vendor.js");
|
|
const _sfc_main = {
|
|
name: "SmartTabs",
|
|
props: {
|
|
// 是否支持滚动
|
|
scrollEnable: {
|
|
type: Boolean,
|
|
required: false,
|
|
default: false
|
|
},
|
|
// 选项卡配置
|
|
tabs: {
|
|
type: Array,
|
|
required: true,
|
|
default: () => []
|
|
},
|
|
// 初始选中的索引
|
|
initialIndex: {
|
|
type: Number,
|
|
default: 0
|
|
},
|
|
// 动画时长
|
|
duration: {
|
|
type: Number,
|
|
default: 300
|
|
},
|
|
// 是否显示徽章
|
|
showBadge: {
|
|
type: Boolean,
|
|
default: true
|
|
},
|
|
// 激活状态颜色
|
|
activeColor: {
|
|
type: String,
|
|
default: "#007AFF"
|
|
},
|
|
// 非激活状态颜色
|
|
inactiveColor: {
|
|
type: String,
|
|
default: "#333"
|
|
},
|
|
// 最小项宽度(用于平铺模式)
|
|
minItemWidth: {
|
|
type: Number,
|
|
default: 120
|
|
// rpx
|
|
}
|
|
},
|
|
data() {
|
|
return {
|
|
currentIndex: this.initialIndex,
|
|
scrollLeft: 0,
|
|
tabWidths: [],
|
|
containerWidth: 0,
|
|
activeTabId: `tab_${this.initialIndex}`,
|
|
canScrollLeft: false,
|
|
canScrollRight: false
|
|
};
|
|
},
|
|
mounted() {
|
|
this.$nextTick(() => {
|
|
this.calculateLayout();
|
|
});
|
|
},
|
|
methods: {
|
|
// 计算布局
|
|
calculateLayout() {
|
|
this.getContainerWidth().then(() => {
|
|
this.calculateTabPositions().then(() => {
|
|
this.checkScrollability();
|
|
this.scrollToCurrentTab();
|
|
});
|
|
});
|
|
},
|
|
// 获取容器宽度
|
|
getContainerWidth() {
|
|
return new Promise((resolve) => {
|
|
const query = common_vendor.index.createSelectorQuery().in(this);
|
|
query.select(".tabs-header").boundingClientRect();
|
|
query.exec((res) => {
|
|
if (res && res[0]) {
|
|
this.containerWidth = res[0].width;
|
|
}
|
|
resolve();
|
|
});
|
|
});
|
|
},
|
|
// 计算选项卡位置
|
|
calculateTabPositions() {
|
|
return new Promise((resolve) => {
|
|
const query = common_vendor.index.createSelectorQuery().in(this);
|
|
this.tabs.forEach((_, index) => {
|
|
query.select(`#tab_${index}`).boundingClientRect();
|
|
});
|
|
query.exec((res) => {
|
|
this.tabWidths = res.map((item) => item ? item.width : 0);
|
|
resolve();
|
|
});
|
|
});
|
|
},
|
|
// 检查是否需要滚动
|
|
checkScrollability() {
|
|
this.checkScrollState();
|
|
},
|
|
// 检查滚动状态
|
|
checkScrollState() {
|
|
if (!this.$props.scrollEnable) {
|
|
this.canScrollLeft = false;
|
|
this.canScrollRight = false;
|
|
return;
|
|
}
|
|
this.canScrollLeft = this.scrollLeft > 0;
|
|
const totalWidth = this.tabWidths.reduce((sum, width) => sum + width, 0);
|
|
this.canScrollRight = this.scrollLeft < totalWidth - this.containerWidth;
|
|
},
|
|
// 滚动到当前选项卡
|
|
scrollToCurrentTab() {
|
|
if (this.tabWidths.length === 0 || !this.$props.scrollEnable)
|
|
return;
|
|
let totalWidth = 0;
|
|
for (let i = 0; i < this.currentIndex; i++) {
|
|
totalWidth += this.tabWidths[i];
|
|
}
|
|
const currentTabWidth = this.tabWidths[this.currentIndex];
|
|
const scrollLeft = totalWidth - (this.containerWidth - currentTabWidth) / 2;
|
|
this.scrollLeft = scrollLeft;
|
|
this.activeTabId = `tab_${this.currentIndex}`;
|
|
this.checkScrollState();
|
|
},
|
|
// 处理滚动事件
|
|
handleScroll(e) {
|
|
this.scrollLeft = e.detail.scrollLeft;
|
|
this.checkScrollState();
|
|
},
|
|
// 处理选项卡点击
|
|
handleTabClick(index) {
|
|
if (this.currentIndex !== index) {
|
|
this.currentIndex = index;
|
|
this.scrollToCurrentTab();
|
|
this.$emit("change", index);
|
|
}
|
|
},
|
|
// 处理滑动切换
|
|
handleSwiperChange(e) {
|
|
const index = e.detail.current;
|
|
if (this.currentIndex !== index) {
|
|
this.currentIndex = index;
|
|
this.scrollToCurrentTab();
|
|
this.$emit("change", index);
|
|
}
|
|
},
|
|
// 获取选项卡样式
|
|
getTabStyle(index) {
|
|
const isActive = this.currentIndex === index;
|
|
const style = {
|
|
color: isActive ? this.activeColor : this.inactiveColor,
|
|
fontWeight: isActive ? "bold" : "normal",
|
|
width: this.scrollEnable ? "auto" : `${100 / this.tabs.length}%`
|
|
};
|
|
if (!this.$props.scrollEnable) {
|
|
style.flex = "1";
|
|
style.minWidth = "0";
|
|
style.textAlign = "center";
|
|
}
|
|
return style;
|
|
},
|
|
getScrollViewStyle() {
|
|
console.log("aaa", this.$props.scrollEnable);
|
|
const isActive = this.$props.scrollEnable;
|
|
const style = {
|
|
"--scroll-content-display": isActive ? "block" : "flex"
|
|
};
|
|
console.log("aaa", this.$props.scrollEnable);
|
|
return style;
|
|
},
|
|
// 切换到指定选项卡
|
|
switchTo(index) {
|
|
if (index >= 0 && index < this.tabs.length && index !== this.currentIndex) {
|
|
this.currentIndex = index;
|
|
this.scrollToCurrentTab();
|
|
this.$emit("change", index);
|
|
}
|
|
},
|
|
// 向左滚动
|
|
scrollLeftByStep() {
|
|
this.scrollLeft = Math.max(0, this.scrollLeft - 100);
|
|
this.checkScrollState();
|
|
},
|
|
// 向右滚动
|
|
scrollRightByStep() {
|
|
const totalWidth = this.tabWidths.reduce((sum, width) => sum + width, 0);
|
|
const maxScroll = totalWidth - this.containerWidth;
|
|
this.scrollLeft = Math.min(maxScroll, this.scrollLeft + 100);
|
|
this.checkScrollState();
|
|
}
|
|
},
|
|
watch: {
|
|
initialIndex(newVal) {
|
|
if (newVal !== this.currentIndex) {
|
|
this.currentIndex = newVal;
|
|
this.scrollToCurrentTab();
|
|
}
|
|
},
|
|
tabs() {
|
|
this.$nextTick(() => {
|
|
this.calculateLayout();
|
|
});
|
|
}
|
|
}
|
|
};
|
|
const __injectCSSVars__ = () => {
|
|
common_vendor.useCssVars((_ctx) => ({
|
|
"71c614aa": _ctx.activeColor
|
|
}));
|
|
};
|
|
const __setup__ = _sfc_main.setup;
|
|
_sfc_main.setup = __setup__ ? (props, ctx) => {
|
|
__injectCSSVars__();
|
|
return __setup__(props, ctx);
|
|
} : __injectCSSVars__;
|
|
function _sfc_render(_ctx, _cache, $props, $setup, $data, $options) {
|
|
return {
|
|
a: common_vendor.f($props.tabs, (tab, index, i0) => {
|
|
return common_vendor.e({
|
|
a: common_vendor.t(tab.label),
|
|
b: $props.showBadge && tab.badge
|
|
}, $props.showBadge && tab.badge ? {
|
|
c: common_vendor.t(tab.badge > 99 ? "99+" : tab.badge)
|
|
} : {}, {
|
|
d: index,
|
|
e: `tab_${index}`,
|
|
f: $data.currentIndex === index ? 1 : "",
|
|
g: common_vendor.s($options.getTabStyle(index)),
|
|
h: common_vendor.o(($event) => $options.handleTabClick(index), index)
|
|
});
|
|
}),
|
|
b: $props.scrollEnable,
|
|
c: $data.scrollLeft,
|
|
d: $props.scrollEnable,
|
|
e: $data.activeTabId,
|
|
f: common_vendor.s($options.getScrollViewStyle()),
|
|
g: common_vendor.o((...args) => $options.handleScroll && $options.handleScroll(...args)),
|
|
h: common_vendor.s(_ctx.__cssVars())
|
|
};
|
|
}
|
|
const Component = /* @__PURE__ */ common_vendor._export_sfc(_sfc_main, [["render", _sfc_render], ["__scopeId", "data-v-f67213a1"]]);
|
|
wx.createComponent(Component);
|