用戶
 找回密碼
 立即注冊

QQ登錄

只需一步,快速開始

掃一掃,登錄網站

小程序社區 首頁 教程 實戰教程 查看內容

小程序監聽滾動時,更優雅的修改頁面樣式

Rolan 2020-7-4 00:08

場景 在項目中有一個需求,監聽頁面滾動,動態修改組件的背景色,之前是在監聽以后,計算顏色,通過 this.setData({ bgColor: newBgColor }) 復制代碼方式修改背景色,但是在快速滾動情況下,會瘋狂修改,一直調用se ...

場景

在項目中有一個需求,監聽頁面滾動,動態修改組件的背景色,之前是在監聽以后,計算顏色,通過

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="./index.wxs"></wxs>
復制代碼
  1. 監聽滾動事件,在里面直接修改元素樣式
<scroll-view scroll-y="true" style="height: 100%;" bindscroll="{{module.handleScroll}}">
復制代碼

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

完整代碼如下:

<!-- index.html -->
<wxs module="module" src="./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;
}

鮮花
鮮花
雞蛋
雞蛋
分享至 : QQ空間
收藏
原作者: LastStartDust 來自: 掘金
快乐十分复式