uni-app微信小程序性能優(yōu)化技巧 | 13個(gè)實(shí)用方法

2024-12-18 11:09 更新

大家好,我是威哥,在使用uni-app開發(fā)微信小程序時(shí),性能優(yōu)化是提升用戶體驗(yàn)的關(guān)鍵。今天的內(nèi)容,整理了以下13個(gè)有效的性能優(yōu)化技巧,供你在開發(fā)中參考:

1. 減少頁(yè)面層級(jí)和組件嵌套:

減少頁(yè)面層級(jí)和組件嵌套是前端性能優(yōu)化中的常見做法,它有助于減少瀏覽器的渲染負(fù)擔(dān),提高頁(yè)面的響應(yīng)速度。我們通過(guò)以下優(yōu)化前后的示例對(duì)比來(lái)說(shuō)明:

優(yōu)化前:

假設(shè)我們有一個(gè)電商應(yīng)用的商品詳情頁(yè),頁(yè)面結(jié)構(gòu)如下:

<view class="product-detail">
  <view class="product-header">
    <view class="product-title">一條瑜伽褲</view>
    <view class="product-price">¥199</view>
  </view>
  <view class="product-body">
    <view class="product-image">
      <image src="path/to/img-ku"></image>
    </view>
    <view class="product-info">
      <view class="info-item">
        <text>品牌:</text>
        <text>VG牌</text>
      </view>
      <view class="info-item">
        <text>產(chǎn)地:</text>
        <text>東莞</text>
      </view>
      <!-- 更多 info-item -->
    </view>
  </view>
  <view class="product-footer">
    <button class="buy-button">購(gòu)買</button>
  </view>
</view>

在這個(gè)例子中,product-detail 下有三個(gè)直接子元素:product-header、product-bodyproduct-footer。product-body 下又嵌套了 product-imageproduct-info,而 product-info 下還有多個(gè) info-item。

優(yōu)化后:

我們可以將一些不需要單獨(dú)樣式或行為的子元素合并到父元素中,以減少層級(jí):

<view class="product-detail">
  <view class="product-header">
    <text class="product-title">一條瑜伽褲</text>
    <text class="product-price">¥199</text>
  </view>
  <image class="product-image" src="path/to/image"></image>
  <view class="product-info">
    <view class="info-item">
      <text>品牌:</text>
      <text>VG牌</text>
    </view>
    <view class="info-item">
      <text>產(chǎn)地:</text>
      <text>東莞</text>
    </view>
    <!-- 更多 info-item -->
  </view>
  <button class="product-footer buy-button">購(gòu)買</button>
</view>

在這個(gè)優(yōu)化后的示例中,我們做了以下改動(dòng):

  1. product-titleproduct-price 直接作為 product-header 的子元素,而不是嵌套在另一個(gè) <view> 中。
  2. product-image 不再需要嵌套在 product-body 中,可以直接作為 product-detail 的子元素。
  3. buy-button 合并到 product-footer 中,并移除了 product-footer 的嵌套。

優(yōu)化說(shuō)明:

  • 減少DOM元素?cái)?shù)量:優(yōu)化后的代碼減少了不必要的 <view> 元素,這減少了DOM樹的深度,使得瀏覽器渲染成本降低。
  • 簡(jiǎn)化結(jié)構(gòu):簡(jiǎn)化的頁(yè)面結(jié)構(gòu)使得維護(hù)和理解代碼變得更加容易。
  • 提高性能:較少的DOM操作和更少的重排重繪,可以提高頁(yè)面的響應(yīng)速度和流暢度。

通過(guò)這樣的優(yōu)化,我們能夠提升頁(yè)面的性能,使得用戶在使用小程序時(shí)能夠獲得更好的體驗(yàn)。

2. 避免頻繁的數(shù)據(jù)更新:

避免頻繁的數(shù)據(jù)更新是提升性能的一個(gè)重要方面,特別是在數(shù)據(jù)綁定頻繁更新時(shí),可能會(huì)導(dǎo)致頁(yè)面渲染性能問(wèn)題。以下是優(yōu)化前后的示例對(duì)比說(shuō)明,我們來(lái)看一下:

優(yōu)化前:

假設(shè)我們有一個(gè)商品列表頁(yè)面,每個(gè)商品項(xiàng)都有一個(gè)“加入購(gòu)物車”的按鈕,點(diǎn)擊后商品數(shù)量會(huì)增加。我們可能會(huì)這樣編寫代碼:

<template>
  <view class="product-list">
    <view v-for="(product, index) in products" :key="index" class="product-item">
      <text class="product-name">{{ product.name }}</text>
      <text class="product-quantity">{{ product.quantity }}</text>
      <button @click="addToCart(product)">加入購(gòu)物車</button>
    </view>
  </view>
</template>


<script>
export default {
  data() {
    return {
      products: [
        { name: '商品1-瑜伽褲', quantity: 0 },
        { name: '商品2-瑜伽衣', quantity: 0 },
        // 更多商品
      ]
    };
  },
  methods: {
    addToCart(product) {
      product.quantity += 1;
    }
  }
};
</script>

在這個(gè)例子中,每次點(diǎn)擊“加入購(gòu)物車”按鈕,都會(huì)觸發(fā) addToCart 方法,該方法直接修改了 product.quantity 的值,導(dǎo)致視圖重新渲染。

優(yōu)化后:

我們可以優(yōu)化數(shù)據(jù)更新的方式,減少不必要的數(shù)據(jù)綁定和視圖渲染:

<template>
  <view class="product-list">
    <view v-for="(product, index) in products" :key="index" class="product-item">
      <text class="product-name">{{ product.name }}</text>
      <text class="product-quantity">{{ product.quantity }}</text>
      <button @click="addToCart(index)">加入購(gòu)物車</button>
    </view>
  </view>
</template>


<script>
export default {
  data() {
    return {
      products: [
        { name: '商品1-瑜伽褲', quantity: 0 },
        { name: '商品2-瑜伽衣', quantity: 0 },
        // 更多商品
      ]
    };
  },
  methods: {
    addToCart(index) {
      this.products[index].quantity += 1;
    },
    updateQuantity(product) {
      this.$set(this.products, product.index, { ...product });
    }
  }
};
</script>

在這個(gè)優(yōu)化后的示例中,我們做了以下改動(dòng):

  1. addToCart 方法現(xiàn)在接收商品的索引而不是商品對(duì)象本身。
  2. 添加了一個(gè)新的 updateQuantity 方法,用于更新商品數(shù)量,并觸發(fā)視圖更新。

優(yōu)化說(shuō)明:

  • 減少數(shù)據(jù)綁定:通過(guò)避免直接在事件處理函數(shù)中修改數(shù)據(jù),我們可以減少數(shù)據(jù)綁定的更新次數(shù)。
  • 使用 $set 方法:Vue 提供了 $set 方法來(lái)確保對(duì)象屬性的添加和刪除能夠觸發(fā)視圖更新。在這個(gè)例子中,我們可以使用 $set 來(lái)更新商品數(shù)量,而不是直接修改 product.quantity
  • 避免不必要的渲染:通過(guò)減少數(shù)據(jù)更新的次數(shù),我們可以避免不必要的視圖渲染,從而提高性能。

通過(guò)這樣的優(yōu)化,我們可以減少數(shù)據(jù)更新對(duì)性能的影響,使得頁(yè)面響應(yīng)更加迅速,提升用戶體驗(yàn)。

3. 使用小程序自帶組件:

在微信小程序開發(fā)中,使用小程序自帶組件而不是自定義組件可以顯著提升性能。這是因?yàn)樽詭ЫM件經(jīng)過(guò)了微信團(tuán)隊(duì)的優(yōu)化,能夠更高效地渲染和更新。以下是優(yōu)化前后的代碼示例對(duì)比,來(lái)看一下:

優(yōu)化前:

假設(shè)我們正在開發(fā)一個(gè)商品列表頁(yè),可能會(huì)使用自定義的<custom-list-item>組件來(lái)展示每個(gè)商品項(xiàng):

<!-- 在頁(yè)面 wxml 中使用自定義組件 -->
<view class="product-list">
  <custom-list-item wx:for="{{products}}" wx:key="id" product="{{item}}"></custom-list-item>
</view>

自定義組件<custom-list-item>可能包含復(fù)雜的結(jié)構(gòu)和樣式,增加了渲染的負(fù)擔(dān)。

優(yōu)化后:

我們改用微信小程序提供的<view><text>等基礎(chǔ)組件來(lái)實(shí)現(xiàn)同樣的功能:

<!-- 在頁(yè)面 wxml 中使用小程序基礎(chǔ)組件 -->
<view class="product-list">
  <view wx:for="{{products}}" wx:key="id" class="product-item">
    <text class="product-name">{{item.name}}</text>
    <text class="product-price">{{item.price}}</text>
  </view>
</view>

在這個(gè)優(yōu)化后的示例中,我們直接使用<view><text>標(biāo)簽來(lái)展示商品信息,減少了自定義組件的使用,從而降低了頁(yè)面的渲染時(shí)間。

優(yōu)化說(shuō)明:

  • 減少組件嵌套:使用基礎(chǔ)組件代替自定義組件,減少了組件嵌套的層級(jí),簡(jiǎn)化了DOM樹。
  • 提高渲染效率:基礎(chǔ)組件由于其簡(jiǎn)單性,能夠更快地被渲染,特別是在列表渲染等高頻更新的場(chǎng)景中。
  • 降低內(nèi)存占用:自定義組件可能會(huì)包含額外的邏輯和樣式,這會(huì)增加內(nèi)存的占用。使用基礎(chǔ)組件可以減少不必要的內(nèi)存使用。

通過(guò)這樣的優(yōu)化,是不是提升小程序的渲染性能了呢,使得頁(yè)面滑動(dòng)更加流暢,提升用戶體驗(yàn)。

4. 優(yōu)化圖片資源:

優(yōu)化圖片資源是提升小程序性能的重要手段,尤其是在移動(dòng)網(wǎng)絡(luò)環(huán)境下,合理的圖片優(yōu)化可以顯著減少加載時(shí)間,提升用戶體驗(yàn)。以下是優(yōu)化前后的代碼示例對(duì)比:

優(yōu)化前:

在小程序中,我們可能會(huì)直接使用較大的圖片資源,沒有進(jìn)行任何優(yōu)化:

<!-- 在 wxml 中直接使用大圖 -->
<image src="path/to/large-image.jpg" class="product-image"></image>

如果這里的large-image.jpg是一個(gè)高分辨率的圖片,加載時(shí)間較長(zhǎng),就會(huì)影響用戶體驗(yàn)。

優(yōu)化后:

我們可以采取以下措施進(jìn)行優(yōu)化:

  1. 圖片壓縮:使用工具壓縮圖片,減少文件大小。
  2. 圖片懶加載:僅在圖片即將進(jìn)入視口時(shí)才開始加載。
  3. 使用合適的圖片格式:如WebP格式,它通常比JPEG或PNG格式的文件更小。
  4. 使用CDN托管:將圖片資源托管在內(nèi)容分發(fā)網(wǎng)絡(luò)(CDN)上,加快加載速度。

優(yōu)化后的代碼可能如下:

<!-- 在 wxml 中使用優(yōu)化后的圖片 -->
<image src="https://cdn.example.com/optimized-image.jpg" rel="external nofollow"  class="product-image"></image>

在小程序的app.json或頁(yè)面的.json配置文件中,可以配置圖片的懶加載:

{
  "lazyLoad": true
}

優(yōu)化說(shuō)明:

  • 通過(guò)壓縮工具減小圖片文件的大小,而不損失太多視覺質(zhì)量。
  • 通過(guò)延遲非視口內(nèi)圖片的加載,減少初次頁(yè)面加載的數(shù)據(jù)量,提升首屏加載速度。
  • 利用CDN的分布式服務(wù)器,用戶可以從距離自己最近的服務(wù)器獲取資源,加快加載速度。
  • WebP等現(xiàn)代圖片格式在保持相同質(zhì)量的前提下,文件大小通常更小。

通過(guò)這樣的優(yōu)化,可以減少圖片資源對(duì)小程序性能的影響,提高頁(yè)面的加載速度和用戶體驗(yàn)。

5. 分頁(yè)加載大量數(shù)據(jù):

在微信小程序中,處理大量數(shù)據(jù)時(shí),分頁(yè)加載是一種常見的優(yōu)化手段。以下是優(yōu)化前后的代碼示例對(duì)比:

優(yōu)化前:

在沒有進(jìn)行分頁(yè)處理的情況下,可能會(huì)一次性加載所有數(shù)據(jù),這會(huì)導(dǎo)致加載緩慢,用戶體驗(yàn)差:

// 假設(shè)有一個(gè)獲取所有數(shù)據(jù)的方法
getData() {
  wx.request({
    url: 'https://api.vg.com/data',
    success: (res) => {
      this.setData({
        items: res.data
      });
    }
  });
}

這種方法會(huì)一次性請(qǐng)求所有數(shù)據(jù),如果數(shù)據(jù)量大,會(huì)導(dǎo)致頁(yè)面響應(yīng)慢。

優(yōu)化后:

采用分頁(yè)加載,每次只加載一部分?jǐn)?shù)據(jù),用戶可以觸發(fā)加載更多或者上拉加載更多:

// 頁(yè)面數(shù)據(jù)
data: {
  items: [], // 當(dāng)前頁(yè)面的數(shù)據(jù)列表
  currentPage: 1, // 當(dāng)前頁(yè)碼
  pageSize: 10, // 每頁(yè)顯示的條數(shù)
  hasMore: true // 是否還有更多數(shù)據(jù)
},


// 加載數(shù)據(jù)的方法
loadData() {
  if (!this.data.hasMore) {
    return; // 如果沒有更多數(shù)據(jù),則不執(zhí)行加載
  }
  wx.request({
    url: 'https://api.vg.com/data',
    data: {
      page: this.data.currentPage,
      pageSize: this.data.pageSize
    },
    success: (res) => {
      let newItems = this.data.items.concat(res.data); // 將新數(shù)據(jù)追加到舊數(shù)據(jù)后面
      this.setData({
        items: newItems,
        currentPage: this.data.currentPage + 1
      });
      if (res.data.length < this.data.pageSize) {
        this.setData({
          hasMore: false // 如果返回的數(shù)據(jù)少于pageSize,說(shuō)明沒有更多數(shù)據(jù)了
        });
      }
    }
  });
},


// 上拉觸底加載更多
onReachBottom() {
  this.loadData();
},


// 頁(yè)面加載時(shí)觸發(fā)
onLoad() {
  this.loadData();
}

在這個(gè)優(yōu)化后的示例中,我們通過(guò)currentPagepageSize控制每次請(qǐng)求的數(shù)據(jù)量,并且只有當(dāng)用戶滾動(dòng)到頁(yè)面底部時(shí)才會(huì)觸發(fā)onReachBottom事件,加載更多數(shù)據(jù)。

優(yōu)化說(shuō)明:

  • 分頁(yè)加載可以減少單次請(qǐng)求的數(shù)據(jù)量,避免一次性加載大量數(shù)據(jù)導(dǎo)致的性能問(wèn)題。
  • 用戶可以更快地看到首批數(shù)據(jù),提升用戶體驗(yàn)。
  • 服務(wù)器和客戶端都不需要一次性處理大量數(shù)據(jù),節(jié)省了資源消耗。

通過(guò)分頁(yè)加載,我們可以有效地提升小程序處理大量數(shù)據(jù)時(shí)的性能,使得用戶體驗(yàn)更加流暢。

6. 異步處理復(fù)雜操作:

在微信小程序中,異步處理復(fù)雜操作是一種常見的優(yōu)化手段,特別是在處理數(shù)據(jù)加載、網(wǎng)絡(luò)請(qǐng)求或計(jì)算密集型任務(wù)時(shí)。以下是優(yōu)化前后的代碼示例對(duì)比:

優(yōu)化前:

在沒有進(jìn)行異步處理的情況下,可能會(huì)直接在主線程中執(zhí)行復(fù)雜操作,這會(huì)導(dǎo)致界面卡頓,舉個(gè)栗子:

// 假設(shè)有一個(gè)計(jì)算密集型的操作
calculateData() {
  let result = 0;
  for (let i = 0; i < 10000000; i++) {
    result += Math.sqrt(i);
  }
  this.setData({
    calculationResult: result
  });
}

在這個(gè)示例中,計(jì)算操作直接在主線程中執(zhí)行,如果計(jì)算量很大,會(huì)導(dǎo)致界面無(wú)法響應(yīng)用戶操作。

優(yōu)化后:

我們使用 setTimeout 或者微信小程序提供的 worker 線程來(lái)異步處理復(fù)雜操作,避免阻塞主線程:

// 使用 setTimeout 異步處理
calculateData() {
  setTimeout(() => {
    let result = 0;
    for (let i = 0; i < 10000000; i++) {
      result += Math.sqrt(i);
    }
    this.setData({
      calculationResult: result
    });
  }, 0);
}


// 或者使用 worker 線程異步處理(需要在 app.json 中開啟 worker)
// 在 js 文件中創(chuàng)建 worker
if (wx.canIUse('worker')) {
  const worker = new Worker();
  worker.onMessage((message) => {
    this.setData({
      calculationResult: message.data
    });
  });
  worker.postMessage('start');

  
  // 監(jiān)聽 worker 線程的消息
  worker.onMessage(function (event) {
    this.setData({
      calculationResult: event.data
    });
  });


  // 處理 worker 線程發(fā)送的數(shù)據(jù)
  worker.postMessage('Hello Worker');
}

在這個(gè)優(yōu)化后的示例中,我們通過(guò) setTimeout 將計(jì)算操作放在異步隊(duì)列中執(zhí)行,或者使用 worker 線程來(lái)處理,這樣主線程仍然可以響應(yīng)用戶操作,提升用戶體驗(yàn)。

優(yōu)化說(shuō)明:

  • 通過(guò)異步處理,避免了復(fù)雜操作阻塞主線程,使得界面可以保持流暢。
  • 用戶操作可以得到及時(shí)響應(yīng),不會(huì)因?yàn)楹笈_(tái)操作而等待。
  • 用戶在使用小程序時(shí),不會(huì)因?yàn)殚L(zhǎng)時(shí)間的計(jì)算操作而感到卡頓或延遲。

這樣是不是可以讓用戶體驗(yàn)更加贊呢。

7. 優(yōu)化啟動(dòng)速度:

在uni-app中,優(yōu)化啟動(dòng)速度是提升用戶體驗(yàn)的重要方面。以下是一些優(yōu)化啟動(dòng)速度的示例和方法:

優(yōu)化前(未進(jìn)行啟動(dòng)速度優(yōu)化):

// 在App.vue中全局引入大量樣式和腳本
import Vue from 'vue'
import App from './App'


// 全局樣式
import './styles/global.scss'
// 全局插件
import './plugins/global-plugin'


Vue.config.productionTip = false


App.mpType = 'app'


const app = new Vue({
    ...App
})
app.$mount()

在這種情況下,應(yīng)用在啟動(dòng)時(shí)會(huì)加載所有全局樣式和插件,這可能會(huì)導(dǎo)致啟動(dòng)速度變慢。

優(yōu)化后(進(jìn)行啟動(dòng)速度優(yōu)化):

// 在App.vue中按需引入資源
import Vue from 'vue'
import App from './App'


// 僅引入必要的全局樣式
import './styles/essential.scss'


Vue.config.productionTip = false


App.mpType = 'app'


const app = new Vue({
    ...App
})
app.$mount()

在優(yōu)化后的示例中,我們只引入了必要的全局樣式,減少了不必要的資源加載,從而加快了啟動(dòng)速度。

優(yōu)化說(shuō)明:

  • 只加載應(yīng)用啟動(dòng)時(shí)真正需要的資源,減少不必要的資源加載。
  • 使用Webpack等構(gòu)建工具進(jìn)行代碼分割,將代碼拆分成多個(gè)小塊,按需加載。
  • 利用uni-app的分包加載功能,將應(yīng)用分割成多個(gè)子包,減少主包體積。
  • 對(duì)資源進(jìn)行優(yōu)先級(jí)排序,確保關(guān)鍵資源優(yōu)先加載。
  • 合理利用緩存,減少重復(fù)加載資源的次數(shù)。

在Webpack中,代碼分割(Code Splitting)是一種常用的優(yōu)化手段,它允許將代碼分離成不同的包(bundles),然后可以按需加載或并行加載這些文件。這不僅可以使應(yīng)用的初始加載更快,還可以控制資源加載的優(yōu)先級(jí),從而顯著減少加載時(shí)間。以下是一些代碼分割的示例和優(yōu)化方法:

優(yōu)化前(未進(jìn)行代碼分割):

假設(shè)你有一個(gè)應(yīng)用,其中包含了多個(gè)模塊,這些模塊都打包到一個(gè)主bundle中:

// main.js
import moduleA from './moduleA';
import moduleB from './moduleB';


function init() {
  // 初始化代碼
  moduleA.doSomething();
  moduleB.doSomething();
}
init();

在這種情況下,所有模塊都在初始加載時(shí)被加載,即使某些模塊可能稍后才會(huì)用到或根本不會(huì)用到。

優(yōu)化后(使用動(dòng)態(tài)導(dǎo)入進(jìn)行代碼分割):

使用Webpack的動(dòng)態(tài)導(dǎo)入功能,可以將模塊分割成不同的chunks,并在需要時(shí)加載:

// main.js
function init() {
  // 初始化代碼
  import('./moduleA').then(moduleA => {
    moduleA.default.doSomething();
  });


  // 假設(shè)moduleB只有在用戶點(diǎn)擊按鈕后才需要加載
  document.getElementById('loadButton').addEventListener('click', () => {
    import('./moduleB').then(moduleB => {
      moduleB.default.doSomething();
    });
  });
}
init();

在這個(gè)優(yōu)化后的示例中,moduleA 在應(yīng)用啟動(dòng)時(shí)加載,而 moduleB 則在用戶點(diǎn)擊按鈕時(shí)才加載。這樣可以減少應(yīng)用的初始加載時(shí)間,并在需要時(shí)才加載額外的代碼。

優(yōu)化說(shuō)明:

  • 通過(guò)使用 import() 語(yǔ)法,Webpack會(huì)將導(dǎo)入的模塊分割成單獨(dú)的chunk,并在運(yùn)行時(shí)按需加載。
  • 只加載應(yīng)用啟動(dòng)時(shí)真正需要的代碼,從而減少初始加載的大小。
  • 根據(jù)用戶的行為或應(yīng)用的狀態(tài)來(lái)加載代碼,這樣可以提高性能并減少不必要的資源加載。

8. 使用nvue代替vue:

在uni-app中,使用nvue代替vue可以顯著提升頁(yè)面性能,尤其是在App端。以下是優(yōu)化前后的代碼示例對(duì)比:

優(yōu)化前(使用vue頁(yè)面):

<template>
  <view class="container">
    <view v-for="(item, index) in list" :key="index" class="item">
      <text>{{ item.text }}</text>
    </view>
  </view>
</template>


<script>
export default {
  data() {
    return {
      list: [{ text: '短褲' }, { text: '長(zhǎng)褲' }, ...]
    };
  }
};
</script>


<style>
.container {
  display: flex;
  flex-direction: column;
}
.item {
  margin-bottom: 10px;
}
</style>

在這個(gè)例子中,我們使用了vue頁(yè)面來(lái)渲染一個(gè)列表,每個(gè)列表項(xiàng)都是一個(gè)簡(jiǎn)單的文本。

優(yōu)化后(使用nvue頁(yè)面):

<template>
  <view class="container">
    <view v-for="(item, index) in list" :key="index" class="item">
      <text>{{ item.text }}</text>
    </view>
  </view>
</template>


<script>
export default {
  data() {
    return {
      list: [{ text: '短褲' }, { text: '長(zhǎng)褲' }, ...]
    };
  }
};
</script>


<style>
.container {
  display: flex;
  flex-direction: column;
}
.item {
  margin-bottom: 10px;
}
</style>

在nvue頁(yè)面中,代碼結(jié)構(gòu)與vue頁(yè)面相似,但是渲染引擎不同。nvue頁(yè)面使用原生渲染引擎,可以提供更好的性能和流暢性。

優(yōu)化說(shuō)明:

  • nvue頁(yè)面基于weex定制的原生渲染引擎,可以實(shí)現(xiàn)頁(yè)面原生渲染,提高頁(yè)面流暢性。這對(duì)于滾動(dòng)列表和動(dòng)畫效果較多的頁(yè)面尤其有效。
  • nvue頁(yè)面減少了邏輯層和視圖層之間的通信損耗,從而減少了資源消耗。
  • 對(duì)于需要高性能滾動(dòng)列表、復(fù)雜動(dòng)畫或者原生控件覆蓋的場(chǎng)景,使用nvue是更好的選擇。

需要注意的是,nvue頁(yè)面的CSS支持有限,因此可能需要對(duì)樣式進(jìn)行一些調(diào)整。

9. 避免使用大圖:

在uni-app開發(fā)中,避免使用大圖是優(yōu)化性能的重要措施之一。以下是優(yōu)化前后的代碼示例對(duì)比:

優(yōu)化前(使用大圖):

<template>
  <view>
    <image src="path/to/large-image.jpg" class="large-image"></image>
  </view>
</template>


<style>
.large-image {
  width: 100%;
  height: auto;
}
</style>

在這個(gè)例子中,我們直接在頁(yè)面中使用了一張大圖,這可能會(huì)導(dǎo)致頁(yè)面加載緩慢,增加內(nèi)存消耗。

優(yōu)化后(使用壓縮后的圖片或適當(dāng)尺寸的圖片):

<template>
  <view>
    <image src="path/to/compressed-image.jpg" class="optimized-image"></image>
  </view>
</template>


<style>
.optimized-image {
  width: 100%;
  height: auto;
}
</style>

在優(yōu)化后的示例中,我們使用了壓縮后的圖片或適當(dāng)尺寸的圖片來(lái)替代原始的大圖。這可以通過(guò)使用圖片壓縮工具如TinyPNG或在線圖片壓縮工具來(lái)實(shí)現(xiàn)。

10. 優(yōu)化數(shù)據(jù)更新:

uni-app 中,定義在 data 里面的數(shù)據(jù)每次變化時(shí)都會(huì)通知視圖層重新渲染頁(yè)面。所以如果不是視圖所需要的變量,可以不定義在 data 中,以避免造成資源浪費(fèi)。優(yōu)化數(shù)據(jù)更新是一個(gè)關(guān)鍵的步驟,以提高應(yīng)用的性能和用戶體驗(yàn)。以下是優(yōu)化前后的代碼示例對(duì)比:

優(yōu)化前(頻繁更新整個(gè)頁(yè)面數(shù)據(jù)):

export default {
  data() {
    return {
      items: [一些敏感數(shù)據(jù),你需要自己模擬一下哦], // 存儲(chǔ)列表數(shù)據(jù)
      otherData: {其它數(shù)據(jù)} // 其他不相關(guān)數(shù)據(jù)
    };
  },
  methods: {
    fetchData() {
      // 假設(shè)這個(gè)方法從服務(wù)器獲取數(shù)據(jù)
      this.items = response.data.items;
      this.otherData = response.data.otherData;
    }
  }
}

在這個(gè)例子中,每次調(diào)用fetchData方法時(shí),都會(huì)更新整個(gè)頁(yè)面的數(shù)據(jù),包括列表數(shù)據(jù)和其他不相關(guān)的數(shù)據(jù)。這可能導(dǎo)致不必要的渲染和性能損耗。

優(yōu)化后(僅更新必要的數(shù)據(jù)):

export default {
  data() {
    return {
      items: [一些敏感數(shù)據(jù),你需要自己模擬一下哦] // 僅存儲(chǔ)列表數(shù)據(jù)
    };
  },
  methods: {
    fetchItems() {
      // 只更新列表數(shù)據(jù),不更新其他不相關(guān)的數(shù)據(jù)
      this.items = response.data.items;
    }
  }
}

在優(yōu)化后的示例中,我們只更新了視圖真正需要的數(shù)據(jù),即列表數(shù)據(jù)items,而沒有更新其他不相關(guān)的數(shù)據(jù)。這樣可以減少不必要的數(shù)據(jù)綁定更新,提高性能。

優(yōu)化說(shuō)明:

  • 不是所有數(shù)據(jù)變化都需要反映到視圖上,有時(shí)候只需要更新部分?jǐn)?shù)據(jù)。

11. 長(zhǎng)列表優(yōu)化:

長(zhǎng)列表中如果每個(gè) item 有一個(gè)點(diǎn)贊按鈕,點(diǎn)擊后點(diǎn)贊數(shù)字+1,此時(shí)點(diǎn)贊組件必須是一個(gè)單獨(dú)引用的組件,才能做到差量數(shù)據(jù)更新。否則會(huì)造成整個(gè)列表數(shù)據(jù)重載。

優(yōu)化前(使用普通循環(huán)渲染):

<template>
  <scroll-view scroll-y="true" class="scroll-view">
    <view v-for="(item, index) in longList" :key="index">
      {{ item.content }}
    </view>
  </scroll-view>
</template>


<script>
export default {
  data() {
    return {
      longList: Array(1000).fill().map((_, index) => ({ content: `Item ${index + 1}` }))
    };
  }
};
</script>


<style>
.scroll-view {
  height: 100%;
}
</style>

在這個(gè)例子中,我們使用了一個(gè)scroll-view組件來(lái)渲染一個(gè)長(zhǎng)列表,列表中的每個(gè)項(xiàng)都是通過(guò)v-for指令循環(huán)生成的。當(dāng)列表項(xiàng)非常多時(shí),這種渲染方式會(huì)導(dǎo)致性能問(wèn)題,因?yàn)樗械牧斜眄?xiàng)都會(huì)被渲染,即使它們不在屏幕內(nèi)。

優(yōu)化后(使用<list>組件):

<template>
  <list class="list">
    <cell v-for="(item, index) in longList" :key="index">
      {{ item.content }}
    </cell>
  </list>
</template>


<script>
export default {
  data() {
    return {
      longList: Array(1000).fill().map((_, index) => ({ content: `Item ${index + 1}` }))
    };
  }
};
</script>


<style>
.list {
  height: 100%;
}
</style>

在優(yōu)化后的示例中,我們使用了<list>組件來(lái)渲染長(zhǎng)列表。<list>組件是專門為長(zhǎng)列表優(yōu)化的,它會(huì)自動(dòng)回收不在屏幕內(nèi)的列表項(xiàng)的渲染資源,從而提高性能和流暢度。這種方式特別適合App端的nvue頁(yè)面,因?yàn)樗褂昧嗽匿秩緳C(jī)制 。

優(yōu)化說(shuō)明:

  • 通過(guò)使用<list>組件,只有用戶可見區(qū)域內(nèi)的列表項(xiàng)會(huì)被渲染,從而減少了不必要的渲染和內(nèi)存消耗。
  • <list>組件的滾動(dòng)性能通常優(yōu)于<scroll-view>,因?yàn)樗鼘iT為長(zhǎng)列表優(yōu)化,能夠提供更流暢的滾動(dòng)體驗(yàn)。
  • 通過(guò)回收不在屏幕內(nèi)的列表項(xiàng)資源,<list>組件減少了內(nèi)存的使用,避免了因渲染大量列表項(xiàng)而導(dǎo)致的內(nèi)存溢出問(wèn)題。

12. 優(yōu)化頁(yè)面切換動(dòng)畫:

頁(yè)面初始化時(shí)若存在大量圖片或原生組件渲染和大量數(shù)據(jù)通訊,會(huì)發(fā)生新頁(yè)面渲染和窗體進(jìn)入動(dòng)畫搶資源,造成頁(yè)面切換卡頓、掉幀。我們可以延時(shí)渲染圖片或復(fù)雜原生組件,分批進(jìn)行數(shù)據(jù)加載。

優(yōu)化前(無(wú)動(dòng)畫或簡(jiǎn)單動(dòng)畫):

<template>
  <view @click="goToNextPage">
    點(diǎn)擊前往下一頁(yè)
  </view>
</template>


<script>
export default {
  methods: {
    goToNextPage() {
      uni.navigateTo({
        url: 'path/to/next/page'
      });
    }
  }
}
</script>

這個(gè)示例中頁(yè)面切換時(shí)沒有特別的動(dòng)畫效果,或者只使用了簡(jiǎn)單的淡入淡出效果。

優(yōu)化后(自定義動(dòng)畫效果):

<template>
  <view @click="goToNextPage">
    點(diǎn)擊前往下一頁(yè)
  </view>
</template>


<script>
export default {
  methods: {
    goToNextPage() {
      const animation = uni.createAnimation({
        duration: 300, // 動(dòng)畫持續(xù)時(shí)間
        timingFunction: 'ease-in-out', // 動(dòng)畫的效果
      });
      animation.scale(0.95, 0.95).rotate(15).step(); // 縮小并旋轉(zhuǎn)
      this.setData({
        animationData: animation.export(),
      });
      uni.navigateTo({
        url: 'path/to/next/page',
        animationType: 'pop-in', // 使用系統(tǒng)動(dòng)畫
        animationDuration: 300, // 動(dòng)畫持續(xù)時(shí)間,與上面保持一致
      });
    }
  }
}
</script>


<style>
/* 可以在這里定義動(dòng)畫樣式 */
</style>

在優(yōu)化后的示例中,我們使用了uni.createAnimation來(lái)創(chuàng)建一個(gè)自定義的動(dòng)畫效果,使得點(diǎn)擊時(shí)有一個(gè)縮小并旋轉(zhuǎn)的動(dòng)畫,然后頁(yè)面切換時(shí)使用了系統(tǒng)的pop-in動(dòng)畫效果。

優(yōu)化說(shuō)明:

  • 通過(guò)uni.createAnimation可以創(chuàng)建復(fù)雜的動(dòng)畫效果,使頁(yè)面切換更加生動(dòng)有趣。
  • uni.navigateTouni.redirectTo等頁(yè)面跳轉(zhuǎn)方法中,可以指定系統(tǒng)提供的動(dòng)畫效果,如pop-inpop-out等。
  • 保持自定義動(dòng)畫和系統(tǒng)動(dòng)畫的持續(xù)時(shí)間一致,以確保動(dòng)畫效果的流暢性。
  • 在頁(yè)面初始化時(shí),如果有大量圖片或原生組件渲染和大量數(shù)據(jù)通訊,可能會(huì)與頁(yè)面進(jìn)入動(dòng)畫搶資源,造成卡頓或掉幀。建議延時(shí)渲染圖片或復(fù)雜原生組件,分批進(jìn)行數(shù)據(jù)通信,以減少一次性渲染的節(jié)點(diǎn)數(shù)量。

13. 優(yōu)化樣式渲染速度:

如果頁(yè)面背景是深色,在vue頁(yè)面中可能會(huì)發(fā)生新窗體剛開始動(dòng)畫時(shí)是灰白色背景,動(dòng)畫結(jié)束時(shí)才變?yōu)樯钌尘?,造成閃屏。此時(shí)需將樣式寫在 App.vue 里,可以加速頁(yè)面樣式渲染速度。

優(yōu)化前(使用大量DOM和復(fù)雜的CSS):

<template>
  <view class="container">
    <view v-for="(item, index) in items" :key="index" class="item">
      <text class="text">{{ item.text }}</text>
    </view>
  </view>
</template>


<style>
.container {
  background-image: url('path/to/large-background-image.jpg');
}
.item {
  background-color: rgba(255, 255, 255, 0.8);
  border-radius: 10px;
  box-shadow: 0 2px 10px rgba(0, 0, 0, 0.2);
}
.text {
  font-size: 16px;
  color: #333;
}
</style>

在這個(gè)例子中,頁(yè)面使用了大型背景圖片,并且每個(gè)列表項(xiàng)都有復(fù)雜的樣式,這可能導(dǎo)致樣式計(jì)算和渲染變慢。

優(yōu)化后(減少DOM數(shù)量和簡(jiǎn)化CSS):

<template>
  <view class="container">
    <text v-for="(item, index) in items" :key="index" class="text">{{ item.text }}</text>
  </view>
</template>


<style>
.container {
  background-color: #fff; /* 使用純色背景代替圖片 */
}
.text {
  font-size: 16px;
  color: #333;
  margin: 10px;
  padding: 10px;
  background-color: rgba(255, 255, 255, 0.8);
  border-radius: 5px;
  box-shadow: none; /* 移除陰影效果 */
}
</style>

在優(yōu)化后的示例中,我們做了以下改動(dòng):

  1. 移除了.item類,直接將文本包裹在<text>標(biāo)簽中,減少了DOM數(shù)量。
  2. 使用純色背景代替大型背景圖片,減少了圖片加載時(shí)間。
  3. 簡(jiǎn)化了.text類的樣式,移除了陰影效果,減少了樣式計(jì)算的復(fù)雜度。

優(yōu)化說(shuō)明:

  • 減少頁(yè)面中的DOM元素?cái)?shù)量,可以減少瀏覽器的渲染負(fù)擔(dān),提高渲染效率。
  • 簡(jiǎn)化CSS樣式,避免復(fù)雜的盒模型計(jì)算和陰影效果,可以減少樣式計(jì)算時(shí)間。
  • 使用小圖或純色背景代替大圖,可以減少圖片加載時(shí)間,加快頁(yè)面渲染速度。

通過(guò)這樣的優(yōu)化,可以顯著提升頁(yè)面的渲染速度,使得用戶體驗(yàn)更加流暢。同時(shí),也要注意在App.vue中設(shè)置全局樣式,以加速頁(yè)面樣式的渲染速度。如果是在App端,還可以在pages.json中配置頁(yè)面的原生背景色,以避免新頁(yè)面進(jìn)入時(shí)背景閃白的問(wèn)題。

最后

以上優(yōu)化小技巧,可以顯著提升微信小程序的響應(yīng)速度和用戶體驗(yàn),你還有哪些在實(shí)際開發(fā)中的經(jīng)驗(yàn),可以在評(píng)論區(qū)與大家一起分享,感謝你的支持,歡迎關(guān)注威哥愛編程,創(chuàng)造不易,點(diǎn)個(gè)贊唄。

以上內(nèi)容是否對(duì)您有幫助:
在線筆記
App下載
App下載

掃描二維碼

下載編程獅App

公眾號(hào)
微信公眾號(hào)

編程獅公眾號(hào)