Component({ options: { multipleSlots: true, addGlobalClass: true }, properties: { list: { type: Array }, active: { type: Number, value: 0 }, onChenge: { type: Function }, showIcon: { type: Boolean, value: true }, anchor: { type: Number, value: 0.4 // 锚点位置,0-1,表示选中项中心在容器宽度的比例位置 } }, data: { scrollLeft: 0, startPoint: 0, slipFlag: false, }, lifetimes: { attached: function () { getApp().globalData.Language.getLanguagePackage(this); }, ready: function () { this.setActive(); } }, methods: { tabsChenge(e) { const { index } = e.currentTarget.dataset; if (this.data.active == index) return; this.setData({ active: index }, () => { this.setActive(); }); }, setActive() { const that = this; const active = this.data.active; const anchor = this.data.anchor; const query = wx.createSelectorQuery().in(this); query.select('.scroll').fields({ rect: true, scrollOffset: true }) .select(`#active${active}`).boundingClientRect() .selectAll('.item').boundingClientRect() .exec((res) => { const container = res[0]; const elem = res[1]; const items = res[2]; if (!container || !elem || !items || items.length === 0) return; // 容器宽度通过 right - left 计算 const containerWidth = container.right - container.left; const containerLeft = container.left; const currentScrollLeft = container.scrollLeft || 0; const firstItem = items[0]; const lastItem = items[items.length - 1]; // 第一个元素相对于内容左边界的偏移(通常为0) const firstItemLeftContent = firstItem.left - containerLeft + currentScrollLeft; // 最后一个元素右边界相对于内容左边界的偏移 const lastItemRightContent = lastItem.left - containerLeft + currentScrollLeft + lastItem.width; const contentWidth = lastItemRightContent - firstItemLeftContent; const viewportWidth = containerWidth; const maxScrollLeft = Math.max(0, contentWidth - viewportWidth); // 选中元素在内容中的左偏移(相对于第一个元素) const elemLeftContent = elem.left - containerLeft + currentScrollLeft - firstItemLeftContent; // 目标:元素中心位于可视区域宽度 * anchor 处 const targetElemLeftInViewport = viewportWidth * anchor - elem.width / 2; let targetScrollLeft = elemLeftContent - targetElemLeftInViewport; // 边界限制 if (targetScrollLeft < 0) targetScrollLeft = 0; if (targetScrollLeft > maxScrollLeft) targetScrollLeft = maxScrollLeft; // 避免微小移动 if (Math.abs(targetScrollLeft - currentScrollLeft) < 1) return; that.setData({ scrollLeft: targetScrollLeft }); }); this.triggerEvent("onChenge", active); }, myTouchStart(e) { return; // 禁用滑动切换 this.setData({ slipFlag: true, startPoint: e.touches[0] }) }, myTouchMove(e) { return; // 禁用滑动切换 let active = this.data.active; if (((this.data.startPoint.clientX - e.touches[e.touches.length - 1].clientX) > 80) && this.data.slipFlag) { if (active != this.data.list.length - 1) active++; this.setData({ slipFlag: false, active }) } else if (((this.data.startPoint.clientX - e.touches[e.touches.length - 1].clientX) < -80) && this.data.slipFlag) { if (active != 0) active--; this.setData({ slipFlag: false, active }) } this.setActive(); }, } });