:從請求封裝到列表渲染)
簡介這份資源是一套基于微信小程序實現(xiàn)的火車票查詢系統(tǒng)源碼面向具備小程序基礎語法、希望練習接口調用與頁面聯(lián)調的開發(fā)者也可作為課程設計或畢業(yè)設計的起步模板。項目圍繞車次查詢、站點信息與余票展示等典型場景組織代碼方便在此基礎上繼續(xù)擴展訂單、登錄等功能。壓縮包共23個文件約11KB包含8個js邏輯腳本、5個json配置、5個wxss樣式、4個wxml頁面結構以及1個md說明文檔分別承擔業(yè)務邏輯、頁面配置、界面樣式與視圖渲染等職責目錄按頁面與工具模塊劃分結構清晰。目前已有1643人學習下載。讀者可從中獲取完整的小程序請求封裝與頁面交互示例理解api與request工具模塊的調用方式并參考其目錄組織與配置寫法快速搭建自己的查詢類小程序減少從零摸索的成本。1. 從一次搶票失敗說起這個火車票查詢小程序到底能干什么去年春運前我?guī)团笥芽匆粋€搶票腳本的問題結果發(fā)現(xiàn)他連車次余票都查不明白——用的還是某個第三方網(wǎng)頁接口返回的數(shù)據(jù)結構一變整個腳本就崩了。當時我就想與其依賴別人維護的接口不如自己寫一個能跑通查詢鏈路的小程序。后來在代碼倉庫里翻到了這個「微信小程序-火車票查詢」項目它正好解決了一個很具體的需求在微信里輸入出發(fā)站、到達站和日期直接拿到車次列表和余票信息不用跳來跳去。這個項目適合兩類人一是想學小程序網(wǎng)絡請求和列表渲染的新手代碼結構簡單跑起來就能看到數(shù)據(jù)二是需要快速搭一個查詢工具原型的開發(fā)者核心邏輯抽出來就能復用。它不涉及支付和下單只做查詢展示所以調試成本很低不用申請復雜的商戶資質。接下來我按「能跑、能看懂、能改」的順序把這個項目的骨架和關鍵實現(xiàn)拆一遍。2. 項目骨架與運行鏈路從目錄結構到第一次請求成功2.1 目錄結構小程序標準分層與頁面組織拿到源碼后先看根目錄。這個項目用的是微信小程序原生框架沒有引入第三方 UI 庫所以目錄很干凈。常見結構是pages放頁面、utils放工具函數(shù)、app.json做全局配置。我打開時第一眼找的是app.json里的pages數(shù)組它決定了啟動頁和頁面路徑。{ pages: [ pages/index/index, pages/result/result ], window: { navigationBarTitleText: 火車票查詢, navigationBarBackgroundColor: #1E90FF } }這段配置里pages數(shù)組第一項是啟動頁所以打開小程序先看到查詢表單。window里設了導航欄標題和背景色改顏色直接改十六進制值就行。注意pages路徑不要寫.js后綴否則編譯會報錯這是新手常踩的坑。pages/index負責輸入pages/result負責展示車次列表。兩個頁面之間用wx.navigateTo跳轉參數(shù)通過 URL 拼接傳遞。這種拆分方式讓查詢邏輯和渲染邏輯分開改起來不會互相干擾。2.2 查詢表單輸入校驗與日期選擇首頁的index.wxml里放了兩個輸入框和一個日期選擇器。出發(fā)站和到達站用input日期用picker modedate。我一般會在這里加一個非空校驗防止用戶直接點查詢導致請求參數(shù)為空。// pages/index/index.js Page({ data: { from: , to: , date: }, onFromInput(e) { this.setData({ from: e.detail.value.trim() }); }, onDateChange(e) { this.setData({ date: e.detail.value }); }, onQuery() { const { from, to, date } this.data; if (!from || !to || !date) { wx.showToast({ title: 請?zhí)顚懲暾? icon: none }); return; } wx.navigateTo({ url: /pages/result/result?from${from}to${to}date${date} }); } });setData是小程序更新視圖的核心方法這里把輸入值同步到data。onQuery里先做空值判斷再用模板字符串拼 URL。注意from和to如果包含特殊字符需要encodeURIComponent處理否則跳轉后參數(shù)會截斷。日期選擇器返回的是YYYY-MM-DD格式正好符合大多數(shù)查詢接口的要求。2.3 網(wǎng)絡請求封裝wx.request 與公共配置查詢請求放在result.js的onLoad里。項目里把請求域名和路徑抽到了utils/config.js這樣換接口時不用翻遍所有頁面。// utils/config.js const BASE_URL https://api.example.com; // 替換成實際可用的查詢接口 module.exports { QUERY_TRAINS: ${BASE_URL}/train/query };// pages/result/result.js const config require(../../utils/config.js); Page({ data: { trains: [], loading: true }, onLoad(options) { const { from, to, date } options; this.queryTrains(from, to, date); }, queryTrains(from, to, date) { wx.request({ url: config.QUERY_TRAINS, method: GET, data: { from, to, date }, success: (res) { if (res.data res.data.code 0) { this.setData({ trains: res.data.list, loading: false }); } else { wx.showToast({ title: 查詢失敗, icon: none }); } }, fail: () { wx.showToast({ title: 網(wǎng)絡異常, icon: none }); } }); } });wx.request的data字段會自動拼成查詢字符串不用手動拼接。success里先判斷業(yè)務狀態(tài)碼再取list賦值給trains。這里有個細節(jié)如果接口返回的字段名不是list需要同步改setData的鍵名。fail回調處理網(wǎng)絡層錯誤比如域名未配置或超時。注意小程序正式環(huán)境要求 HTTPS 域名開發(fā)時可以在開發(fā)者工具里勾選「不校驗合法域名」臨時繞過。2.4 列表渲染wx:for 與余票狀態(tài)展示拿到數(shù)據(jù)后result.wxml用wx:for渲染車次列表。每個車次顯示車次號、出發(fā)到達時間、歷時和余票狀態(tài)。view wx:if{{loading}}加載中.../view view wx:else view wx:for{{trains}} wx:keytrainNo classtrain-item text{{item.trainNo}}/text text{{item.fromTime}} - {{item.toTime}}/text text{{item.duration}}/text text class{{item.seatCount 0 ? has-seat : no-seat}} {{item.seatCount 0 ? 有票 : 無票}} /text /view /viewwx:key用trainNo保證列表更新時不會錯位。余票狀態(tài)用三元表達式切換 classhas-seat和no-seat在wxss里定義顏色。如果接口返回的余票是數(shù)字直接比較如果是字符串「有」「無」需要改判斷條件。這里我一般會加一個item.seatCount的默認值防止字段缺失導致渲染空白。3. 核心模塊拆解查詢參數(shù)處理與數(shù)據(jù)映射3.1 車站數(shù)據(jù)本地字典與拼音匹配火車票查詢有個繞不開的問題用戶輸入「北京」還是「北京西」項目里用了一個本地車站字典放在utils/stations.js把常用車站名和拼音縮寫都列出來。// utils/stations.js const stations [ { name: 北京, code: BJP, pinyin: beijing }, { name: 北京西, code: BXP, pinyin: beijingxi }, { name: 上海, code: SHH, pinyin: shanghai }, { name: 廣州, code: GZQ, pinyin: guangzhou } ]; module.exports stations;查詢前先用stations.find把用戶輸入轉成車站代碼再傳給接口。如果找不到匹配項就提示「車站不存在」。這個字典可以按需擴充但注意代碼要和接口要求的一致不同數(shù)據(jù)源可能用不同的三字碼。我一般會把字典單獨維護不混在頁面邏輯里方便后續(xù)替換成遠程接口。3.2 日期格式化補零與接口兼容日期選擇器返回的格式是YYYY-MM-DD但有些接口要求YYYYMMDD。項目里在utils/util.js寫了一個轉換函數(shù)。// utils/util.js function formatDate(dateStr) { return dateStr.replace(/-/g, ); } module.exports { formatDate };調用時formatDate(2025-01-01)返回20250101。如果接口要求帶時間戳可以再包一層new Date(dateStr).getTime()。注意時區(qū)問題小程序運行在用戶設備上new Date會按本地時區(qū)解析跨時區(qū)場景要統(tǒng)一用 UTC。3.3 請求參數(shù)組裝從頁面到接口的完整鏈路把前面的步驟串起來result.js里實際組裝參數(shù)的邏輯是這樣的const stations require(../../utils/stations.js); const { formatDate } require(../../utils/util.js); queryTrains(from, to, date) { const fromStation stations.find(s s.name from || s.pinyin from); const toStation stations.find(s s.name to || s.pinyin to); if (!fromStation || !toStation) { wx.showToast({ title: 車站名有誤, icon: none }); return; } wx.request({ url: config.QUERY_TRAINS, data: { from: fromStation.code, to: toStation.code, date: formatDate(date) }, // ... 成功失敗回調同上 }); }這里先做車站匹配支持中文名和拼音兩種輸入。find返回第一個匹配項如果有重名車站比如「北京」和「北京西」都包含「北京」需要更精確的匹配規(guī)則比如優(yōu)先完全相等。日期轉換放在請求前保證接口收到的格式統(tǒng)一。如果接口返回的車次字段和頁面渲染字段不一致可以在success里做一層映射把train_code轉成trainNo之類的。4. 避坑與排查調試查詢功能時容易翻車的幾個點4.1 現(xiàn)象開發(fā)者工具里請求成功真機預覽失敗原因小程序正式環(huán)境要求請求域名在后臺配置白名單且必須是 HTTPS。開發(fā)者工具默認不校驗真機走嚴格模式。解決在微信公眾平臺后臺「開發(fā)管理」里添加 request 合法域名。如果只是本地調試可以在開發(fā)者工具「詳情」里勾選「不校驗合法域名、web-view業(yè)務域名、TLS 版本以及 HTTPS 證書」。但上線前必須配好域名否則用戶端會直接報錯。4.2 現(xiàn)象列表渲染出來但余票狀態(tài)全是「無票」原因接口返回的余票字段可能是字符串0或有而代碼里用 0比較字符串和數(shù)字比較會觸發(fā)隱式轉換但有 0是false。解決先打印res.data.list看實際字段類型。如果是字符串用item.seatCount ! 0或parseInt(item.seatCount) 0。我一般會在setData之前做一次數(shù)據(jù)清洗把余票統(tǒng)一轉成數(shù)字。4.3 現(xiàn)象跳轉結果頁后參數(shù)丟失或亂碼原因URL 拼接時沒有對中文或特殊字符做編碼wx.navigateTo的url長度也有限制。解決用encodeURIComponent包一層接收時用decodeURIComponent還原。如果參數(shù)很多可以只傳一個 ID在結果頁重新請求詳情。另外注意url最大長度是 1024 字節(jié)超長會跳轉失敗。4.4 現(xiàn)象查詢接口返回 403 或頻繁超時原因部分公開接口有頻率限制或需要特定請求頭比如Referer或User-Agent。解決小程序wx.request不能自定義User-Agent但可以加header字段。如果接口對來源校驗嚴格建議換一個穩(wěn)定的數(shù)據(jù)源或者自己搭一層后端轉發(fā)。不要在小程序里硬編碼密鑰容易被反編譯。4.5 現(xiàn)象日期選擇器在 iOS 上顯示英文原因picker組件的語言跟隨系統(tǒng)iOS 某些版本會顯示英文月份。解決這是系統(tǒng)級行為不影響功能。如果必須統(tǒng)一中文可以用自定義 picker 或第三方組件庫。我一般接受這個差異因為用戶對日期格式的敏感度不高。5. 二次開發(fā)與改造從查詢工具到可復用的數(shù)據(jù)面板這個項目最值錢的地方不是查詢本身而是它把「輸入 → 請求 → 渲染」這條鏈路跑通了。如果你想把它改成別的查詢工具比如航班、汽車票、快遞只需要換三樣東西車站字典、接口地址、列表字段映射。我一般會先把utils/config.js里的BASE_URL抽成環(huán)境變量用wx.getAccountInfoSync判斷開發(fā)版還是正式版分別指向測試和線上接口。// utils/config.js 改造版 const env wx.getAccountInfoSync().miniProgram.envVersion; const BASE_URL env develop ? https://test-api.example.com : https://api.example.com; module.exports { QUERY_TRAINS: ${BASE_URL}/train/query };這樣切環(huán)境不用改代碼提交審核前也不會誤連測試數(shù)據(jù)。另一個改造點是加緩存。查詢結果可以按fromtodate存到wx.setStorageSync下次相同條件先讀緩存減少請求次數(shù)。注意緩存要設過期時間火車票余票變化快建議 5 分鐘失效。const cacheKey train_${from}_${to}_${date}; const cached wx.getStorageSync(cacheKey); if (cached Date.now() - cached.time 5 * 60 * 1000) { this.setData({ trains: cached.list, loading: false }); return; } // 請求成功后寫入緩存 wx.setStorageSync(cacheKey, { list: res.data.list, time: Date.now() });如果你想讓列表支持下拉刷新在result.json里加enablePullDownRefresh: true然后在onPullDownRefresh里重新調用queryTrains完成后wx.stopPullDownRefresh()。這個改動很小但體驗提升明顯。最后說一個我踩過的坑不要直接把接口返回的整個對象塞進setData數(shù)據(jù)量大的時候會觸發(fā)性能警告。只取渲染需要的字段比如trainNo、fromTime、toTime、seatCount其他字段留在內存里備用。從那以后我每次做列表渲染都強制走一遍字段裁剪希望幫到你。本文還有配套的精品資源點擊獲取