22 <template v-if =" sticky " >
33 <wd-sticky-box >
44 <view
5- :class =" `wd-tabs ${customClass} ${slidableNum < items.length ? 'is-slide' : ''} ${mapNum < items.length && mapNum !== 0 ? 'is-map' : ''}`"
5+ :class =" `wd-tabs ${customClass} ${innerSlidable ? 'is-slide' : ''} ${mapNum < items.length && mapNum !== 0 ? 'is-map' : ''}`"
66 :style =" customStyle"
77 >
88 <wd-sticky :offset-top =" offsetTop" >
99 <!-- 头部导航容器-->
1010 <view class =" wd-tabs__nav wd-tabs__nav--sticky" >
1111 <view class =" wd-tabs__nav--wrap" >
12- <scroll-view :scroll-x =" slidableNum < items.length " scroll-with-animation :scroll-left =" state.scrollLeft" >
12+ <scroll-view :scroll-x =" innerSlidable " scroll-with-animation :scroll-left =" state.scrollLeft" >
1313 <view class =" wd-tabs__nav-container" >
1414 <!-- nav列表-->
1515 <view
2020 :style =" state.activeIndex === index ? (color ? 'color:' + color : '') : inactiveColor ? 'color:' + inactiveColor : ''"
2121 >
2222 {{ item.title }}
23+ <view class =" wd-tabs__line wd-tabs__line--inner" v-if =" state.activeIndex === index && state.useInnerLine" ></view >
2324 </view >
2425 <!-- 下划线-->
2526 <view class =" wd-tabs__line" :style =" state.lineStyle" ></view >
7677 </template >
7778
7879 <template v-else >
79- <view :class =" `wd-tabs ${customClass} ${slidableNum < items.length ? 'is-slide' : ''} ${mapNum < items.length && mapNum !== 0 ? 'is-map' : ''}`" >
80+ <view :class =" `wd-tabs ${customClass} ${innerSlidable ? 'is-slide' : ''} ${mapNum < items.length && mapNum !== 0 ? 'is-map' : ''}`" >
8081 <!-- 头部导航容器-->
8182 <view class =" wd-tabs__nav" >
8283 <view class =" wd-tabs__nav--wrap" >
83- <scroll-view :scroll-x =" slidableNum < items.length " scroll-with-animation :scroll-left =" state.scrollLeft" >
84+ <scroll-view :scroll-x =" innerSlidable " scroll-with-animation :scroll-left =" state.scrollLeft" >
8485 <view class =" wd-tabs__nav-container" >
8586 <!-- nav列表-->
8687 <view
9192 :style =" state.activeIndex === index ? (color ? 'color:' + color : '') : inactiveColor ? 'color:' + inactiveColor : ''"
9293 >
9394 {{ item.title }}
95+ <view class =" wd-tabs__line wd-tabs__line--inner" v-if =" state.activeIndex === index && state.useInnerLine" ></view >
9496 </view >
9597 <!-- 下划线-->
9698 <view class =" wd-tabs__line" :style =" state.lineStyle" ></view >
@@ -143,7 +145,6 @@ export default {
143145import wdIcon from ' ../wd-icon/wd-icon.vue'
144146import wdSticky from ' ../wd-sticky/wd-sticky.vue'
145147import wdStickyBox from ' ../wd-sticky-box/wd-sticky-box.vue'
146-
147148import { computed , getCurrentInstance , onMounted , watch , nextTick , reactive , type CSSProperties } from ' vue'
148149import { addUnit , checkNumRange , debounce , getRect , isDef , isNumber , isString , objToStyle } from ' ../common/util'
149150import { useTouch } from ' ../composables/useTouch'
@@ -162,6 +163,7 @@ const { translate } = useTranslate('tabs')
162163const state = reactive ({
163164 activeIndex: 0 , // 选中值的索引,默认第一个
164165 lineStyle: ' display:none;' , // 激活项边框线样式
166+ useInnerLine: false , // 是否使用内部激活项边框线,当外部激活下划线未成功渲染时显示内部定位的
165167 inited: false , // 是否初始化
166168 animating: false , // 是否动画中
167169 mapShow: false , // map的开关
@@ -171,12 +173,16 @@ const state = reactive({
171173// map的开关
172174
173175const { children, linkChildren } = useChildren (TABS_KEY )
174- linkChildren ({ state })
176+ linkChildren ({ state , props })
175177
176178const { proxy } = getCurrentInstance () as any
177179
178180const touch = useTouch ()
179181
182+ const innerSlidable = computed (() => {
183+ return props .slidable === ' always' || items .value .length > props .slidableNum
184+ })
185+
180186// tabs数据
181187const items = computed (() => {
182188 return children .map ((child , index ) => {
@@ -196,29 +202,33 @@ const bodyStyle = computed(() => {
196202 })
197203})
198204
205+ /**
206+ * 更新激活项
207+ * @param value 激活值
208+ * @param init 是否已初始化
209+ * @param setScroll // 是否设置scroll-view滚动
210+ */
211+ const updateActive = (value : number | string = 0 , init : boolean = false , setScroll : boolean = true ) => {
212+ // 没有tab子元素,不执行任何操作
213+ if (items .value .length === 0 ) return
214+
215+ value = getActiveIndex (value )
216+ // 被禁用,不执行任何操作
217+ if (items .value [value ].disabled ) return
218+ state .activeIndex = value
219+ if (setScroll ) {
220+ updateLineStyle (init === false )
221+ scrollIntoView ()
222+ }
223+ setActiveTab ()
224+ }
225+
199226/**
200227 * @description 修改选中的tab Index
201228 * @param {String |Number } value - radio绑定的value或者tab索引,默认值0
202229 * @param {Boolean } init - 是否伴随初始化操作
203230 */
204- const setActive = debounce (
205- function (value : number | string = 0 , init : boolean = false , setScroll : boolean = true ) {
206- // 没有tab子元素,不执行任何操作
207- if (items .value .length === 0 ) return
208-
209- value = getActiveIndex (value )
210- // 被禁用,不执行任何操作
211- if (items .value [value ].disabled ) return
212- state .activeIndex = value
213- if (setScroll ) {
214- updateLineStyle (init === false )
215- scrollIntoView ()
216- }
217- setActiveTab ()
218- },
219- 100 ,
220- { leading: false }
221- )
231+ const setActive = debounce (updateActive , 100 , { leading: false })
222232
223233watch (
224234 () => props .modelValue ,
@@ -282,7 +292,8 @@ watch(
282292onMounted (() => {
283293 state .inited = true
284294 nextTick (() => {
285- setActive (props .modelValue , true )
295+ updateActive (props .modelValue , true )
296+ state .useInnerLine = true
286297 })
287298})
288299
@@ -305,15 +316,15 @@ function toggleMap() {
305316}
306317
307318/**
308- * @description 更新navBar underline的偏移量
309- * @param {Boolean} animation 是否伴随动画
319+ * 更新 underline的偏移量
320+ * @param animation 是否开启动画
310321 */
311322function updateLineStyle(animation : boolean = true ) {
312323 if (! state .inited ) return
313324 const { lineWidth, lineHeight } = props
325+
314326 getRect ($item , true , proxy ).then ((rects ) => {
315327 const lineStyle: CSSProperties = {}
316-
317328 if (isDef (lineWidth )) {
318329 lineStyle .width = addUnit (lineWidth )
319330 }
@@ -323,11 +334,14 @@ function updateLineStyle(animation: boolean = true) {
323334 }
324335 const rect = rects [state .activeIndex ]
325336 let left = rects .slice (0 , state .activeIndex ).reduce ((prev , curr ) => prev + Number (curr .width ), 0 ) + Number (rect .width ) / 2
326- lineStyle .transform = ` translateX(${left }px) translateX(-50%) `
327- if (animation ) {
328- lineStyle .transition = ' width 300ms ease, transform 300ms ease'
337+ if (left ) {
338+ lineStyle .transform = ` translateX(${left }px) translateX(-50%) `
339+ if (animation ) {
340+ lineStyle .transition = ' width 300ms ease, transform 300ms ease'
341+ }
342+ state .useInnerLine = false
343+ state .lineStyle = objToStyle (lineStyle )
329344 }
330- state .lineStyle = objToStyle (lineStyle )
331345 })
332346}
333347/**
0 commit comments