前言

在 uni-app 开发中  scroll-view 组件用到几率也是比较大滴,存在问题主要是:点击子元素,子元素在什么位置展示?

今天我们来好好总结一下 0.0~

Part.1  可能出现的需求

效果一:当前点击子元素靠左展示

uniapp官网 vue3 globalData uniapp官网scroll view_uni-app

 

效果二:当前点击子元素靠左留一展示

uniapp官网 vue3 globalData uniapp官网scroll view_uni-app_02

 

效果三:当前点击子元素居中展示

uniapp官网 vue3 globalData uniapp官网scroll view_元素节点_03

 

应该常见的用户体验效果就这三种了,我们看看怎么实现?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>