構(gòu)與避坑全流程)
簡(jiǎn)介一套包含100個(gè)微信小程序源碼的實(shí)戰(zhàn)資料包面向小程序入門(mén)開(kāi)發(fā)者、前端學(xué)習(xí)者及需要項(xiàng)目靈感的工程師。源碼覆蓋了從基礎(chǔ)語(yǔ)法到高級(jí)能力的完整鏈路包括頁(yè)面生命周期onLoad、onShow、onHide的調(diào)用時(shí)機(jī)、基于data屬性的單向數(shù)據(jù)流、通過(guò)wx.setStorageSync與wx.getStorageSync實(shí)現(xiàn)的本地持久化以及wx.request異步請(qǐng)求與錯(cuò)誤處理。此外地圖、支付、分享等常用API的集成方式也有典型示例可幫助讀者深入理解JavaScript邏輯層、WXML界面結(jié)構(gòu)與WXSS樣式布局三者如何協(xié)同構(gòu)建動(dòng)態(tài)應(yīng)用。壓縮包約185.3MB內(nèi)含100個(gè)可直接閱讀的微信小程序項(xiàng)目以JS邏輯文件、WXML結(jié)構(gòu)文件、WXSS樣式文件為核心代碼路徑清晰便于按模塊拆解學(xué)習(xí)。該資源已有554人學(xué)習(xí)下載既適合零基礎(chǔ)對(duì)照代碼掌握開(kāi)發(fā)流程也適合中高級(jí)開(kāi)發(fā)者借鑒性能優(yōu)化與交互設(shè)計(jì)思路。1. 微信小程序源碼拿來(lái)就跑還是拿來(lái)就改搜索“微信小程序源碼”的人十有八九不是想讀源碼而是想省事要么想找個(gè)成熟模板直接改改上線要么想把一套開(kāi)源代碼跑起來(lái)研究別人的頁(yè)面結(jié)構(gòu)。但真把源碼下載下來(lái)很多人卡在第一步——不知道哪些文件能刪、哪些文件動(dòng)不得更不知道改完怎么驗(yàn)證。這套東西其實(shí)不復(fù)雜核心就三件事看懂目錄、跑通環(huán)境、改對(duì)入口。本地跑通一套源碼比從零搭一個(gè)頁(yè)面省一半時(shí)間前提是知道每一步在干什么。這篇文章就從源碼結(jié)構(gòu)講起一直講到改造成自己的項(xiàng)目最后告訴你哪些坑是下載源碼后必踩的。2. 讀懂微信小程序源碼的目錄結(jié)構(gòu)先分清哪些是骨架、哪些是血肉2.1 源碼到底有哪幾類(lèi)文件從 app.js 到 page 的四層結(jié)構(gòu)微信小程序源碼和傳統(tǒng) Web 項(xiàng)目最大的區(qū)別是它有自己的一套運(yùn)行時(shí)框架。源碼里你會(huì)看到 .js、.json、.wxml、.wxss 四種后綴再加一個(gè)全局的 app.js、app.json、app.wxss。這套東西不是隨手建的微信開(kāi)發(fā)者工具在編譯時(shí)會(huì)按約定解析。拿到一套源碼我一般先打開(kāi)根目錄下的 app.json。這個(gè)文件決定了小程序有幾個(gè)頁(yè)面、每個(gè)頁(yè)面叫什么路徑、tabBar 怎么排是整個(gè)項(xiàng)目的“戶(hù)口本”。app.json 里有一個(gè) pages 數(shù)組第一項(xiàng)是啟動(dòng)頁(yè)后面的項(xiàng)是其他頁(yè)面。你在微信開(kāi)發(fā)者工具里看到的任何一個(gè)可跳轉(zhuǎn)頁(yè)面都必須在 pages 數(shù)組里登記過(guò)否則編譯能過(guò)、跳轉(zhuǎn)必失敗。{ pages: [ pages/index/index, pages/category/category, pages/cart/cart, pages/user/user ], window: { navigationBarTitleText: 商城Demo, navigationBarBackgroundColor: #ffffff, navigationBarTextStyle: black }, tabBar: { list: [ { pagePath: pages/index/index, text: 首頁(yè) }, { pagePath: pages/category/category, text: 分類(lèi) }, { pagePath: pages/cart/cart, text: 購(gòu)物車(chē) }, { pagePath: pages/user/user, text: 我的 } ] } }parameters 逐一說(shuō)一下pages 數(shù)組是頁(yè)面路由清單數(shù)組順序就是頁(yè)面編譯順序tabBar 只對(duì)原生 tab 頁(yè)面生效list 最多 5 項(xiàng)window 里配置的是頂部導(dǎo)航欄樣式navigationBarTitleText 改的是全局標(biāo)題。想快速判斷一套源碼的復(fù)雜程度先看 pages 數(shù)量和 tabBar 數(shù)量就夠了。全局的 app.js 是項(xiàng)目啟動(dòng)入口里面通常會(huì)做全局?jǐn)?shù)據(jù)初始化、登錄態(tài)檢查、版本更新檢測(cè)。很多源碼會(huì)在 app.js 里用 wx.getStorageSync 讀取本地 token判斷用戶(hù)是否登錄。app.wxss 是全局樣式表頁(yè)面樣式優(yōu)先于全局樣式同名類(lèi)名會(huì)被頁(yè)面 wxss 覆蓋。2.2 單個(gè)頁(yè)面里的四件套wxml 管結(jié)構(gòu)、wxss 管長(zhǎng)相、js 管邏輯、json 管配置進(jìn)入一個(gè)頁(yè)面目錄你會(huì)看到四個(gè)同名文件index.wxml、index.wxss、index.js、index.json。這四個(gè)文件互相配合缺一個(gè)編譯就報(bào)錯(cuò)。wxml 是頁(yè)面骨架里面全是自定義標(biāo)簽view、text、image、button。wxss 是樣式描述語(yǔ)法接近 CSS但只支持部分選擇器不支持通配符*也不支持部分偽類(lèi)。js 文件里存的是 Page 構(gòu)造函數(shù)里面有 data、onLoad、onShow 等生命周期以及所有事件處理函數(shù)。json 文件配置的是當(dāng)前頁(yè)面的標(biāo)題和下拉刷新開(kāi)關(guān)。Page({ data: { productList: [], currentPage: 1, hasMore: true }, onLoad() { this.loadProductList(); }, loadProductList() { wx.request({ url: https://api.example.com/products, data: { page: this.data.currentPage }, success: (res) { this.setData({ productList: this.data.productList.concat(res.data.list) }); } }); } })這段代碼注意三點(diǎn)。第一setData 是唯一能更新界面的 API直接改 this.data 不會(huì)觸發(fā)視圖刷新這個(gè)區(qū)別是源碼改造時(shí)最容易犯的錯(cuò)。第二success 回調(diào)里用的是箭頭函數(shù)確保 this 指向 Page 實(shí)例如果寫(xiě)成普通 functionthis 就丟了。第三頁(yè)面數(shù)據(jù)請(qǐng)求通常寫(xiě)在 onLoad 里onShow 適合做回到頁(yè)面時(shí)的刷新動(dòng)作。翻源碼時(shí)如果看到 onLoad 和 onShow 都發(fā)了請(qǐng)求說(shuō)明作者在刻意處理“首次進(jìn)入加載”和“二次進(jìn)入刷新”的差異??匆惶自创a質(zhì)量高低不要只看頁(yè)面效果先看以下三點(diǎn)檢查項(xiàng)質(zhì)量差的表現(xiàn)質(zhì)量好的表現(xiàn)生命周期所有邏輯堆在 onLoad加載、刷新、滑到底部加載分函數(shù)處理樣式命名大量?jī)?nèi)聯(lián) style類(lèi)名語(yǔ)義化復(fù)用公共樣式數(shù)據(jù)層頁(yè)面直接改全局變量有請(qǐng)求層、狀態(tài)管理和頁(yè)面隔離新手拿到源碼先別急著刪文件照著這個(gè)表過(guò)一遍目錄心里有數(shù)再動(dòng)手。3. 把微信小程序源碼跑起來(lái)從導(dǎo)入到真機(jī)預(yù)覽的完整命令鏈3.1 本地跑通的最小步驟注冊(cè)、導(dǎo)入、開(kāi)服務(wù)端口下載一套源碼之后第一件事不是看代碼而是確認(rèn)自己的開(kāi)發(fā)環(huán)境能把它跑起來(lái)。微信開(kāi)發(fā)者工具有一個(gè)特性不登錄不能編譯。所以你需要一個(gè)自己的 AppID。如果只是本地研究可以用工具里的“測(cè)試號(hào)”模式不需要去公眾平臺(tái)注冊(cè)企業(yè)賬號(hào)。但測(cè)試號(hào)不能調(diào)用大部分需要審核的接口而且云開(kāi)發(fā)功能不可用跑通到真機(jī)預(yù)覽這一步?jīng)]問(wèn)題。打開(kāi)微信開(kāi)發(fā)者工具選“導(dǎo)入項(xiàng)目”目錄選源碼所在文件夾AppID 選測(cè)試號(hào)或自己的真實(shí) AppID。這里有一個(gè)很多人踩過(guò)的坑源碼里如果引用了云開(kāi)發(fā)能力工具會(huì)要求你開(kāi)通云環(huán)境。云環(huán)境開(kāi)通需要實(shí)名認(rèn)證沒(méi)有實(shí)名就只能用本地資源替換后面會(huì)講怎么處理。# 用命令行打開(kāi)微信開(kāi)發(fā)者工具不經(jīng)過(guò)圖形界面點(diǎn)選 # 前提是開(kāi)發(fā)者工具安裝目錄里的 cli 已加入系統(tǒng) PATH cli open --project /path/to/miniprogram-source --appid your-appid命令行打開(kāi)適合自動(dòng)化腳本或者反復(fù)編譯調(diào)試的場(chǎng)景。參數(shù)解釋--project指向源碼的絕對(duì)路徑必須包含 app.json 那一層--appid換自己的 AppID如果源碼里 app.js 寫(xiě)死了 AppID會(huì)在代碼里覆蓋它加了--auto-port參數(shù)時(shí)工具會(huì)在啟動(dòng)時(shí)輸出調(diào)試端口號(hào)供后續(xù)自動(dòng)化腳本連接。編譯通過(guò)不代表功能正常。項(xiàng)目跑起來(lái)后第一件事是看 Console 面板有沒(méi)有報(bào)錯(cuò)最常見(jiàn)的錯(cuò)誤是 request 請(qǐng)求的域名不在合法列表里。微信對(duì)小程序請(qǐng)求有強(qiáng)校驗(yàn)正式環(huán)境只允許訪問(wèn) HTTPS 且已備案的域名開(kāi)發(fā)工具可以勾選“不校驗(yàn)合法域名”。但真機(jī)預(yù)覽時(shí)這個(gè)開(kāi)關(guān)不生效所以本地跑通和真機(jī)跑通是兩回事。3.2 真機(jī)預(yù)覽與調(diào)試把源碼從編輯器搬到手機(jī)上本地編譯通過(guò)后點(diǎn)擊工具欄的“預(yù)覽”按鈕會(huì)生成一個(gè)二維碼。同一局域網(wǎng)下用微信掃碼就能把源碼跑在真機(jī)上。真機(jī)預(yù)覽最大的區(qū)別是環(huán)境切換電腦上的緩存、本地存儲(chǔ)、網(wǎng)絡(luò)請(qǐng)求全都在手機(jī)端重新執(zhí)行一遍。如果源碼里有請(qǐng)求接口真機(jī)預(yù)覽時(shí)請(qǐng)求會(huì)指向正式環(huán)境還是本地環(huán)境取決于代碼里的 baseURL 判斷。const isDev options.env development; const baseURL isDev ? http://localhost:3000/api : https://api.yourdomain.com/api;這段代碼的邏輯說(shuō)明開(kāi)發(fā)環(huán)境下走本機(jī) localhost發(fā)布走正式域名這是最常見(jiàn)的環(huán)境切換寫(xiě)法人手一個(gè)。但真機(jī)預(yù)覽有個(gè)坑手機(jī)訪問(wèn)電腦的 localhost 是失敗的手機(jī)只能訪問(wèn)局域網(wǎng)內(nèi)電腦的 IP。需要把 baseURL 改成局域網(wǎng) IP比如http://192.168.1.100:3000/api并且確認(rèn)電腦防火墻放行了 3000 端口。常見(jiàn)做法是在源碼里抽出一個(gè) config.js單獨(dú)放環(huán)境變量改起來(lái)不用全局搜索。真機(jī)預(yù)覽階段建議打開(kāi) vConsole。在 app.js 里引入 vConsole 之后手機(jī)端就能看到 console 日志和網(wǎng)絡(luò)請(qǐng)求詳情。源碼里如果帶了 vConsole調(diào)試效率提升一個(gè)量級(jí)沒(méi)有的話(huà)自己加一行代碼也不難。真機(jī)調(diào)試的另一大好處是能看到模擬器里不明顯的問(wèn)題真機(jī)渲染差異、字體適配、底部安全區(qū)、滑動(dòng)性能這些在電腦上跑不出感覺(jué)。4. 把通用源碼改造成自己的項(xiàng)目AppID、域名、tabBar 與主題色替換4.1 全局搜索替換法AppID、項(xiàng)目名、請(qǐng)求域名的四條修改主軸拿到萬(wàn)能模板很多人第一反應(yīng)是改圖片換文案。這個(gè)思路沒(méi)錯(cuò)但順序要反過(guò)來(lái)先改項(xiàng)目身份再改視覺(jué)。項(xiàng)目身份指的是 AppID、項(xiàng)目名、請(qǐng)求域名、云開(kāi)發(fā)環(huán)境 ID。這四樣?xùn)|西不改小程序頁(yè)面再漂亮發(fā)布時(shí)也上不了線。實(shí)際操作中我一般用工具全局搜索以下關(guān)鍵詞替換 AppID 搜wx開(kāi)頭的 appid 字符串替換項(xiàng)目名搜小程序初始化的項(xiàng)目名稱(chēng)替換請(qǐng)求域名搜https://開(kāi)頭的接口地址替換云環(huán)境搜cloud.init方法里的環(huán)境 ID。每個(gè)源碼的寫(xiě)法不同但搜索命中的位置高度集中app.js、config.js、項(xiàng)目根目錄的 project.config.json。{ appid: touristappid, projectname: example-mall, setting: { es6: true, postcss: true, minified: true }, libVersion: 2.30.0 }project.config.json 是開(kāi)發(fā)者工具的項(xiàng)目配置文件里面放著appid、項(xiàng)目名、編譯選項(xiàng)。替換源碼時(shí)最容易遺漏的就是這里很多人只改了 app.js 里的 AppID工具的正式環(huán)境編譯怎么都不對(duì)。projectname 對(duì)源碼本身沒(méi)有影響但它決定了工具左側(cè)展示的項(xiàng)目名也是微信公眾平臺(tái)后臺(tái)識(shí)別項(xiàng)目的依據(jù)。替換完四件套后建議做一次全量編譯再逐個(gè)頁(yè)面點(diǎn)擊測(cè)試。這里有一個(gè)很常見(jiàn)的現(xiàn)象替換完域名后首頁(yè)能打開(kāi)、列表能加載但詳情頁(yè)或登錄接口 404。原因是源碼里不同頁(yè)面可能用了不同的請(qǐng)求層封裝有的走 wx.request有的走云函數(shù)改造時(shí)只替換了其中一部分請(qǐng)求地址。4.2 頁(yè)面級(jí)改造tabBar、主題色、圖片資源的三板斧身份替換完成接下來(lái)是頁(yè)面改造。tabBar 在 app.json 里定義改 tab 的圖標(biāo)需要準(zhǔn)備 81px 和 81px 兩套尺寸的 PNG普通 PNG 圖標(biāo)在 tabBar 里會(huì)被等比縮放。注意 tabBar 的圖標(biāo)不能大于 40KB超出后真機(jī)會(huì)渲染失敗。主題色替換最簡(jiǎn)單的辦法是全局搜索主色號(hào)比如#ff6600把出現(xiàn)的所有位置統(tǒng)一映射不遺漏。更規(guī)范的做法是把主題色提成全局公共變量在 wxss 里不能直接用 CSS 變量所以通常用 class 復(fù)用替代。圖片資源的替換是最容易被忽略的一環(huán)。很多源碼的圖片用的是絕對(duì)路徑比如/images/banner.png。這些圖片被壓縮過(guò)直接替換同名文件可能出現(xiàn)尺寸不匹配。建議在項(xiàng)目目錄里看 images 文件夾的實(shí)際文件清單和頁(yè)面引用一一對(duì)應(yīng)。一張張?zhí)鎿Q很繁瑣但值得做視覺(jué)上的違和感幾乎都是圖片比例不對(duì)造成的。// 頁(yè)面事件處理用 dataset 傳遞當(dāng)前點(diǎn)擊項(xiàng) handleProductTap(event) { const { id, name } event.currentTarget.dataset; wx.navigateTo({ url: /pages/detail/detail?id${id}name${name} }); }dataset 是 WXML 里>// navigationConfig.js 頁(yè)面導(dǎo)航配置 module.exports [ { title: 產(chǎn)品手冊(cè), path: /pages/manual/manual, icon: book }, { title: 常見(jiàn)問(wèn)題, path: /pages/faq/faq, icon: help }, { title: 版本記錄, path: /pages/changelog/changelog, icon: time } ];// index.js 讀取配置渲染導(dǎo)航 const navConfig require(./navigationConfig); Page({ data: { items: navConfig }, onNavTap(event) { const path event.currentTarget.dataset.path; wx.navigateTo({ url: path }); } })這樣的配置驅(qū)動(dòng)方式好處是新增頁(yè)面不碰頁(yè)面文件只動(dòng)配置。源碼原有的頁(yè)面邏輯不用重寫(xiě)只需要把原來(lái)的靜態(tài)列表替換成遍歷渲染。這算是從“改源碼”到“用源碼”的一個(gè)臺(tái)階。我做了這么多年源碼改造最大的教訓(xùn)是永遠(yuǎn)不要高估自己對(duì)別人代碼的理解力。拿到一套源碼先小步改造、反復(fù)編譯驗(yàn)證改一處就測(cè)一處比一次性把 app.json 大改一通再回頭排查省時(shí)得多。這套思路同樣適合后續(xù)加功能加一個(gè)“分享得積分”模塊只需要在導(dǎo)航配置里加一項(xiàng)頁(yè)面文件單獨(dú)建不用動(dòng)入口。希望這些經(jīng)驗(yàn)?zāi)茏屇闵僮咭欢螐澛吩谠创a改造的路上更順一些。本文還有配套的精品資源點(diǎn)擊獲取