微信小程序实战之scroll-view的n种用法

11,323 阅读5分钟

这是我参与更文挑战的第2天,活动详情查看: 更文挑战

前言

在开发小程序的过程中,官方自带的组件scroll-view应该是使用的地方很多了,今天就来看看这个组件的n中常见用法。

官方介绍

尤大说了文档是个好东西!所以在学习任何东西的时候,首先我们需要做的就是认认真真的去看看官方文档介绍,毕竟很多东西都能够从文档上获取到的。这里还是提供一张官方的文档截图,如下: 1.png 上面图用红色框起来的可以适当注意下,算是常用的几个。

上图中漏掉了两个常用的bindscrolltoupper、bindscrolltolower

第一种基础用法

这种用法也是最常用的,有两种形式。

定高滚动

给定一个高度,让内容在这个高度内容显示,超出可以滑动显示内容,这里的高度可以是小于页面的高度,也可以刚好是页面的高度。代码如下:

<scroll-view scroll-y="true" class="demo-scroll-block">
    <view>
        <view>这是测试的文字哦</view>
        <view>这是测试的文字哦</view>
        <view>这是测试的文字哦</view>
        <view>这是测试的文字哦</view>
        <view>这是测试的文字哦</view>
        <view>这是测试的文字哦</view>
        <view>这是测试的文字哦</view>
        <view>这是测试的文字哦</view>
        <view>这是测试的文字哦</view>
        <view>这是测试的文字哦</view>
        <view>这是测试的文字哦</view>
        <view>这是测试的文字哦</view>
        <view>这是测试的文字哦</view>
        <view>这是测试的文字哦</view>
    </view>
</scroll-view>

.demo-scroll-block {
    width: 100%;
    height: 200rpx;
}

效果如下: 2.gif

定高下拉更新上拉加载更多

就是在上面的基础上添加上拉加载更多和下拉更新数据的功能。其实就是运用了两个官方的方法而已。

  • bindscrolltoupper:滚动到顶部/左边时触发
  • bindscrolltolower:滚动到底部/右边时触发

这里就不具体介绍了,主要就是用着两个方法滚动到顶部时,请求接口更新数据,滚动到底部时加载下一页数据。

第二种用法:左右滚动导航

第二种用法也是在做小程序的过程中很常见的用法了,直接上代码:

<scroll-view scroll-x="true" class="demo-scroll-nav">
    <view class="nav-wrapper">
        <text class="{{navIndex == index ? 'active':''}}" wx:for="{{navArr}}" wx:key="unique" bindtap="navChange" data-index="{{index}}">{{item}}</text>
    </view>
</scroll-view>

navArr:['指南','框架','组件','API','服务端','工具','云开发','扩展能力','更新日志'],
navIndex:0,

navChange(e){
    this.setData({
        navIndex:e.currentTarget.dataset.index
    })
}

.demo-scroll-nav {
    height: 80rpx;
}

.nav-wrapper {
    height: 100%;
    white-space: nowrap;
}

.nav-wrapper text {
    display: inline-block;
    padding: 0 20px;
    height: 100%;
    line-height: 80rpx;
}

.nav-wrapper text.active {
    color: #ff4400;
}

效果如下: 3.gif

第三种用法:快速定位联系人

这种用法我们在生活中经常见到,比如手机中联系人的界面,有的选择地址或者国家页面都有类似功能。主要用到了scroll-view中的scroll-into-view属性,类似网页中锚点的功能。例子如下:

<scroll-view scroll-y="true" class="demo-scroll-filter" scroll-into-view="{{toView}}">
    <view id="block0">
        <view>A</view>
        <view>阿里</view>
        <view>阿猫</view>
        <view>阿狗</view>
        <view>阿里</view>
        <view>阿猫</view>
        <view>阿狗</view>
        <view>阿里</view>
        <view>阿猫</view>
        <view>阿狗</view>
    </view>
    <view id="block1">
        <view>B</view>
        <view>阿里</view>
        <view>阿猫</view>
        <view>阿狗</view>
        <view>阿里</view>
        <view>阿猫</view>
        <view>阿狗</view>
        <view>阿里</view>
        <view>阿猫</view>
        <view>阿狗</view>
        <view>阿里</view>
        <view>阿猫</view>
        <view>阿狗</view>
        <view>阿里</view>
        <view>阿猫</view>
        <view>阿狗</view>
    </view>
    <view id="block2">
        <view>C</view>
        <view>阿里</view>
        <view>阿猫</view>
        <view>阿狗</view>
        <view>阿里</view>
        <view>阿猫</view>
        <view>阿狗</view>
        <view>阿里</view>
        <view>阿猫</view>
        <view>阿狗</view>
    </view>
    <view id="block3">
        <view>D</view>
        <view>阿里</view>
        <view>阿猫</view>
        <view>阿狗</view>
        <view>阿里</view>
        <view>阿猫</view>
        <view>阿狗</view>
        <view>阿里</view>
        <view>阿猫</view>
        <view>阿狗</view>
    </view>
</scroll-view>
<view class="filter-nav">
    <view bindtap="toViewId" data-index="0">A</view>
    <view bindtap="toViewId" data-index="1">B</view>
    <view bindtap="toViewId" data-index="2">C</view>
    <view bindtap="toViewId" data-index="3">D</view>
</view>

Page({
    data: {
        toView:'block0'
    },
    toViewId(e){
        this.setData({
            toView:'block'+e.currentTarget.dataset.index
        })
    },
 })

.demo-scroll-filter {
    height: 100vh;
}

.filter-nav {
    position: fixed;
    right: 0;
    top: 20rpx;
}

.filter-nav view {
    padding: 40rpx;
    background: #ff4400;
    margin-top: 20rpx;
}

效果如下: 4.gif

第四种用法:结合第二和第三种用法

这种用就是点击顶部导航,下面的页面中内容就滚动到相应的地方去。废话不说了,直接上代码:

<scroll-view scroll-x="true" class="demo-scroll-nav">
    <view class="nav-wrapper">
        <text class="{{navIndex == index ? 'active':''}}" wx:for="{{navArr}}" wx:key="unique" bindtap="navChange" data-index="{{index}}">{{item}}</text>
    </view>
</scroll-view>
<scroll-view scroll-y="true" class="demo-scroll-filter" scroll-into-view="{{toView}}">
    <view id="block{{index}}" wx:for="{{navArr}}" wx:key="unique">
        <view>{{index}}</view>
        <view>阿里</view>
        <view>阿猫</view>
        <view>阿狗</view>
        <view>阿里</view>
        <view>阿猫</view>
        <view>阿狗</view>
        <view>阿里</view>
        <view>阿猫</view>
        <view>阿狗</view>
    </view>
</scroll-view>

Page({
    data: {
        navArr:['指南','框架','组件','API','服务端','工具','云开发','扩展能力','更新日志'],
        navIndex:0,
        toView:'block0'
    },
    navChange(e){
        this.setData({
            navIndex:e.currentTarget.dataset.index,
            toView:'block'+e.currentTarget.dataset.index
        })
    },
})

.demo-scroll-nav {
    height: 80rpx;
}
.nav-wrapper {
    height: 100%;
    white-space: nowrap;
}
.nav-wrapper text {
    display: inline-block;
    padding: 0 20px;
    height: 100%;
    line-height: 80rpx;
}
.nav-wrapper text.active {
    color: #ff4400;
}
.demo-scroll-filter {
    height: calc( 100vh - 80rpx );
}

效果如下: 5.gif

第五种用法:左右联动

这种用法多用于外卖,点餐以及商城项目中。效果如下: 6.gif 这种用法难点在于如何滚动右边联动左边的。上代码:

<view class="main">
    <view class="scroll-nav">
        <view class="{{activeIndex == 0 ? 'active':''}}" bindtap="titleChange" data-index="0">1</view>
        <view class="{{activeIndex == 1 ? 'active':''}}" bindtap="titleChange" data-index="1">2</view>
        <view class="{{activeIndex == 2 ? 'active':''}}" bindtap="titleChange" data-index="2">3</view>
        <view class="{{activeIndex == 3 ? 'active':''}}" bindtap="titleChange" data-index="3">4</view>
        <view class="{{activeIndex == 4 ? 'active':''}}" bindtap="titleChange" data-index="4">5</view>
    </view>
    <view class="scroll-content">
        <scroll-view scroll-y="true" style="height:100%" scroll-into-view="{{toView}}" scroll-with-animation="ture" bindscroll="scroll">
            <view class="content-item" id="content0">1</view>
            <view class="content-item" id="content1">2</view>
            <view class="content-item" id="content2">3</view>
            <view class="content-item" id="content3">4</view>
            <view class="content-item" id="content4">5</view>
        </scroll-view>
    </view>
</view>

let distance = 0
Page({
    data: {
        activeIndex:0,
        heightArr:[],
        toView:'content0'
    },
    onLoad(){
        let query = wx.createSelectorQuery(),self = this
        query.selectAll('.content-item').boundingClientRect((rect)=> {
            rect.forEach(ele => {
                self.calculateHeight(ele.height)
            })
        }).exec();
    },
    titleChange(e){
        this.setData({
            activeIndex:e.currentTarget.dataset.index,
            toView: 'content'+e.currentTarget.dataset.index
        })
    },
    scroll(e){
        if (this.data.heightArr.length == 0) {
            return
        }
        let scrollTop = e.detail.scrollTop
        let current = this.data.activeIndex
        if (scrollTop >= this.distance) { //页面向上滑动
            //如果右侧当前可视区域最底部到顶部的距离 超过 当前列表选中项距顶部的高度(且没有下标越界),则更新左侧选中项
            if (current + 1 < this.data.heightArr.length && scrollTop >= this.data.heightArr[current]) {
                this.setData({
                    activeIndex: current + 1
                })
            }
        } else { //页面向下滑动
            //如果右侧当前可视区域最底部到顶部的距离 小于 当前列表选中的项距顶部的高度,则更新左侧选中项
            if (current - 1 >= 0 && scrollTop < this.data.heightArr[current - 1]) {
                this.setData({
                    activeIndex: current - 1
                })
            }
        }
        //更新到顶部的距离
        this.distance = scrollTop
    },
    // 计算滚动的区间
    calculateHeight(height) {
        if(!this.data.heightArr.length) {
            this.data.heightArr.push(height)
        }else {
            this.data.heightArr.forEach(ele => {
                height += ele
            })
            this.data.heightArr.push(height);
        }
    }
})

.main{
    height: 100vh;
    display: flex;
}

.scroll-nav{
    width: 20%;
}

.scroll-nav view{
    text-align: center;
    padding: 20rpx 0;
}

.scroll-nav view.active{
    background: #ff4400;
}

.scroll-content{
    flex: 1;
}

.content-item{
    height: 600rpx;
}

上面的例子中左边的导航这里是直接用了view,如果这里内容很多也可以使用scroll-view实现,这个就交给大家自己去实现了,我这里只是抛砖引玉哦。

总结

scroll-vew的用法还有很多,目前自己的实际项目中只用这几种方法,如果大家有更多方法,欢迎下面留言探讨哦。