小程序监听滚动时,更优雅的修改页面样式 - 新闻资讯 - 云南小程序开发|云南软件开发|云南网站建设-昆明葵宇信息科技有限公司

159-8711-8523

云南网建设/小程序开发/软件开发

知识

不管是网站,软件还是小程序,都要直接或间接能为您产生价值,我们在追求其视觉表现的同时,更侧重于功能的便捷,营销的便利,运营的高效,让网站成为营销工具,让软件能切实提升企业内部管理水平和效率。优秀的程序为后期升级提供便捷的支持!

您当前位置>首页 » 新闻资讯 » 小程序相关 >

小程序监听滚动时,更优雅的修改页面样式

发表时间:2021-1-11

发布人:葵宇科技

浏览次数:85

场景

在项目中有一个需求,监听页面滚动,动态修改组件的背景色,之前是在监听以后,计算颜色,通过

this.setData({
    bgColor: newBgColor
})
复制代码

方式修改背景色,但是在快速滚动情况下,会疯狂修改,一直调用setData()方法,性能很糟糕,会出现卡顿情况

核心就是减少setData()方法调用

解决思路

方案1

可以使用函数节流,防止调用太多,减少调用频率

方案2

具体分析,我们只是单纯的修改样式,不涉及逻辑,可以将修改的样式的动作放到渲染层去处理,不在通过逻辑层,直接将setData()次数减低到零

  • 要点
  • 小程序的运行环境分成渲染层和逻辑层
  • 在渲染层,可以监听事件,修改元素的样式

实现

方案1

定义一个函数节流工具

/**
 * @description 函数节流: 每隔一段时间,只执行一次函数
 * @param { Function } fn 需要延迟执行的函数
 * @param { Number } interval 延迟执行的时间,默认值500ms
 */
export function throttle(fn, interval = 500) {
  // 记录定时器id
  let timer = null
  // 是否是第一次调用
  let isFirstTime = true

  return function () {
    const args = arguments
    const _me = this

    // 第一次直接执行,改变标志,无需延迟
    if (isFirstTime) {
      fn.apply(_me, args)
      return (isFirstTime = false)
    }

    // 不是第一次
    // 存在定时器,前面的延迟操作没有完成,直接返回,拒绝调用请求
    if (timer) {
      return false
    }

    // 延迟执行
    timer = setTimeout(() => {
      clearTimeout(timer)
      timer = null
      fn.apply(_me, args)
    }, interval)
  }
}
复制代码

页面中使用节流函数

// index.js
import { throttle } from '../utils/util';

// 创建一个长度100的数组
const list = [...new Array(100).keys()].map(i => {
  return { name: 'lisr' + (i + 1), age: i + 1}
})

Page({
  data: {
    list: list
  },

  onScroll: throttle(function(e) {
    console.log(e)
    const { scrollTop: top } = e.detail
    let channelColor = top * 1 // 任意通道颜色
    if(channelColor > 255) {
      channelColor = channelColor%255
    }
	
	// 样式
    const style = `background-color: rgb(${channelColor}${channelColor},${channelColor});`
    this.setData({
      style  // 设置背景色
    }, () => {
      this.countStatistics()
    })
  }, 300),
  // 调用次数
  count: 0,
  // 更新调用次数和并打印出来
  countStatistics() {
    ++this.count
    console.log(this.count)
  }
})
复制代码

页面结构

<!-- index.html -->
<!-- 一个大盒子包住所有的元素 -->
<view class="container-fill">
    <!-- 包住 swiper 组件 -->
    <view class="scroll-fullpage" style="height: 100%">
        <scroll-view scroll-y="true" style="height: 100%;" bindscroll="onScroll">
            <view class="item" hover-class="none" hover-stop-propagation="false" style="{{style}}" wx:for="{{ list }}" wx:key="index">
                {{item.name}} - {{item.age}}
            </view>
        </scroll-view>
    </view>
</view>
复制代码

页面样式

/* index.wxss */
.container-fill {
  position: fixed;
  top: 0;
  bottom: 0;
  left: 0;
  right: 0;
  overflow: hidden;
  z-index: 10;
}

.container-fill .scroll-fullpage {
  height: 100%;
  transition: all 0.3s;
}

.scroll-fullpage .item {
  height: 30%;
  width: 80%;
  background-color: skyblue;
  border-radius: 10rpx;
  margin: 50rpx auto;
  display: flex;
  justify-content: center;
  align-items: center;
  font-size: 50rpx;
}
复制代码

演示效果 TODO

方案2

定义wxs, 用于修改元素的样式

// 调用次数
var count = 0

function handleScroll(e, ownerInstance) {
  var top = e.detail.scrollTop
  var channelColor = top * 1 // 任意通道颜色
  if (channelColor > 255) {
    channelColor = channelColor % 255
  }
  var instances = ownerInstance.selectAllComponents('.item') // 获取类名为item的组件
  for(var i = 0; i < instances.length; i++) {
    var instance = instances[i]
    instance.setStyle({
      'background-color':
        'rgb(' + channelColor + ',' + channelColor + ',' + channelColor + ')', // 设置背景色
    })
  }
  countStatistics()
}

// 更新调用次数和并打印出来
function countStatistics() {
  ++count
  console.log(count)
}

module.exports = {
  handleScroll: handleScroll
}
复制代码

页面逻辑层代码

// 创建一个长度100的数组
const list = [...new Array(100).keys()].map(i => {
  return { name: 'lisr' + (i + 1), age: i + 1}
})

Page({
  data: {
    list: list
  }
})
复制代码

页面渲染层

  1. 需要引入写好的wxs模块
<wxs module="module" src=http://www.wxapp-union.com/"./index.wxs"></wxs>
复制代码
  1. 监听滚动事件,在里面直接修改元素样式
<scroll-view scroll-y="true" style="height: 100%;" bindscroll="{{module.handleScroll}}">
复制代码

注意引入模块使用{{}}包裹

完整代码如下:

<!-- index.html -->
<wxs module="module" src=http://www.wxapp-union.com/"./index.wxs"></wxs>

<!-- 一个大盒子包住所有的元素 -->
<view class="container-fill">
    <!-- 包住 swiper 组件 -->
    <view class="scroll-fullpage" style="height: 100%">
        <scroll-view scroll-y="true" style="height: 100%;" bindscroll="{{module.handleScroll}}">
            <view class="item" hover-class="none" hover-stop-propagation="false" style="{{style}}" wx:for="{{ list }}" wx:key="index">
                {{item.name}} - {{item.age}}
            </view>
        </scroll-view>
    </view>
</view>

复制代码

页面样式

/* index.wxss */
.container-fill {
  position: fixed;
  top: 0;
  bottom: 0;
  left: 0;
  right: 0;
  overflow: hidden;
  z-index: 10;
}

.container-fill .scroll-fullpage {
  height: 100%;
  transition: all 0.3s;
}

.scroll-fullpage .item {
  height: 30%;
  width: 80%;
  background-color: skyblue;
  border-radius: 10rpx;
  margin: 50rpx auto;
  display: flex;
  justify-content: center;
  align-items: center;
  font-size: 50rpx;
}

相关案例查看更多