前言
在 uni-app 開發中 scroll-view 組件用到幾率也是比較大滴,存在問題主要是:點擊子元素,子元素在什么位置展示?
今天我們來好好總結一下 0.0~
Part.1 可能出現的需求
效果一:當前點擊子元素靠左展示
效果二:當前點擊子元素靠左留一展示
效果三:當前點擊子元素居中展示
應該常見的用戶體驗效果就這三種了,我們看看怎么實現?go~
Part.2 我的思路
在 uni-app 的官方( https://uniapp.dcloud.io/component/scroll-view ) API中對 scroll-view 組件有詳細的介紹和屬性說明,今天我們主要用到的屬性是:scroll-left (設置橫向滾動條的位置)
一般偷懶或者常用的方式是使用 scroll-into-view 這個屬性,隨着當前點擊元素的ID滾動,但是這個屬性制作出來后會和我上面 效果一 一樣靠左展示,這種展示方式體驗不是太好(從前往后點擊可能還好,但是從后往前就很...),這種方式配合 swiper 或者其它組件做長列表或者其它還可勉強接受,因為不用去點擊,直接手動滑動就可切換。但是假如不存在手可滑動的話,就會很糟糕。
接下來我們具體來看看,這三種效果如何實現:
效果一: 可直接使用 scroll-into-view 屬性實現 或者 也可使用 scroll-left
思路:第一種, scroll-into-view 綁定一個動態 ID,子元素循環產出ID,點擊時進行綁定(這次就不做代碼產出了)
第二種, 計算每個子元素的寬度,點擊時獲取當前點擊元素前面的元素寬度之和
效果二:使用 scroll-left
思路:計算每個子元素的寬度,點擊時獲取當前點擊元素索引 - 1 的前面元素寬度之和,相比於效果一的第二種情況,這里少算當前點擊元素前面的一個元素的寬度,實現留一
效果三:使用 scroll-left
思路:當前點擊子元素距離左邊欄的距離 - scroll-view 寬度的一半 + 當前點擊子元素一半的寬度 實現居中展示
Part.3 代碼實現
1 <template> 2 <view class="lxy-content"> 3 <scroll-view scroll-x="true" 4 class="content-scroll" 5 scroll-with-animation 6 :scroll-left="scrollLeft"> 7 <view v-for="(item, index) in category" 8 :key="index" 9 class="scroll-item" 10 @click="changeTitle(index)"> 11 <text class="item-text" 12 :class="curIndex == index? 'active' : ''">{{item.name}}</text> 13 </view> 14 </scroll-view> 15 </view> 16 </template>
1 <script> 2 export default { 3 data() { 4 return { 5 category: [ 6 { 7 id: 1, 8 name: '星期一' 9 }, 10 { 11 id: 2, 12 name: '星期二' 13 }, 14 { 15 id: 3, 16 name: '星期三' 17 }, 18 { 19 id: 4, 20 name: '星期四' 21 }, 22 { 23 id: 5, 24 name: '星期五' 25 }, 26 { 27 id: 6, 28 name: '星期六' 29 }, 30 { 31 id: 7, 32 name: '星期七' 33 }, 34 { 35 id: 8, 36 name: '星期八' 37 }, 38 { 39 id: 9, 40 name: '星期九' 41 }, 42 { 43 id: 10, 44 name: '星期十' 45 } 46 ], 47 48 contentScrollW: 0, // 導航區寬度 49 curIndex: 0, // 當前選中 50 scrollLeft: 0, // 橫向滾動條位置 51 } 52 }, 53 mounted() { 54 // 獲取標題區域寬度,和每個子元素節點的寬度 55 this.getScrollW() 56 }, 57 methods: { 58 // 獲取標題區域寬度,和每個子元素節點的寬度以及元素距離左邊欄的距離 59 getScrollW() { 60 const query = uni.createSelectorQuery().in(this); 61 62 query.select('.content-scroll').boundingClientRect(data => { 63 // 拿到 scroll-view 組件寬度 64 this.contentScrollW = data.width 65 }).exec(); 66 67 query.selectAll('.scroll-item').boundingClientRect(data => { 68 let dataLen = data.length; 69 for (let i = 0; i < dataLen; i++) { 70 // scroll-view 子元素組件距離左邊欄的距離 71 this.category[i].left = data[i].left; 72 // scroll-view 子元素組件寬度 73 this.category[i].width = data[i].width 74 } 75 }).exec() 76 }, 77 78 79 // 選擇標題 80 changeTitle(index) { 81 this.curIndex = index; 82 83 // 效果一(當前點擊子元素靠左展示) 局限性:子元素寬度相同 84 this.scrollLeft = index * this.category[index].width 85 86 // 效果一(當前點擊子元素靠左展示) 子元素寬度不相同也可實現 87 /* this.scrollLeft = 0; 88 for (let i = 0; i < index; i++) { 89 this.scrollLeft += this.category[i].width 90 }; */ 91 92 93 // 效果二(當前點擊子元素靠左留一展示) 局限性:子元素寬度相同 94 /* this.scrollLeft = (index - 1) * this.category[index].width */ 95 96 // 效果二(當前點擊子元素靠左留一展示) 子元素寬度不相同也可實現 97 /* this.scrollLeft = 0; 98 for (let i = 0; i < index - 1; i++) { 99 this.scrollLeft += this.category[i].width 100 }; */ 101 102 103 // 效果三(當前點擊子元素居中展示) 不受子元素寬度影響 104 /* this.scrollLeft = this.category[index].left - this.contentScrollW / 2 + this.category[index].width / 2; */ 105 106 } 107 } 108 } 109 </script>
1 <style lang="scss" scoped> 2 .lxy-content { 3 width: 100%; 4 height: 100rpx; 5 margin-top: 50rpx; 6 box-sizing: border-box; 7 .content-scroll { 8 height: 100rpx; 9 white-space: nowrap; 10 .scroll-item { 11 height: 100rpx; 12 padding: 0 20rpx; 13 display: inline-block; 14 text-align: center; 15 .item-text { 16 font-size: 30rpx; 17 line-height: 100rpx; 18 &.active { 19 color: #1468FF; 20 } 21 } 22 } 23 } 24 } 25 </style>