從零到部署:用 Vue 和 Express 實現迷你全棧電商應用(一)

tuture發表於2020-04-11

Vue 是尤雨溪在 2014 年建立的一個前端框架,目前 Github Star 數高達 150K,是 Star 數最高的前端專案,並且 Vue 有著極為活躍的社群生態以及專職團隊進行維護以確保專案可以健康長久地發展。

目前中國很多網際網路公司前端程式設計師的招聘要求都要求程式設計師掌握 Vue,像滴滴、美團、餓了麼等大廠也在重度使用 Vue 進行開發,並且有著像 ElementmpvueiView 這樣優秀的基於 Vue 開源專案存在,所以學習 Vue 是一個不錯的投資,當你學會 Vue,就可以快速開發專案,這樣不僅可以接外包掙外快,而且當有了一定的專案經驗,還可以在一線網際網路大廠找到一份不錯的工作。

看到這裡你心動了嘛?心動不如行動!而最幸運的是,本教程將會一步一步帶你以實戰的方式實現一個迷你全棧電商網站。並在實戰的過程中,瞭解 Vue 的全貌,現在就開啟電腦,跟隨我的腳步,徹底掌握 Vue 開發!

歡迎閱讀《從零到部署:用 Vue 和 Express 實現迷你全棧電商應用》系列:

如果您覺得我們的教程寫得還不錯,請記得給我們點個贊哦!鼓勵我們更快更好地寫完剩下的教程!你也可以在評論區留言,告訴我們想要實現什麼功能,我們一定會仔細考慮的哦!

快速入門

程式碼

你可以在 Github 檢視本教程最終的原始碼:原始碼地址

專案準備

安裝依賴

安裝 Node.js,你可以去 Node.js 官網下載安裝包,通過安裝包安裝會同時安裝 Node.js 包管理工具 Npm,用於便捷的管理專案依賴和下載第三方包。

開啟終端,輸入如下命令測試是否安裝成功:

node -v # v10.16.0
npm -v # 6.9.0

如果在你的終端有如上輸出,那麼代表你安裝成功。

提示

通過上面安裝包安裝,你會安裝最新的 Node 穩定版本,這可能和我的機器上的 Node 版本不一致,但是不用擔心,本教程使用到的程式碼語法適用於絕大多數新的或更老的 Node。

安裝 vue-cli,在絕大多數場景下,我們使用 vue-cli 來初始化我們的 vue 專案,本教程也不例外,在終端執行如下命令來安裝:

npm install -g vue-cli

開啟終端,輸入如下命令測試是否安裝成功:

vue --version # 2.9.6

提示

雖然 Vue 3.x 已經正式推出,但是這篇教程用的是主流、穩定的 Vue 2.x 版本。由於 Vue 的整體思想基本沒有改變,所以不影響我們的學習。在接下來的教程中,我們會遷移到 Vue 3.x,並通過講解新老 Vue 版本的差異讓你更好地理解 Vue 的演變。

上面兩個安裝步驟已經足夠完成我們的教程的學習,但是我想額外推薦你一款編輯器,VSCode,你可以通過訪問 VSCode 官網安裝。

在 VSCode 裡面找到 Vue 外掛,可以獲得程式碼語法高亮以及自動格式化非常便捷的功能,並且 VSCode 天然對 JavaScript 的支援,會大大提高我們的開發效率,本教程所涉及專案的開發都是使用 VSCode 完成的。

初始化專案

開啟終端輸入如下命令初始化我們的 Vue 專案:

vue init webpack vue-online-shop-frontend

命令列接著會顯示一些列選項讓你選擇,具體我們的選擇如下圖:

提示

其中 Author 欄位你可以填自己的暱稱,然後我們在選擇了安裝 vue-router 之後,其他的都選擇了 no,因為本篇教程是面向初學者的實戰教程,如果引入了過多和 Vue 核心無關的概念,就會引起很多困惑,所以這裡我們不配置它們

當專案初始化成功之後,接下來通過如下命令開啟專案:

# code vue-online-shop-frontend # 如果你使用了 VSCode 編輯器,可以用這行命令開啟專案
cd vue-online-shop-frontend && npm start

接著開啟瀏覽器,訪問 http://localhost:8080/ 檢視我們初始好的專案效果。

注意

如果你使用 VSCode 編輯器開啟專案進行開發,在執行 code project-name 之前需要安裝 code 指令碼,具體我找了一篇教程:戳我訪問

初探腳手架程式碼

通過 vue-cli 初始化的腳手架程式碼中,我們在整個教程中需要了解的就是以下五個檔案:

  • src/main.js
  • index.html
  • src/App.vue
  • src/router/index.js
  • src/components/HelloWorld.vue

src/main.js

首先我們來看一下 src/main.js,這個是 Vue 應用的入口。我們通過匯入 Vue 類、App 元件、router 路由,再加上 el ,將這些引數傳給 Vue 類,生成一個 Vue 例項。

// The Vue build version to load with the `import` command
// (runtime-only or standalone) has been set in webpack.base.conf with an alias.
import Vue from 'vue';
import App from './App';
import router from './router';

Vue.config.productionTip = false;

/* eslint-disable no-new */
new Vue({
  el: '#app',
  router,
  components: { App },
  template: '<App/>',
});

index.html

接著我們來看一下 index.html 檔案,它的程式碼是這樣的:

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width,initial-scale=1.0">
    <title>vue-online-shop</title>
  </head>
  <body>
    <div id="app"></div>
    <!-- built files will be auto injected -->
  </body>
</html>

當我們開啟專案之後,Vue 所使用的構建工具 Webpack 將會:

  • 根據入口檔案 src/main.js 裡面宣告的 el 屬性(#app),找到 index.html 中 id 為app 的 DOM 節點
  • 把編譯好的檢視模板程式碼掛載到這個 DOM 節點下面
  • 將專案涉及的 JavaScript 和 CSS 程式碼以 scriptlink 的方式插入到 index.html
  • 開啟開發伺服器,開啟瀏覽器,進而瀏覽器將 index.html 渲染,我們就可以看到寫好的 Vue 頁面效果。

src/App.vue

src/App.vue 就是 Vue 為我們提供的元件檔案,使得我們可以以元件的形式來組織程式碼,並通過元件的組合來構建任意規模的專案,程式碼如下:

<template>
  <div id="app">
    <img src="./assets/logo.png">
    <router-view/>
  </div>
</template>

<script>
export default {
  name: 'App',
};
</script>

<style>
#app {
  font-family: 'Avenir', Helvetica, Arial, sans-serif;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-align: center;
  color: #2c3e50;
  margin-top: 60px;
}
</style>

可以看到, App 元件包含了三個部分的程式碼:

  • template
  • script
  • style

其實就是對應了傳統 Web “三劍客”,HTMLJavaScriptCSS

這裡在 template 部分展示了一張 Vue 的 logo 圖片,然後顯示此刻渲染的路由元件:<router-view />。我們將在後面繼續講解路由,這裡不懂也沒有關係哦。script 部分,主要是匯出了一個名為 App 的元件。style 部分就是我們熟悉的 CSS 程式碼了。

提示

上面所講的是比較小的元件的寫法,當元件中涉及的程式碼較多時,我們需要把 scriptstyle 抽成獨立的 .js.css 檔案。就像下面這樣:

<!-- ./src/App.vue -->
<template>
  <div id="app">
    <img src="./assets/hello.png">
    <router-view/>
  </div>
</template>
<script src="./app.js"></script>
<style src="./app.css"></style>

Vue 元件和模板語法是 Vue 的核心概念,我們在後面會以實戰的形式重點講解這些內容。

src/router/index.js

src/router/index.js 檔案是 Vue 為我們提供的路由檔案,程式碼如下:

import Vue from 'vue';
import Router from 'vue-router';
import HelloWorld from '@/components/HelloWorld';

Vue.use(Router);

export default new Router({
  routes: [
    {
      path: '/',
      name: 'HelloWorld',
      component: HelloWorld,
    },
  ],
});

首先我們匯出了 Vue 類,以及 Router 類,以及我們的 HelloWorld 元件。

接著我們使用 Vue.use(Router) 告訴 Vue,我們應用接入了路由。

在匯出的路由例項中,我們通過 routes 陣列定義了專案所有的頁面,每個頁面是一個類似 { path, name, component } 的物件。

比如初始化時生成的 HelloWorld.vue 就是我們的網站首頁 – 也就是開啟瀏覽器訪問到的第一個頁面,因為它的路徑(path)定義為 / 。此外一個頁面定義還需要 name,它代表此頁面在 vue-router 中的識別符號,component 則代表此頁面渲染時的所用到的元件。

提示

這裡我們可以看到匯出 HelloWorld 元件時,我們在路徑最前面加上了 "@",那是因為我們在 webpack 配置中將會 "@"
對映成 resolve('src'),也就是我們專案目錄下 src 資料夾的路徑,最後我們的 '@/components/HelloWorld' 的實際上的效果相當於取到了專案目錄 src 資料夾裡面的 components/HelloWorld 元件。

src/components/HelloWorld.vue

最後是 src/components/HelloWorld.vue 檔案,是腳手架程式碼為我們提供的一個例項元件,程式碼如下:

<template>
  <div class="hello">
    <h1>{{ msg }}</h1>
    <h2>Essential Links</h2>
    <!-- 省略其他模板程式碼 ... -->
  </div>
</template>

<script>
export default {
  name: 'HelloWorld',
  data() {
    return {
      msg: 'Welcome to Your Vue.js App',
    };
  },
};
</script>

<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped>
h1, h2 {
  font-weight: normal;
}
ul {
  list-style-type: none;
  padding: 0;
}
li {
  display: inline-block;
  margin: 0 10px;
}
a {
  color: #42b983;
}
</style>

可以看到,其結構大致與 App.vue 類似。其中也有一些不同,比如 script 裡面的 data 欄位,還有 template 中的 {{ }} 語法。這個我們會在下一節進行講解。

當我們開啟瀏覽器時,地址為:http://localhost:8080/ 此時路徑為 /,啟用 HelloWorld.vue 元件,所以最後我們整個專案渲染 App.vue 的內容,顯示的結構即為:

  • 一張 Vue logo 圖
  • 我們的 HelloWorld.vue 元件的內容

小結

通過一窺 vue-cli 為我們初始化的專案程式碼,我們可以學到如下的知識:

  • Vue 通過元件來組織專案,單個元件就是我們傳統的 Web “三劍客”:HTML、JavaScript、CSS。
  • Vue 通過路由來定義多個頁面,並且進行頁面之間的跳轉。
  • 一個頁面是一個元件,一個元件可以由很多元件組成,通過這種組合式的思想,我們可以編寫任意複雜的專案。

編寫你的第一個 Vue 頁面

下面我們來編寫電商應用的首頁。

編寫頁面元件

src/components 下面建立 Home.vue 檔案,然後編寫如下程式碼:

<template>
  <div>
    <div class="title">
      <h1>{{msg}}</h1>
    </div>
  </div>
</template>

<script>
  export default {
    name: 'home',
    data () {
      return {
        msg: 'Welcome to Your Vue.js App'
      };
    },
  }
</script>

在上面,我們建立了一個名為 Home.vue 的 Vue 元件,可以看到它和我們之前的 HelloWorld.vue 的內容大致相仿,但是也有一些不同的地方:

  • 首先,我們暫時沒有寫樣式(沒有 style 部分),而是先專注於基礎知識的講解。在後續教程中,我們會使用 Element UI 元件庫讓我們的介面變得專業美觀。
  • 其次,我們在 script 中引入了 data ,在 template 引入了插值語法 {{var}}。其中 data 是宣告此元件的初始化資料,而 {{var}} 插值語法是方便將資料渲染到檢視模板中;這裡我們將在 script 中定義的 data 中的 msg 插值到檢視模板中,最終會渲染一個 h1 標籤,標籤內容就為 msg 的內容。

接入路由

接著,我們在 src/router/index.js 路由中將主頁路由 / 所繫結的元件從預設的 HelloWorld 修改為剛才寫好的 Home 元件:

import Vue from 'vue';
import Router from 'vue-router';
import Home from '@/components/Home';

Vue.use(Router);

export default new Router({
  routes: [
    {
      path: '/',
      name: 'Home',
      component: Home,
    },
  ],
});

現在我們儲存程式碼,開啟瀏覽器,就會顯示剛才在 Home.vue 裡面填寫的那個標題:

使用路由進行多頁面跳轉

一個經典的電商應用通常包括如下部分:

  • 商品展示列表 (Home.vue
  • 商品詳情(Detail.vue
  • 購物車(Cart.vue

這裡因為我們追求簡單,也將商品的後臺管理頁面 (Admin.vue)放入了專案中。

現在我們先來實現商品展示列表、購物車和後臺管理頁面的模板內容。因為商品詳情頁後面將會使用元件進行復用,所以這裡我們暫時先不建立。

新增首頁導航

首先修改 App.vue ,加入三個導航連結 router-link,方便讓使用者跳轉到到自己想看的頁面,程式碼如下:

<template>
  <div id="app">
    <nav>
      <div class="container">
        <ul class="nav__left">
          <li>
            <router-link to="/">Home</router-link>
          </li>
          <li>
            <router-link to="/admin">Admin</router-link>
          </li>
          <li>
            <router-link to="/cart">Cart</router-link>
          </li>
        </ul>
      </div>
    </nav>

    <router-view/>
  </div>
</template>

<script>
export default {
  name: 'App',
};
</script>

<style>
#app {
  font-family: 'Avenir', Helvetica, Arial, sans-serif;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-align: center;
  color: #2c3e50;
  margin-top: 60px;
}
</style>

這裡我們在頭部新增了三個 router-link 代表我們的頭部導航。

router-linka 標籤類似,只不過 Vue 為它新增一些額外的優化邏輯。

建立後臺管理頁面

接著我們編寫 Admin.vue 元件,但這裡稍微有點不同,即我們在 src/pages 下建立 Admin.vue 元件,因為對於頁面級元件,我們傾向於將其放到一個特殊 pages 資料夾,這樣方便組織專案。其程式碼如下:

<template>
  <div>
    <div class="title">
      <h1>{{msg}}</h1>
    </div>
  </div>
</template>

<script>
  export default {
    name: 'home',
    data () {
      return {
        msg: 'Welcome to the Admin Page'
      }
    }
  }
</script>

可以看到這個頁面內容和我們之前的 Home.vue 內容相似。

建立購物車頁面

然後是我們的購物車頁面 Cart.vue,程式碼如下:

<template>
  <div>
    <div class="title">
      <h1>{{msg}}</h1>
    </div>
  </div>
</template>

<script>
  export default {
    name: 'home',
    data () {
      return {
        msg: 'Welcome to the Cart Page'
      }
    }
  }
</script>

可以看到這個頁面內容和我們之前的 Home.vue 內容相似。

將新頁面匯入路由

最後,我們把上一步中建立的 Home.vue 移到 src/pages 目錄中,並在路由檔案 src/routes/index.js 中匯入這三個頁面,程式碼如下:

import Vue from 'vue';
import Router from 'vue-router';
import Home from '@/pages/Home';
import Admin from '@/pages/Admin';
import Cart from '@/pages/Cart';

Vue.use(Router);

export default new Router({
  routes: [
    {
      path: '/',
      name: 'Home',
      component: Home,
    },
    {
      path: '/admin',
      name: 'Admin',
      component: Admin,
    },
    {
      path: '/cart',
      name: 'Cart',
      component: Cart,
    },
  ],
});

儲存程式碼,然後開啟瀏覽器,我們可以看到下面的效果:

你可以點選頭部的三個導航連結,下面的標題內容會隨著點選的連結變化。恭喜你,你已經成功地實現了一個基於 Vue 的多頁面網站了!

使用巢狀路由和動態路由合理組織頁面

隨著頁面的增多,如果我們把所有的頁面都塞到一個 routes 陣列裡面會顯得很亂,你無法確定哪些頁面存在關係。還好 vue-router 提供了巢狀路由的功能,讓我們能把相關聯的頁面組織在一起。

升級路由

在我們的商城專案中,後臺管理頁 Admin 涉及到很多操作頁面,比如:

  • /create 建立新的商品
  • /edit 編輯商品資訊

讓我們通過巢狀路由的方式將它們組織在一起。首先在路由檔案 src/router/index.js 中宣告後臺管理所有用到的頁面元件(我們馬上就會去實現它們):

import Vue from 'vue';
import Router from 'vue-router';

import Home from '@/pages/Home';
import Cart from '@/pages/Cart';

// Admin Components
import Index from '@/pages/admin/Index';
import New from '@/pages/admin/New';
import Products from '@/pages/admin/Products';
import Edit from '@/pages/admin/Edit';

Vue.use(Router);

export default new Router({
  routes: [
    {
      path: '/',
      name: 'Home',
      component: Home,
    },
    {
      path: '/admin',
      name: 'Admin',
      component: Index,
      children: [
        {
          path: 'new',
          name: 'New',
          component: New,
        },
        {
          path: '',
          name: 'Products',
          component: Products,
        },
        {
          path: 'edit/:id',
          name: 'Edit',
          component: Edit,
        },
      ]
    },
    {
      path: '/cart',
      name: 'Cart',
      component: Cart,
    },
  ],
});

巢狀路由的用法就是給需要歸為一類的頁面設定一個入口頁面,然後把這一類頁面都放到這個路由頁面路由定義的 children 欄位陣列中。

通過上面的程式碼我們可以看到,Admin 類別下有四個元件,Index 是我們 Admin 類別的入口元件,也是作為 path = /admin 的渲染元件,然後其他元件就放到 path = /admin 這個路由定義的 children 陣列裡,其定義和其他父級一致。

這樣的巢狀寫法帶來了兩個好處:

  • 很清晰的組織了一類頁面,方便閱讀。
  • 在定義路由的 path 的時候,複用了父級的 path,即現在我們的 New 這個路由,它在瀏覽器中訪問的路徑為:'/admin' + 'new',如果我們統一放到 routes 陣列的第一級定義,那麼後面的 ProductsEditpath 都要帶上諸如 /admin/admin/edit/:id 這樣長長的路徑,顯得特別複雜。

這裡還有一個改變就是,我們發現 Edit 這個路由的 path 有點不太一樣,它有個特殊的標誌 edit/:id,這種寫法被稱為動態路由,即 :id 會匹配任意字串,所以使用者訪問 /admin/edit/<any-string> 都會啟用 Edit 路由,從而渲染 Edit.vue 元件。

建立 Admin 的子頁面

首先建立 Index.vue 入口元件,程式碼如下:

<template>
  <div>
    <div class="admin-new">
      <div class="container">
        <div class="col-lg-3 col-md-3 col-sm-12 col-xs-12">
          <ul class="admin-menu">
            <li>
              <router-link to="/admin">View Products</router-link>
            </li>
            <li>
              <router-link to="/admin/new">New Products</router-link>
            </li>
          </ul>
        </div>
        <router-view></router-view>
      </div>
    </div>
  </div>
</template>

可以看到,它作為巢狀路由的入口級元件,和我們之前在 App.vue 裡面看到的樣子類似,在其中會有 router-link 導向更深層級的路由.

router-view 用於渲染子路由元件,比如我們此時訪問 /admin/new 頁面,那麼 router-view 部分會被替換成 New.vue 元件的內容,因為我們在之前的巢狀路由定義中 pathnew 的渲染元件為 New.vue

建立 src/pages/admin/Edit.vue 元件,程式碼如下:

<template>
  <div>
    <div class="title">
      <h1>This is Admin/Edit/{{$route.params.id}}</h1>
    </div>
  </div>
</template>

可以看到,當使用者訪問 /admin/edit/:id,會啟用渲染 Edit.vue 元件,我們可以通過 $route.params.id 的方式獲取使用者輸入的路徑 :id 部分。比如我們在瀏覽器中輸入 /admin/edit/52tuture,那麼瀏覽器將會以 h1 的形式打出 "This is Admin/Edit/52tuture"

提示

$route 這個變數是 Vue 在執行時為我們自動插入到所有元件屬性中的,所有我們不用手動去管理它。

建立 src/pages/admin/New.vue,程式碼如下:

<template>
  <div>
    <div class="title">
      <h1>This is Admin/New</h1>
    </div>
  </div>
</template>

建立 src/pages/admin/Products.vue ,程式碼如下:

<template>
  <div>
    <div class="title">
      <h1>This is Admin</h1>
    </div>
  </div>
</template>

儲存我們編寫的內容,開啟瀏覽器,我們可以看到如下內容:

至此,我們的迷你全棧電商應用的第一部分就完成了,在接下來的教程中,我們將用 Express 和 MongoDB 搭建這個電商應用的後端 API,不見不散哦~

想要學習更多精彩的實戰技術教程?來圖雀社群逛逛吧。

本作品採用《CC 協議》,轉載必須註明作者和本文連結

圖雀社群

相關文章