戰(zhàn):從零構(gòu)建仿京東商城APP的架構(gòu)設(shè)計(jì)與核心實(shí)現(xiàn))
簡(jiǎn)介這是一套基于Vue 2開(kāi)發(fā)的仿京東商城移動(dòng)端前端項(xiàng)目實(shí)戰(zhàn)源碼專(zhuān)為高校前端課程期末大作業(yè)、畢業(yè)設(shè)計(jì)及初學(xué)者進(jìn)階實(shí)踐打造。項(xiàng)目覆蓋首頁(yè)、商品列表、詳情頁(yè)、購(gòu)物車(chē)、用戶(hù)中心等核心模塊采用Vue CLI腳手架構(gòu)建集成Vue Router、Vuex及Axios等主流生態(tài)工具具備完整可運(yùn)行結(jié)構(gòu)與清晰分層邏輯。壓縮包共81個(gè)文件含9個(gè)核心.vue組件文件、13個(gè).js業(yè)務(wù)邏輯與配置腳本、7個(gè).css樣式文件、21個(gè).png與8個(gè).jpg資源圖以及配套R(shí)EADME.md說(shuō)明文檔和.gitignore等工程規(guī)范文件整體僅1.31MB輕量易部署。目前已有1608人學(xué)習(xí)下載讀者可直接導(dǎo)入運(yùn)行、調(diào)試分析組件通信與狀態(tài)管理機(jī)制并參考目錄結(jié)構(gòu)含src、public、dist及babel.config.js等標(biāo)準(zhǔn)Vue2工程配置快速掌握企業(yè)級(jí)單頁(yè)應(yīng)用開(kāi)發(fā)流程與代碼組織范式。1. 從零到一為什么選擇Vue復(fù)刻京東商城APP最近幾年前端技術(shù)棧的迭代速度讓人眼花繚亂但無(wú)論怎么變Vue.js憑借其漸進(jìn)式的設(shè)計(jì)理念和極佳的上手體驗(yàn)始終是快速構(gòu)建現(xiàn)代化Web應(yīng)用的首選框架之一。對(duì)于想深入前端工程化、提升實(shí)戰(zhàn)能力的開(kāi)發(fā)者來(lái)說(shuō)找一個(gè)有足夠復(fù)雜度和業(yè)務(wù)深度的項(xiàng)目來(lái)練手是突破瓶頸的關(guān)鍵。而“仿京東商城APP”這個(gè)選題恰好踩在了這個(gè)痛點(diǎn)上。它不是一個(gè)簡(jiǎn)單的TODO List或者博客后臺(tái)而是一個(gè)涵蓋了商品展示、購(gòu)物車(chē)、訂單、支付模擬、用戶(hù)中心等完整電商核心鏈路的綜合性項(xiàng)目。通過(guò)復(fù)刻這樣一個(gè)大家耳熟能詳?shù)膽?yīng)用你不僅能系統(tǒng)性地串聯(lián)起Vue的核心知識(shí)組件化、狀態(tài)管理、路由、生命周期等更能直面真實(shí)業(yè)務(wù)場(chǎng)景下的技術(shù)挑戰(zhàn)比如復(fù)雜組件通信、狀態(tài)持久化、性能優(yōu)化和移動(dòng)端適配。我之所以推薦這個(gè)項(xiàng)目是因?yàn)樗槿鸽m小五臟俱全。你不需要從零設(shè)計(jì)業(yè)務(wù)邏輯京東APP本身就是最好的產(chǎn)品原型和交互規(guī)范。你的精力可以完全聚焦在技術(shù)實(shí)現(xiàn)上如何用Vue 3的Composition API優(yōu)雅地組織代碼如何用Pinia管理跨組件的購(gòu)物車(chē)狀態(tài)如何實(shí)現(xiàn)一個(gè)流暢的樓層滾動(dòng)導(dǎo)航如何優(yōu)化長(zhǎng)列表圖片的懶加載這些問(wèn)題都會(huì)在開(kāi)發(fā)過(guò)程中一一浮現(xiàn)并得到解決。完成這個(gè)項(xiàng)目后你收獲的將不僅僅是一個(gè)可以寫(xiě)進(jìn)簡(jiǎn)歷的“項(xiàng)目經(jīng)驗(yàn)”更是一套解決復(fù)雜前端問(wèn)題的思維方法和工程實(shí)踐能力。接下來(lái)我將以一個(gè)完整的實(shí)戰(zhàn)視角帶你拆解這個(gè)項(xiàng)目的構(gòu)建全過(guò)程并分享那些官方文檔里不會(huì)寫(xiě)的“踩坑”經(jīng)驗(yàn)。2. 項(xiàng)目架構(gòu)設(shè)計(jì)與技術(shù)選型背后的思考在動(dòng)手寫(xiě)第一行代碼之前花時(shí)間在架構(gòu)設(shè)計(jì)上是絕對(duì)值得的。一個(gè)好的起點(diǎn)能避免后期大量的重構(gòu)和“屎山”代碼。對(duì)于這個(gè)Vue仿京東項(xiàng)目我們的目標(biāo)是構(gòu)建一個(gè)清晰、可維護(hù)、易于擴(kuò)展的現(xiàn)代前端應(yīng)用。2.1 技術(shù)棧的確定與理由首先我們鎖定核心框架為Vue 3。雖然Vue 2仍有大量存量項(xiàng)目但Vue 3的Composition API在邏輯復(fù)用和組織復(fù)雜組件方面具有天然優(yōu)勢(shì)這是未來(lái)趨勢(shì)。構(gòu)建工具選擇Vite而非傳統(tǒng)的Webpack。Vite的閃電般冷啟動(dòng)和熱更新速度能在開(kāi)發(fā)階段極大提升幸福感其基于ES Module的按需編譯也更為現(xiàn)代。狀態(tài)管理是電商項(xiàng)目的重中之重。購(gòu)物車(chē)狀態(tài)、用戶(hù)登錄態(tài)、全局配置等都需要在多個(gè)組件間共享和持久化。這里我強(qiáng)烈推薦Pinia作為Vue的官方狀態(tài)管理庫(kù)。相比VuexPinia的API更簡(jiǎn)潔完美支持TypeScript并且沒(méi)有冗長(zhǎng)的mutations概念直接修改state和調(diào)用actions即可心智負(fù)擔(dān)更小。對(duì)于這個(gè)項(xiàng)目我們至少需要定義以下幾個(gè)storeuseCartStore: 管理購(gòu)物車(chē)商品增刪改查、選中狀態(tài)、計(jì)算總價(jià)。useUserStore: 管理用戶(hù)登錄態(tài)、token、個(gè)人信息。useGlobalStore: 管理一些全局UI狀態(tài)如加載中、彈窗提示等。路由管理使用Vue Router 4。電商APP的頁(yè)面結(jié)構(gòu)相對(duì)固定通常包括首頁(yè)、商品分類(lèi)頁(yè)、商品詳情頁(yè)、購(gòu)物車(chē)頁(yè)、訂單確認(rèn)頁(yè)、個(gè)人中心頁(yè)等。我們需要設(shè)計(jì)好路由結(jié)構(gòu)并特別注意路由守衛(wèi)的設(shè)置例如未登錄用戶(hù)訪(fǎng)問(wèn)訂單頁(yè)時(shí)需要跳轉(zhuǎn)到登錄頁(yè)。UI框架的選擇見(jiàn)仁見(jiàn)智。為了更貼近原生APP的體驗(yàn)和獲得最大的定制靈活性這個(gè)項(xiàng)目我建議不引入完整的UI組件庫(kù)如Element Plus而是采用“基礎(chǔ)樣式框架 自定義組件”的模式。我們可以使用UnoCSS或Tailwind CSS這類(lèi)原子化CSS框架來(lái)快速構(gòu)建樣式它們能提供極高的開(kāi)發(fā)效率和一致性。對(duì)于復(fù)雜的業(yè)務(wù)組件如商品卡片、地址選擇器、優(yōu)惠券彈窗則完全自己手寫(xiě)這樣能保證樣式和交互與京東APP高度一致且打包體積更小。2.2 目錄結(jié)構(gòu)規(guī)劃清晰的目錄結(jié)構(gòu)是項(xiàng)目可維護(hù)性的基石。我推薦如下結(jié)構(gòu)src/ ├── api/ # 所有接口請(qǐng)求封裝按模塊劃分 ├── assets/ # 靜態(tài)資源圖片、字體、樣式 ├── components/ # 公共業(yè)務(wù)組件 │ ├── common/ # 全局通用組件如NavBar, TabBar, Loading │ └── business/ # 業(yè)務(wù)組件如GoodsCard, SkuSelector ├── composables/ # Vue 3組合式函數(shù)邏輯復(fù)用 ├── router/ # 路由配置 ├── stores/ # Pinia狀態(tài)管理 ├── types/ # TypeScript類(lèi)型定義 ├── utils/ # 工具函數(shù) ├── views/ # 頁(yè)面級(jí)組件 └── App.vue main.ts關(guān)鍵點(diǎn)解析api/目錄這里不是簡(jiǎn)單放請(qǐng)求函數(shù)。我會(huì)為每個(gè)業(yè)務(wù)模塊創(chuàng)建一個(gè)文件如home.ts,product.ts,cart.ts并使用axios創(chuàng)建實(shí)例統(tǒng)一配置攔截器處理請(qǐng)求loading、錯(cuò)誤提示、token注入等。這是與后端協(xié)作的邊界保持清晰至關(guān)重要。composables/目錄這是Vue 3的精髓。我們會(huì)把可復(fù)用的邏輯抽離成組合式函數(shù)例如useScrollLoad滾動(dòng)加載、useImageLazyLoad圖片懶加載、useCountDown倒計(jì)時(shí)。這能讓我們的組件代碼保持清爽。types/目錄即使你不用TypeScript也建議用JSDoc簡(jiǎn)單定義主要的數(shù)據(jù)結(jié)構(gòu)。比如商品GoodsItem、購(gòu)物車(chē)項(xiàng)CartItem的類(lèi)型這能極大減少因字段名拼寫(xiě)錯(cuò)誤導(dǎo)致的bug。2.3 移動(dòng)端適配方案我們的目標(biāo)是仿APP因此必須在移動(dòng)端有完美的表現(xiàn)。核心是視口配置和REM適配。首先在index.html的head中確保有標(biāo)準(zhǔn)的移動(dòng)端視口標(biāo)簽meta nameviewport contentwidthdevice-width, initial-scale1.0, maximum-scale1.0, user-scalableno, viewport-fitcoverviewport-fitcover對(duì)于劉海屏手機(jī)的全屏適配很重要。其次使用REM適配不同屏幕尺寸。我們可以在main.ts或一個(gè)獨(dú)立的工具文件中加入以下代碼// 設(shè)置根元素字體大小設(shè)計(jì)稿以375px寬度為基準(zhǔn) const setRem () { const docEl document.documentElement; const clientWidth docEl.clientWidth; // 375px設(shè)計(jì)稿下1rem 100px便于計(jì)算如設(shè)計(jì)稿上20px代碼寫(xiě)0.2rem const rem (clientWidth / 3.75); docEl.style.fontSize ${rem}px; }; // 初始化執(zhí)行 setRem(); // 窗口變化時(shí)重置 window.addEventListener(resize, setRem);這樣在CSS中我們就可以用rem單位來(lái)寫(xiě)尺寸了。例如設(shè)計(jì)稿上一個(gè)寬為100px的按鈕在CSS中就可以寫(xiě)成width: 1rem;。搭配PostCSS插件postcss-pxtorem可以自動(dòng)將我們寫(xiě)的px單位轉(zhuǎn)換為rem開(kāi)發(fā)體驗(yàn)更佳。注意在引入第三方UI組件庫(kù)時(shí)如果其樣式未使用REM可能會(huì)產(chǎn)生適配問(wèn)題。這就是為什么我建議核心UI自己實(shí)現(xiàn)可以完全掌控樣式。3. 核心頁(yè)面實(shí)現(xiàn)與關(guān)鍵技術(shù)點(diǎn)拆解有了扎實(shí)的架構(gòu)基礎(chǔ)我們就可以開(kāi)始逐個(gè)攻破核心頁(yè)面了。首頁(yè)、商品詳情頁(yè)和購(gòu)物車(chē)是電商APP的三大支柱也是最體現(xiàn)技術(shù)復(fù)雜度的部分。3.1 首頁(yè)性能優(yōu)化與交互體驗(yàn)的戰(zhàn)場(chǎng)首頁(yè)通常由多個(gè)“樓層”組成如輪播圖、金剛區(qū)、秒殺板塊、推薦商品流等。這里最大的挑戰(zhàn)是性能和復(fù)雜交互。1. 圖片懶加載與占位首頁(yè)圖片資源多必須做懶加載。我們可以使用Vue的自定義指令v-lazy或者更簡(jiǎn)單的利用原生Intersection Observer API自己封裝一個(gè)useImageLazyLoad組合式函數(shù)。核心思路是當(dāng)圖片元素進(jìn)入視口時(shí)才將其>import { ref, onMounted, onUnmounted } from vue; export function useInfiniteScroll(loadMore) { const loading ref(false); const noMore ref(false); const checkBottom () { const scrollTop document.documentElement.scrollTop || document.body.scrollTop; const clientHeight document.documentElement.clientHeight; const scrollHeight document.documentElement.scrollHeight; // 距離底部50px時(shí)觸發(fā)加載 if (scrollTop clientHeight scrollHeight - 50 !loading.value !noMore.value) { loading.value true; loadMore().finally(() { loading.value false; }); } }; onMounted(() { window.addEventListener(scroll, checkBottom); }); onUnmounted(() { window.removeEventListener(scroll, checkBottom); }); return { loading, noMore }; }在商品列表組件中調(diào)用這個(gè)函數(shù)并傳入加載數(shù)據(jù)的異步方法即可。記得在接口返回?cái)?shù)據(jù)后判斷是否已無(wú)更多數(shù)據(jù)來(lái)設(shè)置noMore.value true。3.2 商品詳情頁(yè)復(fù)雜狀態(tài)與動(dòng)態(tài)交互商品詳情頁(yè)是轉(zhuǎn)化率的核心其技術(shù)難點(diǎn)在于SKU選擇器和加入購(gòu)物車(chē)的狀態(tài)管理。1. SKU選擇器的實(shí)現(xiàn)SKU庫(kù)存量單位選擇器是電商詳情頁(yè)最復(fù)雜的組件之一。用戶(hù)選擇不同的規(guī)格如顏色、尺寸會(huì)影響價(jià)格、庫(kù)存以及可選的其它規(guī)格。其核心數(shù)據(jù)結(jié)構(gòu)通常是一個(gè)樹(shù)或圖。一個(gè)相對(duì)簡(jiǎn)單的實(shí)現(xiàn)思路是后端返回所有SKU的列表以及規(guī)格名和規(guī)格值的映射關(guān)系。前端需要計(jì)算出一個(gè)“規(guī)格狀態(tài)矩陣”。當(dāng)用戶(hù)選中某個(gè)規(guī)格值時(shí)需要遍歷所有SKU找出同時(shí)包含已選規(guī)格值的SKU集合然后根據(jù)這個(gè)集合來(lái)判定其他未選的規(guī)格值是否可用有庫(kù)存。組件UI上對(duì)于不可用的規(guī)格值要置灰并禁用點(diǎn)擊。這個(gè)組件邏輯復(fù)雜我強(qiáng)烈建議將其單獨(dú)抽離成一個(gè)SkuSelector.vue組件并使用Pinia或provide/inject來(lái)管理其內(nèi)部狀態(tài)避免與詳情頁(yè)其他邏輯耦合過(guò)深。2. 購(gòu)物車(chē)浮層與立即購(gòu)買(mǎi)點(diǎn)擊“加入購(gòu)物車(chē)”通常會(huì)彈出一個(gè)小浮層展示商品信息和已選規(guī)格并允許修改數(shù)量。這個(gè)浮層組件的狀態(tài)顯示/隱藏、商品信息、選中規(guī)格、數(shù)量需要是全局可管理的因?yàn)榭赡軓脑斍轫?yè)的多個(gè)入口如底部欄、商品圖旁的按鈕觸發(fā)。我們可以將其狀態(tài)放在useGlobalStore中或者使用Vue 3的Teleport組件將其掛載到body下避免層級(jí)樣式問(wèn)題?!傲⒓促?gòu)買(mǎi)”的流程則不同它通常不經(jīng)過(guò)購(gòu)物車(chē)而是直接跳轉(zhuǎn)到訂單確認(rèn)頁(yè)。這里需要將當(dāng)前選中的商品信息規(guī)格、數(shù)量作為一個(gè)臨時(shí)訂單數(shù)據(jù)通過(guò)路由參數(shù)或狀態(tài)管理傳遞到下一個(gè)頁(yè)面。3.3 購(gòu)物車(chē)頁(yè)狀態(tài)管理的核心實(shí)踐購(gòu)物車(chē)頁(yè)是檢驗(yàn)?zāi)銧顟B(tài)管理方案設(shè)計(jì)是否合理的“試金石”。它需要處理商品列表的展示圖片、名稱(chēng)、規(guī)格、價(jià)格、數(shù)量。單選、全選與反選邏輯。實(shí)時(shí)計(jì)算選中商品的總價(jià)和總數(shù)量。商品數(shù)量的增減并有最小值和庫(kù)存限制。刪除商品。Pinia Store設(shè)計(jì)示例 (stores/cart.ts):import { defineStore } from pinia; import { ref, computed } from vue; export interface CartItem { id: string; // 購(gòu)物車(chē)項(xiàng)唯一ID goodsId: string; // 商品ID skuId: string; // SKU ID name: string; image: string; price: number; spec: string; // 規(guī)格文本如“黑色 XL” count: number; stock: number; // 當(dāng)前庫(kù)存 selected: boolean; } export const useCartStore defineStore(cart, () { // 狀態(tài) const items refCartItem[]([]); // Getter (計(jì)算屬性) const selectedItems computed(() items.value.filter(item item.selected)); const totalPrice computed(() selectedItems.value.reduce((sum, item) sum item.price * item.count, 0)); const totalCount computed(() selectedItems.value.reduce((sum, item) sum item.count, 0)); const isAllSelected computed(() items.value.length 0 items.value.every(item item.selected)); // Actions (操作方法) const toggleSelect (id: string) { const item items.value.find(i i.id id); if (item) item.selected !item.selected; }; const toggleSelectAll (selected: boolean) { items.value.forEach(item { item.selected selected; }); }; const updateCount (id: string, newCount: number) { const item items.value.find(i i.id id); if (item) { // 邊界檢查 if (newCount 1) newCount 1; if (newCount item.stock) newCount item.stock; item.count newCount; } }; const removeItem (id: string) { const index items.value.findIndex(i i.id id); if (index -1) items.value.splice(index, 1); }; // ... 還有添加商品、清空購(gòu)物車(chē)等方法 return { items, selectedItems, totalPrice, totalCount, isAllSelected, toggleSelect, toggleSelectAll, updateCount, removeItem, }; });在購(gòu)物車(chē)頁(yè)面組件中我們可以直接導(dǎo)入并使用這個(gè)store。計(jì)算屬性和方法讓我們的視圖代碼變得非常簡(jiǎn)潔和響應(yīng)式。踩坑提示購(gòu)物車(chē)數(shù)據(jù)的持久化。用戶(hù)刷新頁(yè)面后購(gòu)物車(chē)不能清空。我們可以在Pinia Store中利用persist插件如pinia-plugin-persistedstate將items狀態(tài)自動(dòng)持久化到localStorage。但要注意商品價(jià)格和庫(kù)存信息可能會(huì)變所以更佳實(shí)踐是在每次進(jìn)入購(gòu)物車(chē)頁(yè)面時(shí)從服務(wù)器同步一次最新數(shù)據(jù)合并本地選中狀態(tài)。4. 開(kāi)發(fā)流程、調(diào)試與部署上線(xiàn)當(dāng)核心功能模塊開(kāi)發(fā)完畢后我們需要關(guān)注如何高效地協(xié)作、調(diào)試并最終將項(xiàng)目發(fā)布出去。4.1 接口模擬與聯(lián)調(diào)策略在真實(shí)后端接口未就緒時(shí)前端獨(dú)立開(kāi)發(fā)離不開(kāi)Mock數(shù)據(jù)。我不推薦在代碼里寫(xiě)死一堆json對(duì)象而是建議使用專(zhuān)業(yè)的Mock工具。這里推薦Mock Service Worker (MSW)。它是一個(gè)基于Service Worker的API Mock庫(kù)可以攔截瀏覽器發(fā)出的fetch或XMLHttpRequest請(qǐng)求并返回我們定義的模擬響應(yīng)。它的好處是無(wú)侵入性你的業(yè)務(wù)代碼axios請(qǐng)求完全不用改就像在請(qǐng)求真實(shí)后端一樣。靈活可以模擬網(wǎng)絡(luò)延遲、錯(cuò)誤狀態(tài)404 500??汕袚Q上線(xiàn)時(shí)只需移除MSW的初始化代碼即可無(wú)縫切換到真實(shí)后端。配置示例// src/mocks/handlers.js import { rest } from msw; export const handlers [ rest.get(/api/goods/list, (req, res, ctx) { return res( ctx.delay(300), // 模擬300ms延遲 ctx.json({ code: 200, data: [...], // 你的模擬商品列表數(shù)據(jù) }) ); }), // ... 更多接口 ]; // src/mocks/browser.js import { setupWorker } from msw; import { handlers } from ./handlers; export const worker setupWorker(...handlers); // 在main.ts中僅在開(kāi)發(fā)環(huán)境啟動(dòng) if (process.env.NODE_ENV development) { const { worker } require(./mocks/browser); worker.start(); }4.2 移動(dòng)端真機(jī)調(diào)試技巧在瀏覽器開(kāi)發(fā)工具中模擬移動(dòng)設(shè)備是不夠的真機(jī)上的表現(xiàn)往往會(huì)有差異。這里有幾個(gè)高效的真機(jī)調(diào)試方法使用本地IP訪(fǎng)問(wèn)運(yùn)行npm run dev后Vite會(huì)輸出一個(gè)本地網(wǎng)絡(luò)IP如http://192.168.1.100:5173。確保手機(jī)和電腦在同一Wi-Fi下用手機(jī)瀏覽器訪(fǎng)問(wèn)這個(gè)地址即可。Chrome Remote Debugging (Android)用USB連接安卓手機(jī)在Chrome瀏覽器地址欄輸入chrome://inspect/#devices勾選“Discover USB devices”你的手機(jī)網(wǎng)頁(yè)就會(huì)出現(xiàn)在列表中點(diǎn)擊inspect即可打開(kāi)一個(gè)和電腦上幾乎一樣的開(kāi)發(fā)者工具。Safari Web Inspector (iOS)在iPhone的“設(shè)置 Safari 高級(jí)”中打開(kāi)“Web檢查器”。用USB連接Mac在Mac的Safari“開(kāi)發(fā)”菜單中就能找到你的設(shè)備進(jìn)行調(diào)試。Vite Console在手機(jī)上訪(fǎng)問(wèn)時(shí)打開(kāi)Vite客戶(hù)端控制臺(tái)通常是http://localhost:5173/vite/client可以看到一些HMR日志對(duì)于調(diào)試熱更新失敗很有幫助。4.3 構(gòu)建優(yōu)化與部署開(kāi)發(fā)完成后使用npm run build進(jìn)行構(gòu)建。Vite默認(rèn)會(huì)輸出高度優(yōu)化的靜態(tài)文件。但為了獲得最佳性能我們還可以做以下事情分析打包體積使用rollup-plugin-visualizer插件生成一個(gè)可視化的依賴(lài)分析圖找出體積過(guò)大的包考慮是否可以用更輕量的庫(kù)替代或者進(jìn)行按需引入。配置公共路徑如果你的項(xiàng)目不是部署在域名的根目錄下例如https://yourdomain.com/mall/需要在vite.config.ts中配置base: /mall/否則資源路徑會(huì)出錯(cuò)。部署到靜態(tài)托管服務(wù)構(gòu)建出的dist文件夾可以直接部署到任何靜態(tài)網(wǎng)站托管服務(wù)如Vercel、Netlify、GitHub Pages或你自己的Nginx服務(wù)器。Vercel/Netlify關(guān)聯(lián)你的Git倉(cāng)庫(kù)它們會(huì)自動(dòng)檢測(cè)Vite項(xiàng)目并完成構(gòu)建和部署還提供全球CDN和自動(dòng)HTTPS非常適合個(gè)人項(xiàng)目演示。Nginx配置一個(gè)簡(jiǎn)單的配置示例如下server { listen 80; server_name yourdomain.com; root /path/to/your/dist; index index.html; # 支持Vue Router的history模式 location / { try_files $uri $uri/ /index.html; } # 緩存靜態(tài)資源 location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg)$ { expires 1y; add_header Cache-Control public, immutable; } }關(guān)鍵點(diǎn)是try_files $uri $uri/ /index.html;它讓所有前端路由都回退到index.html由Vue Router來(lái)處理。完成部署后別忘了在手機(jī)瀏覽器中全面測(cè)試一遍所有核心流程從首頁(yè)瀏覽到下單確保在真實(shí)網(wǎng)絡(luò)環(huán)境下的體驗(yàn)流暢。至此一個(gè)完整的、可用于學(xué)習(xí)和展示的Vue仿京東商城APP項(xiàng)目就真正從零到一地構(gòu)建起來(lái)了。這個(gè)過(guò)程充滿(mǎn)挑戰(zhàn)但每一步問(wèn)題的解決都會(huì)讓你的前端功力更扎實(shí)一分。本文還有配套的精品資源點(diǎn)擊獲取