微信小程序開(kāi)發(fā)之你可能沒(méi)有踩過(guò)的神坑總結(jié)
getApp()
getApp() 函數(shù)是用來(lái)獲取 app 實(shí)例的函數(shù),一般情況下沒(méi)啥問(wèn)題,但是在幾個(gè)特殊的場(chǎng)景下它會(huì)給你帶來(lái)意想不到的 bug。
在 app.js 中的 onLaunch 回調(diào)函數(shù)中使用
// app.js App({ onLaunch() { console.info(getApp(), '!!'); } });
你會(huì)發(fā)現(xiàn)這個(gè)時(shí)候會(huì)輸出 undefined ,這其實(shí)可以理解,畢竟這個(gè)時(shí)候還在初始化階段,app 還沒(méi)出生。如果代碼僅僅是這么簡(jiǎn)單的話,那你可以很容易的發(fā)現(xiàn)這個(gè)問(wèn)題,一旦你在其中調(diào)用了一個(gè)方法,而這個(gè)方法又不小心在獲取 app 實(shí)例來(lái)獲取變量,那意外就產(chǎn)生了。
So~ 如果沒(méi)有同步要求,可以在 onLaunch 中調(diào)用函數(shù)可以包一層 setTimout 避免踩坑:
// app.js App({ onLaunch() { setTimeout(() => { // ... 調(diào)用其他函數(shù) }); } });
將 getApp() 賦值給一個(gè)變量
我們創(chuàng)建一個(gè) a.js 文件:
// a.js const app = getApp(); export function checkVersion() { console.log('checked!'); console.info('app', app, '!!'); }
上面的文件一般情況下不會(huì)遇到什么問(wèn)題,但是一旦你在 app.js 中引入,那驚喜就產(chǎn)生了。
// app.js import { checkVersion } from 'a'; App({ onLaunch() { console.log('I\'m Fine!'); }, onShow() { checkVersion(); } });
這個(gè)時(shí)候你會(huì)發(fā)現(xiàn) app 變量是 undefined,這種錯(cuò)誤你可能很難發(fā)覺(jué),特別是封裝的一個(gè)通用庫(kù),平時(shí)好好的,但是突然在 app.js 中使用了一下,就哎嘿了。
So~ 為了避免這種問(wèn)題,盡量減少公用 app 實(shí)例共享,而是在方法中直接使用 getApp() 來(lái)獲取實(shí)例對(duì)象。如果要使用全局變量,可以單獨(dú)一個(gè) js 文件來(lái)單獨(dú)存儲(chǔ)變量會(huì)更好,比如:
// globalStore.js export default { userInfo: null, isIos: false, isLaunched: false, };
// app.js import store from 'globalStore'; App({ onLaunch() { store.isLaunched = true; }, onShow() { const { isLaunched } = getApp().store, console.log(isLaunched); }, store, });
這樣既可以通過(guò)導(dǎo)入模塊的方式獲取全局變量,又可以兼容通過(guò) getApp().store 來(lái)獲取全局變量。
但是原則上我還是建議通過(guò)導(dǎo)入模塊的方式來(lái)讀寫(xiě)全局變量,畢竟在某些情況下 getApp() 返回了 undefined 。
在頁(yè)面入口文件頂部定義變量
在頁(yè)面入口文件定義變量很常見(jiàn),但是你一定要注意的是,頁(yè)面的入口文件只會(huì)執(zhí)行一次,并不是每個(gè)頁(yè)面實(shí)例獨(dú)立的,比如下面的代碼:
// pages/page/index.js import { getDetailInfo } from 'api'; let ajaxLock = false; Page({ onLoad() { this.getRemoteData(); }, async getRemoteData() { if (ajaxLock) { return; } ajaxLock = true; try { await getDetailInfo(); } catch(err) { // ... 處理錯(cuò)誤 } finally { ajaxLock = false; } }, });
頁(yè)面邏輯比較簡(jiǎn)單,一進(jìn)入頁(yè)面就請(qǐng)求遠(yuǎn)程數(shù)據(jù),目測(cè)也沒(méi)啥問(wèn)題,但是一旦同時(shí)打開(kāi)多個(gè)該頁(yè)面,你會(huì)發(fā)現(xiàn)只有第一個(gè)頁(yè)面請(qǐng)求了數(shù)據(jù),后面的頁(yè)面沒(méi)有請(qǐng)求,因?yàn)檫@幾個(gè)頁(yè)面都共享了 ajaxLock 這個(gè)變量,因此在頁(yè)面頂部聲明的變量,一定要注意使用場(chǎng)景。
頁(yè)面入口文件中 data 中直接賦值全局變量
直接上代碼:
// pages/page/index.js Page({ data: { isIos: getApp().store.isIos, }, });
// app.js App({ onLaunch() { this.getSysInfo(); }, getSysInfo() { return new Promise((resolve, reject) => { wx.getSystemInfoAsync({ success: resolve, fail: reject, }); }).then((res) => { const { store } = getApp(); store.isIos = res.platform.toLowerCase() === 'ios'; }); }, store: { isIos: false, }, });
上面代碼的主要邏輯就是需要知道當(dāng)前設(shè)備是不是 ios ,代碼在模擬器上跑著似乎很穩(wěn)定,但是一旦上了真機(jī),就時(shí)好時(shí)壞了,因?yàn)?isIos 這個(gè)變量不是同步獲取狀態(tài)的,一旦賦值在頁(yè)面入口函數(shù)執(zhí)行完之后,那么狀態(tài)的展現(xiàn)就會(huì)不正確。
因此對(duì)于某些狀態(tài)不是同步賦值,千萬(wàn)不要直接通過(guò)在初始化的時(shí)候直接給 data 賦值的方式去操作,最好放到 onLoad 回調(diào)函數(shù)中去賦值狀態(tài)。
你不知道的 wx.createSelectorQuery() and wx.createIntersectionObserver();
這兩個(gè)函數(shù)也是比較常用的,wx.createSelectorQuery 主要用來(lái)查詢某個(gè)元素,wx.createIntersectionObserver 用在需要處理元素是否在可視區(qū)。這兩個(gè)函數(shù)的問(wèn)題目測(cè)純純的可愛(ài),我也是在實(shí)現(xiàn)某個(gè)特殊需求的時(shí)候才發(fā)現(xiàn),也真是后知后覺(jué),不明覺(jué)厲,細(xì)思極恐...
我們來(lái)復(fù)現(xiàn)問(wèn)題,頁(yè)面入口函數(shù)這么寫(xiě):
// pages/page/index.js let index = 0 Page({ data: { tag: 0 }, onLoad() { if (index++ < 2) { wx.navigateTo({ url: '/pages/page/index' }); } this.setData({ tag: index },() => { setTimeout(() => { const { tag } = this.data; const query = wx.createSelectorQuery(); // const query = this.createSelectorQuery(); query.select(`.c-${ tag }`).boundingClientRect(); query.exec((res) => { console.log(tag, res); }); }, 2000); }); } });
<!-- 模板文件 --> <view class="c-{{tag}}">demo</view>
我模擬了同時(shí)打開(kāi)多個(gè)頁(yè)面的情況,在開(kāi)發(fā)者工具中你就會(huì)發(fā)現(xiàn),前兩個(gè)頁(yè)面的結(jié)果居然是 null ?。?!當(dāng)時(shí)我就覺(jué)得世界有點(diǎn)兒崩塌。因此我懷疑畢竟 wx.createSelectorQuery 是一個(gè)全局函數(shù),因此它查詢的是當(dāng)前活躍窗口下的 wxml。怎么解決呢,我翻了翻官方文檔,用放大鏡找了找小字,發(fā)現(xiàn)有 this.createSelectorQuery 這個(gè)方法,抱著試一試的態(tài)度,問(wèn)題就突然解決了。當(dāng)然 wx.createIntersectionObserver 也是同樣的問(wèn)題,我就不做演示了。
So~ 為了身體好,我強(qiáng)烈建議直接使用 this.createSelectorQuery 和 this.createIntersectionObserver 。
以上是我這幾年開(kāi)發(fā)微信小程序踩過(guò)的神坑,望你不要再踩上~~
總結(jié)
到此這篇關(guān)于微信小程序開(kāi)發(fā)之你可能沒(méi)有踩過(guò)的坑的文章就介紹到這了,更多相關(guān)微信小程序開(kāi)發(fā)的坑內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
JavaScript中日常收集常見(jiàn)的10種錯(cuò)誤(推薦)
本文是小編給大家日常收集整理的js中常見(jiàn)的10種錯(cuò)誤,非常不錯(cuò),具有參考借鑒價(jià)值,需要的朋友參考下2017-01-01JavaScript實(shí)現(xiàn)簡(jiǎn)易計(jì)算器功能的兩種方法
這篇文章主要為大家詳細(xì)介紹了JavaScript實(shí)現(xiàn)簡(jiǎn)易計(jì)算器功能的兩種方法,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2022-07-07JavaScript數(shù)組Array的一些常用方法總結(jié)
JavaScript的Array對(duì)象是用于構(gòu)造數(shù)組的全局對(duì)象,數(shù)組是類(lèi)似于列表的高階對(duì)象,下面這篇文章主要給大家介紹了關(guān)于JavaScript數(shù)組Array的一些常用方法,需要的朋友可以參考下2021-11-11js中常見(jiàn)切割截取字符串的幾種方法小結(jié)
前端開(kāi)發(fā)中,字符串處理是比較常見(jiàn)的,下面這篇文章主要給大家介紹了關(guān)于js中常見(jiàn)切割截取字符串的幾種方法,文中通過(guò)實(shí)例代碼介紹的非常詳細(xì),需要的朋友可以參考下2022-09-09基于JavaScript實(shí)現(xiàn)彈出框效果
彈出框在網(wǎng)站頁(yè)面中是必不可少的一部分,今天借助腳本之家平臺(tái)給大家分享使用js實(shí)現(xiàn)簡(jiǎn)單的彈出框效果,感興趣的朋友一起學(xué)習(xí)吧2016-02-02使用Javascript簡(jiǎn)單實(shí)現(xiàn)圖片無(wú)縫滾動(dòng)
本文簡(jiǎn)單介紹了使用原生javascript實(shí)現(xiàn)簡(jiǎn)單的圖片無(wú)縫滾動(dòng)的方法,并附上示例代碼,推薦給大家,直接可以用在項(xiàng)目中的。2014-12-12一個(gè)可以得到元素真實(shí)的背景顏色的javascript腳本
一個(gè)可以得到元素真實(shí)的背景顏色的javascript腳本...2007-07-07基于javascript實(shí)現(xiàn)listbox左右移動(dòng)
這篇文章主要介紹了基于javascript實(shí)現(xiàn)listbox左右移動(dòng)的相關(guān)資料,以一個(gè)完整的實(shí)例代碼分析了js實(shí)現(xiàn)listbox左右移動(dòng)的相關(guān)技巧,感興趣的小伙伴們可以參考一下2016-01-01js 正則驗(yàn)證密碼強(qiáng)度(包含數(shù)字+特殊字符+英文字母大小寫(xiě))
密碼驗(yàn)證是常見(jiàn)的網(wǎng)站注冊(cè)方法,本文主要介紹了js 正則驗(yàn)證密碼強(qiáng)度(包含數(shù)字+特殊字符+英文字母大小寫(xiě)),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2023-01-01