uni-app開發(fā)之為什么H5正常、微信小程序頻繁踩坑記錄
前言
最近用 uni-app 寫了一個項目,本地用 H5 模式開發(fā)和調(diào)試時一切正常,頁面、交互、數(shù)據(jù)更新都沒有問題。 但當(dāng)代碼部署到 微信小程序 后,卻陸續(xù)出現(xiàn)了一些詭異的問題: 有的邏輯在 H5 能跑,小程序卻完全不生效;有的組件在 H5 表現(xiàn)正常,小程序卻怎么調(diào)都不對。
一開始我以為是自己代碼寫得有問題,直到踩坑越來越多才發(fā)現(xiàn)—— H5 和微信小程序的差異,遠(yuǎn)比我最初想象的要大得多。
所以想寫篇博客記錄一下開發(fā)中遇到的坑以及是如何解決的
同一套 uni-app / Vue 代碼,H5 跑得好好的,到了微信小程序卻各種翻車。
v-show 不生效、table 里 ref 調(diào)不到、輸入框值怎么都回不去……
這些問題并不是偶發(fā) bug,而是微信小程序底層架構(gòu)與瀏覽器完全不同導(dǎo)致的必然結(jié)果。
本文從實際場景出發(fā),把我在實際開發(fā)中高頻踩到的坑系統(tǒng)整理一遍,樹立一下小程序思維。
一、核心結(jié)論先行
一句話總結(jié)微信小程序的本質(zhì):
微信小程序 = 雙線程 + setData + 自定義組件
而 H5 是:
瀏覽器 + DOM + 同步更新
你在開發(fā)中遇到的 80% 問題,都可以回到這條差異上來解釋。
二、什么是「雙線程模型」?
1. H5(瀏覽器)的運行方式
在瀏覽器中:
- JS 可以直接操作 DOM
- 數(shù)據(jù)變化 → 視圖幾乎同步更新
v-model、input.value都是“最終裁判”
可以理解為:
JS 線程 ↓ DOM ↓ 頁面立刻變化
這是一個單一運行環(huán)境。
2. 微信小程序的運行方式
微信小程序為了安全性和可控性,徹底禁用了 DOM,改成了雙線程架構(gòu):
┌──────────────┐
│ 邏輯層 JS │ ← 你的 Vue / JS 代碼
└───────▲──────┘
│ setData(JSON)
┌───────▼──────┐
│ 視圖層 WXML │ ← 渲染、組件內(nèi)部狀態(tài)
└──────────────┘特點:
- 邏輯層和視圖層完全隔離
- 只能通過
setData傳 JSON 數(shù)據(jù) - 所有 UI 更新都是異步的
JS 不能直接改 UI,只能“請求”視圖層更新。
三、為什么「H5 能跑,小程序翻車」?
下面這些你踩過的坑,其實都源于同一個原因。
四、v-show 在 th / td 不生效
1. H5 中的認(rèn)知
<td v-show="show">庫存</td>
在瀏覽器里:
- 本質(zhì)是
display: none - DOM 仍然存在
- table 布局可以正確處理
2. 小程序中為什么不行?
原因有兩個:
小程序沒有真實的 table DOM
table / tr / td只是被編譯成普通 view- 表格布局是 uni-ui 模擬的
表格結(jié)構(gòu)在視圖層一次性計算
v-show只改邏輯層狀態(tài)- 列寬、行結(jié)構(gòu)不會重新計算
結(jié)果就是:
數(shù)據(jù)變了,但表格結(jié)構(gòu)不重算
正確做法
<th v-if="showCol">庫存</th>
<td v-if="showCol">{{ row.stock }}</td>在 table 結(jié)構(gòu)里:只用 v-if,不要用 v-show。
五、table 點擊事件里調(diào)用 ref 不生效
1. 常見寫法
openPopup() {
this.$refs.popupRef.open()
}H5:大多能跑
小程序:經(jīng)常無效
2. 真正原因
在小程序中,事件鏈路是:
點擊 td(視圖層) ↓ 事件傳到邏輯層 ↓ 你同步調(diào)用 ref ↓ popup 組件: - 可能還沒渲染 - 可能被 v-show 隱藏
ref 在小程序中是異步可用的。
正確用法
openPopup() {
this.$nextTick(() => {
this.$refs.popupRef?.open()
})
}并且:
- popup 盡量用
v-if - 不要指望 ref 在同一個 tick 里可用
其實$refs + $nextTick在微信小程序依然不生效的真實原因
很多人在 H5 中已經(jīng)形成了一個條件反射式寫法:
openPopup() {
this.$nextTick(() => {
this.$refs.popupRef?.open()
})
}在 H5 / WebView 下,這種寫法基本 100% 生效; 但在 微信小程序(包括 uni-app)中,這段代碼依然可能完全不生效。
為什么有時候$nextTick + ref在小程序里也不可靠?
核心原因只有一句話:
$nextTick 只能保證 Vue 虛擬 DOM 更新完成,不能保證小程序組件實例已經(jīng) ready。
在微信小程序中:
- 組件是 自定義組件(不是 DOM)
- 渲染發(fā)生在 渲染層線程
- 父組件邏輯運行在 邏輯層線程
- 組件實例的創(chuàng)建、掛載、通信,都需要經(jīng)過
setData的異步橋接
因此會出現(xiàn)以下真實現(xiàn)象:
| 你以為 | 實際發(fā)生 |
|---|---|
$nextTick 后 ref 一定存在 | ref 變量存在,但組件實例尚未 ready |
this.$refs.popupRef.open() | 調(diào)用時組件方法尚未注入 |
| 控制臺不報錯 | UI 沒任何反應(yīng) |
小程序中最穩(wěn)定、推薦的做法:狀態(tài)驅(qū)動 + emit 回傳
不要用父組件主動“命令式”調(diào)用子組件方法,而是:
?? 用狀態(tài)控制子組件,用事件通知父組件
父組件
<Popup :visible="popupVisible" @close="popupVisible = false" />
data() {
return { popupVisible: false }
},
methods: {
openPopup() {
this.popupVisible = true
}
}子組件
props: { visible: Boolean },
watch: {
visible(val) {
val ? this.open() : this.close()
}
},
methods: {
close() {
this.$emit('close')
}
}一句話總結(jié)
- H5:可以命令式(ref / 調(diào)方法)
- 小程序:必須聲明式(狀態(tài)驅(qū)動) v-show 在 th / td 不生效
六、輸入框值更新失?。╱ni-easyinput)
1. 現(xiàn)象
- H5:校驗后值能回退
- 小程序:輸入框仍顯示非法值
2. 根因
在小程序中:
組件內(nèi)部 value(視圖層) ≠ v-model 綁定值(邏輯層)
如果組件不是“完全受控”:
- 視圖層內(nèi)部狀態(tài)優(yōu)先
- 你 setData 只是建議
正確組合
<uni-easyinput v-model="row.qty" :controlled="true" @change="checkQty" />
關(guān)鍵點:
- 使用
change而不是input - 開啟
controlled
七、input / change / blur 的正確選擇
| 事件 | 建議 | 原因 |
|---|---|---|
| input | ? 少用 | 頻繁、不可控 |
| change | ? 推薦 | 停止輸入后的業(yè)務(wù)節(jié)點 |
| blur | ?? UI 用 | 只是焦點變化 |
業(yè)務(wù)校驗一律優(yōu)先用 change。
八、ref、v-for、響應(yīng)式的隱藏雷區(qū)
1. ref + v-for
- H5:ref 數(shù)組
- 小程序:可能只有最后一個
?? 不要依賴 ref 操作列表項
2. 深層對象更新
list[index].count = 1
在小程序中不穩(wěn)定,推薦:
this.list = this.list.map(item =>
item.id === row.id ? { ...item, count: 1 } : item
)
//或者
const index=this.list.findIndex(item.id===row.id)
this.$set(this.list[index], 'count', 1)不可變更新在小程序更安全。
九、統(tǒng)一解釋模型(記住這個)
你遇到的所有問題,其實都是:
邏輯層變了,但視圖層沒有按你預(yù)期同步
對應(yīng)關(guān)系:
| 現(xiàn)象 | 根因 |
|---|---|
| v-show 不生效 | 視圖結(jié)構(gòu)不重算 |
| ref 調(diào)不到 | 組件未 ready |
| input 回寫失敗 | 內(nèi)部狀態(tài)優(yōu)先 |
十、小程序開發(fā)「安全原則」
- 少用
input,多用change - 表格、彈窗優(yōu)先
v-if - ref 一律
nextTick - 組件要么全受控,要么不受控
- 減少 setData 次數(shù)
十一、一句話總結(jié)
H5 是“我命令頁面怎么變” 小程序是“我請求頁面幫我變”
當(dāng)你真正接受這一點,80% 的坑都會自動消失。
到此這篇關(guān)于uni-app開發(fā)之為什么H5正常、微信小程序頻繁踩坑記錄的文章就介紹到這了,更多相關(guān)uni-app H5正常、微信小程序踩坑內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
- uniapp微信小程序使用webview嵌套uniappH5并實現(xiàn)通信詳細(xì)步驟
- uniapp實現(xiàn)h5、app與微信小程序三端pdf文件下載和預(yù)覽功能
- uniapp中微信小程序與H5相互跳轉(zhuǎn)以及傳參詳解(webview)
- uniapp前端實現(xiàn)微信支付功能全過程(小程序、公眾號H5、app)
- uniapp微信小程序與H5的彈窗滾動穿透解決方法
- uniapp開發(fā)H5打包微信小程序樣式失效的完美解決方法
- uniapp小程序和h5如何使用three.js詳解
- 基于uniapp+vue3自定義增強版table表格組件「兼容H5+小程序+App端」
- uni-app開發(fā)微信小程序之H5壓縮上傳圖片的問題詳解
- uniapp微信小程序webview和h5數(shù)據(jù)通信代碼示例
相關(guān)文章
Vue中的v-for循環(huán)key屬性注意事項小結(jié)
這篇文章主要介紹了Vue中的v-for循環(huán)key屬性注意事項小結(jié),非常不錯,具有一定的參考借鑒價值,需要的朋友可以參考下2018-08-08
ElementUI?復(fù)雜頂部和左側(cè)導(dǎo)航欄實現(xiàn)示例
本文主要介紹了ElementUI?復(fù)雜頂部和左側(cè)導(dǎo)航欄實現(xiàn)示例,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2022-04-04
Vue 中 computed的設(shè)計動機與底層實現(xiàn)原理解析
Vue的computed屬性是一個非常強大的功能,它不僅提高了代碼的可讀性和可維護(hù)性,還通過緩存機制優(yōu)化了性能,本文將詳細(xì)介紹Vue中 computed 的設(shè)計動機以及其底層實現(xiàn)原理,感興趣的朋友跟隨小編一起看看吧2025-10-10
vue百度地圖修改折線顏色,添加icon和文字標(biāo)注方式
這篇文章主要介紹了vue百度地圖修改折線顏色,添加icon和文字標(biāo)注方式,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教2024-03-03

