Vue2構建項目實戰

vue構建單頁應用原理

SPA

不是指水療。是 single page web application 的縮寫。中文翻譯爲 單頁應用程序 或 單頁Web應用。更多解釋清參看 百度百科:SPAjavascript

全部的前端人員都應該明白咱們的頁面的 url 構成:css

1 http://www.fengcms.com/index.html?name=fungleo&old=32#mylove/is/world/peace

 

如上的 url 由如下部分組成:html

  1. http:// 規定了頁面採用的協議。
  2. www.fengcms.com 爲頁面所屬的域名。
  3. index.html 爲讀取的文件名稱。
  4. ?name=fungleo&old=32 給頁面經過 GET 方式傳送的參數
  5. #mylove/is/world/peace 爲頁面的錨點區域

前面四個發生改變的時候,會觸發瀏覽器的跳轉亦或是刷新行爲,而更改 url 中的錨點,並不會出現這種行爲,所以,幾乎全部的 spa 應用都是利用錨點的這個特性來實現路由的轉換。以咱們的 vue 項目爲例,它的本地 url 結構通常爲如下格式:前端

1 http://localhost:8080/#/setting/task

 

能夠明顯的看到咱們所謂的路由地址是在 # 號後面的,也就是利用了錨點的特性。vue

RESTful 風格接口

實際狀況是,咱們在先後端在約定接口的時候,能夠約定各類風格的接口,可是,RESTful 接口是目前來講比較流行的,而且在運用中比較方便和常見的接口。java

雖然它有一些缺陷,目前 github 也在主推 GraphQL 這種新的接口風格,但目前國內來講仍是 RESTful 接口風格比較廣泛。node

而且,在掌握了 RESTful 接口風格以後,會深刻的理解這種接口的優缺點,到時候,你天然會去想解決方案,而且在項目中實行新的更好的理念,因此,我這系列的博文,依然採用 http://cnodejs.org/ 網站提供的 RESTful 接口來實戰。jquery

瞭解程序開發的都應該知道,咱們所作的大多數操做都是對數據庫的四格操做 「增刪改查」 對應到咱們的接口操做分別是:linux

  1. post 插入新數據
  2. delete 刪除數據
  3. put 修改數據
  4. get 查詢數據

注意,這裏是咱們約定,並不是這些動做只能幹這件事情。從表層來講,除get外的其餘方法,沒有什麼區別,都是同樣的。從深層來講包括 get在內的全部方法都是如出一轍的,沒有任何區別。可是,咱們約定,每種動做對應不一樣的操做,這樣方便咱們統一規範咱們的全部操做。webpack

假設,咱們的接口是 /api/v1/love 這樣的接口,採用 RESTful 接口風格對應操做是以下的:


get 操做 /api/v1/love

獲取 /api/v1/love 的分頁列表數據,獲得的主體,將是一個數組,咱們能夠用數據來遍歷循環列表

post 操做 /api/v1/love

咱們會往 /api/v1/love 插入一條新的數據,咱們插入的數據,將是JOSN利用對象傳輸的。

get 操做 /api/v1/love/1

咱們獲取到一個 ID 爲 1 的的數據,數據通常爲一個對象,裏面包含了 1 的各項字段信息。

put 操做 /api/v1/love/1

咱們向接口提交了一個新的信息,來修改 ID 爲 1 的這條信息

delete 操做 /api/v1/love/1

咱們向接口請求,刪除 ID 爲 1 的這一條數據


由上述例子可知,咱們實現了5種操做,但只用了兩個接口地址, /api/v1/love 和 /api/v1/love/1 。因此,採用這種接口風格,能夠大幅的簡化咱們的接口設計。

1、安裝 nodejs 環境

你能夠在 https://nodejs.org/ nodejs 官方網站下載安裝包,而後進行安裝。若是是 linux 或者 mac 命令行的用戶,也可使用命令行安裝。

在安裝好了 nodejs 以後,咱們在終端中輸入如下兩個命令:

node -v

npm -v

可以獲得版本號信息,則說明你的 nodejs 環境已經安裝完成了。

2、安裝 vue-cli VUE的腳手架工具

vue-cil是vue的腳手架工具。其模板能夠經過 vuejs-templates 來查看。

咱們首先安裝全局vue-cil腳手架,用於幫助搭建所需的模板框架,命令以下:

npm install -g vue-cli
# 回車,等待安裝...
vue
# 回車,若出現vue信息說明表示成功

這個命令只須要運行一次就能夠了。安裝上以後,之後就不用安裝了。

下面,咱們來用vue-cil構建一個項目。

首先,咱們在終端中把當前目錄定位到你準備存放項目的地方。如我是準備放在~/Sites/MyWork/這個目錄下面,那麼個人命令以下:

cd ~/Sites/MyWork

(也能夠直接在目錄內打開終端)進入到目錄以後,咱們按照下面的代碼逐條輸入,新建一個本身的vue項目,vuedemo是本身起的項目名稱

vue init webpack vuedemo
# 這裏須要進行一些配置,默認回車便可
? Project name vuedemo
? Project description A Vue.js project
? Author
? Vue build standalone
? Install vue-router? Yes
? Use ESLint to lint your code? Yes
? Pick an ESLint preset Standard
? Set up unit tests Yes
? Pick a test runner jest
? Setup e2e tests with Nightwatch? Yes
? Should we run `npm install` for you after the project has been created? (reco
mmended) npm

  vue-cli · Generated "vuedemo".

# Project initialization finished!
# ========================

To get started:

cd vuedemo
npm install
npm run dev

Documentation can be found at https://vuejs-templates.github.io/webpack

如上圖所示,就說明咱們的項目構建成功了。而且,給出了下面要執行的命令,咱們進入項目,安裝並運行:


#在cmd輸入項目名
cd vuedemo
#回車,進入到具體項目文件夾
npm install
#回車,等待一小會兒
#回到項目文件夾,會發現項目結構裏,多了一個node_modules文件夾(該文件裏的內容就是以前安裝的依賴)
最後,執行下面一句,把項目跑起來
npm run dev
DONE Compiled successfully in 4388ms

> Listening at http://localhost:8080

成功執行以上命令後訪問 http://localhost:8080/,輸出結果

總上所述,安裝vue-cil後執行四行命令,就能夠把一個名爲vuedemo的項目跑起來。

進入項目文件夾後vue init webpack vuedemo新建一個項目

進入項目cd vuedemo

建立項目npm install

運行項目npm run dev

固然,這個名字你是能夠隨便起的,根據你的實際項目來定。

經過上面的這些命令,咱們就實現了新建一個vue+webpack的項目。在運行了npm run dev以後,會自動打開一個瀏覽器窗口,就能夠看到實際的效果了。

JavaScript Standard

在建立項目時咱們有開啓了一個standard語法效驗,JavaScript 代碼規範,自帶 linter & 代碼自動修正。

官網:https://standardjs.com/readme-zhcn.html

主要的語法規則有:

  • 使用兩個空格 – 進行縮進
  • 字符串使用單引號 – 須要轉義的地方除外
  • 再也不有冗餘的變量 – 這是致使 大量 bug 的源頭!
  • 無分號 – 沒什麼很差。不騙你!
  • 行首不要以 ([, or ` 開頭
    • 這是省略分號時惟一會形成問題的地方 – 工具裏已加了自動檢測!
    • 詳情
  • 關鍵字後加空格 if (condition) { ... }
  • 函數名後加空格 function name (arg) { ... }
  • 堅持使用全等 === 摒棄 == 一但在須要檢查 null || undefined 時可使用 obj == null
  • 必定要處理 Node.js 中錯誤回調傳遞進來的 err 參數。
  • 文件末尾留一空行
  • 使用瀏覽器全局變量時加上 window 前綴 – document 和 navigator 除外
    •   避免無心中使用到了這些命名看上去很普通的全局變量, openlengthevent 還有 name
  • 查看更多 – 爲什麼不試試 standard 規範呢!

3、項目目錄及文件結構

以前咱們已經新建好了一個基於vue+webpack的項目。咱們在 IDE(Eclipse、Atom等) 中打開該目錄,結構以下所示:

複製代碼
 1 ├── README.md                       // 項目說明文檔
 2 ├── node_modules                    // 項目依賴包文件夾
 3 ├── build                           // 編譯配置文件,通常不用管
 4 │   ├── build.js
 5 │   ├── check-versions.js
 6 │   ├── dev-client.js
 7 │   ├── dev-server.js
 8 │   ├── utils.js
 9 │   ├── vue-loader.conf.js
10 │   ├── webpack.base.conf.js
11 │   ├── webpack.dev.conf.js
12 │   └── webpack.prod.conf.js
13 ├── config                          // 項目基本設置文件夾
14 │   ├── dev.env.js              // 開發配置文件
15 │   ├── index.js                    // 配置主文件
16 │   └── prod.env.js             // 編譯配置文件
17 ├── index.html                      // 項目入口文件
18 ├── package-lock.json           // npm5 新增文件,優化性能
19 ├── package.json                    // 項目依賴包配置文件
20 ├── src                             // 咱們的項目的源碼編寫文件
21 │   ├── App.vue                 // APP入口文件
22 │   ├── assets                      // 初始項目資源目錄,回頭刪掉
23 │   │   └── logo.png
24 │   ├── components              // 組件目錄
25 │   │   └── Hello.vue           // 測試組件,回頭刪除
26 │   ├── main.js                 // 主配置文件
27 │   └── router                      // 路由配置文件夾
28 │       └── index.js            // 路由配置文件
29 └── static                          // 資源放置目錄
複製代碼

 

 

如上圖所示,咱們的目錄結構就是這樣的了。

咱們絕大多數的操做,就是在 src 這個目錄下面。默認的 src 結構比較簡單,咱們須要從新整理。

另外 static 資源目錄,咱們也須要根據放置不一樣的資源,在這邊構建不一樣的子文件夾。

咱們來配置 src 目錄

先不要管這些文件的內容,咱們先創建這些空的文件在這邊。而後咱們後面去完善它。

咱們的這個項目是要作兩個頁面,一個是 cnodejs 的列表頁面,一個是詳情頁面。

因此,我把項目文件夾整理成以下的結構

複製代碼
 1 ├── App.vue                         // APP入口文件
 2 ├── api                             // 接口調用工具文件夾
 3 │   └── index.js                    // 接口調用工具
 4 ├── components                      // 組件文件夾,目前爲空
 5 ├── config                          // 項目配置文件夾
 6 │   └── index.js                    // 項目配置文件
 7 ├── frame                           // 子路由文件夾
 8 │   └── frame.vue                   // 默認子路由文件
 9 ├── main.js                         // 項目配置文件
10 ├── page                                // 咱們的頁面組件文件夾
11 │   ├── content.vue             // 準備些 cnodejs 的內容頁面
12 │   └── index.vue                   // 準備些 cnodejs 的列表頁面
13 ├── router                          // 路由配置文件夾
14 │   └── index.js                    // 路由配置文件
15 ├── style                           // scss 樣式存放目錄
16 │   ├── base                        // 基礎樣式存放目錄
17 │   │   ├── _base.scss          // 基礎樣式文件
18 │   │   ├── _color.scss     // 項目顏色配置變量文件
19 │   │   ├── _mixin.scss     // scss 混入文件
20 │   │   └── _reset.scss     // 瀏覽器初始化文件
21 │   ├── scss                        // 頁面樣式文件夾
22 │   │   ├── _content.scss       // 內容頁面樣式文件
23 │   │   └── _index.scss     // 列表樣式文件
24 │   └── style.scss              // 主樣式文件
25 └── utils                           // 經常使用工具文件夾
26     └── index.js                    // 經常使用工具文件
複製代碼

 

由於咱們刪除了一些默認的文件,因此這個時候項目必定是報錯的,先無論他,咱們根據咱們的需求,新建如上的項目結構。這些都是在 src 目錄裏面的結構。

4、調整app.vue和設置路由

1.調整 App.vue 文件

 咱們先把默認項目裏面沒用的東西先刪除掉,把代碼調整爲下面的樣子。

複製代碼
 1 <template>
 2   <div id="app">
 3     <router-view></router-view>
 4   </div>
 5 </template>
 6 
 7 <script>
 8 export default {
 9   name: 'app'
10 }
11 </script>
12 
13 <style lang="css">
14   @import "./style/index.css";
15 </style>
複製代碼

入口,只有一個空的路由視窗,咱們的項目的全部內容,都基於這個視窗來展示。由於scss文件容易出現語法錯誤,這裏先用css文件替代。後期熟悉以後再更改

咱們的樣式,都將從 src/style/index.css這個文件中引用,若是沒有請按路徑新建!

2.調整 index.vue 和 content.vue 文件

昨天,咱們在 page 文件夾下面創建了兩個空文本文件 index.vue 和 content.vue 文件,是咱們準備用來放列表和內容的。

這裏,咱們先去填寫一點基礎內容在裏面。

index.vue

1 <template>
2   <div>index page</div>
3 </template>

content.vue

1 <template>
2   <div>content page</div>
3 </template>

好,寫上如上的代碼就行,咱們後面再豐富這些內容。

3.調整 router 路由文件

如今,這個項目還跑不起來呢,若是你運行 npm run dev 仍是會出錯的。由於咱們尚未配置路由。

複製代碼
 1 import Vue from 'vue'
 2 import Router from 'vue-router'
 3 import Hello from '@/components/Hello'
 4 
 5 Vue.use(Router)
 6 
 7 export default new Router({
 8   routes: [
 9     {
10       path: '/',
11       name: 'Hello',
12       component: Hello
13     }
14   ]
15 })
複製代碼

以上,是默認的路由文件,引用了一個 Hello 的組件,這個組件被咱們昨天的博文中整理文件結構的時候刪除掉了。因此,這裏就報錯啦。

咱們根據咱們的須要,來調整這個路由文件,以下:

複製代碼
 1 import Vue from 'vue'
 2 import Router from 'vue-router'
 3 import Index from '@/page/index'
 4 import Content from '@/page/content'
 5 
 6 Vue.use(Router)
 7 
 8 export default new Router({
 9   routes: [
10     {
11       path: '/',
12       component: Index
13     }, {
14       path: '/content/:id',
15       component: Content
16     }
17   ]
18 })
複製代碼

默認,咱們的首頁,就是咱們的 index.vue 組件,這裏,你可能要問 :id 是什麼意思?

由於咱們的內容頁面是要展現N條內容的,咱們如何來區分這些內容呢,就是根據ID來進行區分。因此,這裏使用了動態路由匹配。

更多內容,能夠參考官方文檔《動態路由匹配

好,咱們如今,項目應該是沒有任何錯誤,能夠跑起來了。忘記跑起來的命令了?以下:

npm run dev

五。配置axios api接口調用文件

咱們經過配置基本的信息,已經讓咱們的項目可以正常的跑起來了。可是,這裏尚未涉及到 AJAX 請求接口的內容。

vue 自己是不支持 ajax 接口請求的,因此咱們須要安裝一個接口請求的 npm 包,來使咱們的項目擁有這個功能。

這實際上是一個重要的 unix 思想,就是一個工具只作好一件事情,你須要額外的功能的時候,則須要安裝對應的軟件來執行。若是你之前是一個 jquery 重度用戶,那麼可能理解這個思想必定要深刻的理解。

支持 ajax 的工具備不少。一開始,我使用的是 superagent 這個工具。可是我發現近一年來,絕大多數的教程都是使用的 axios 這個接口請求工具。其實,這原本是沒有什麼差異的。可是爲了防止大家在看了個人博文和其餘的文章以後,產生理念上的衝突。所以,我也就改用 axios 這個工具了

 自己, axios 這個工具已經作了很好的優化和封裝。可是,在使用的時候,仍是略顯繁瑣,所以,我從新封裝了一下。固然,更重要的是,封裝 axios 這個工具是爲了和我之前寫的代碼的兼容。不過我封裝得很好,也推薦你們使用。

1.封裝 axios 工具,編輯 src/api/index.js 文件

首先,咱們要使用 axios 工具,就必須先安裝 axios 工具。執行下面的命令進行安裝

npm install axios -D

這樣,咱們就安裝好了 axios 工具了。

還記得咱們在第三篇博文中整理的系統結構嗎?咱們新建了一個 src/api/index.js 這個空文本文件,就那麼放在那裏了。這裏,咱們給它填寫上內容。

複製代碼
// 配置API接口地址
var root = 'https://cnodejs.org/api/v1'
// 引用axios
var axios = require('axios')
// 自定義判斷元素類型JS
function toType (obj) {
  return ({}).toString.call(obj).match(/\s([a-zA-Z]+)/)[1].toLowerCase()
}
// 參數過濾函數
function filterNull (o) {
  for (var key in o) {
    if (o[key] === null) {
      delete o[key]
    }
    if (toType(o[key]) === 'string') {
      o[key] = o[key].trim()
    } else if (toType(o[key]) === 'object') {
      o[key] = filterNull(o[key])
    } else if (toType(o[key]) === 'array') {
      o[key] = filterNull(o[key])
    }
  }
  return o
}
/*
  接口處理函數
  這個函數每一個項目都是不同的,我如今調整的是適用於
  https://cnodejs.org/api/v1 的接口,若是是其餘接口
  須要根據接口的參數進行調整。參考說明文檔地址:
  https://cnodejs.org/topic/5378720ed6e2d16149fa16bd
  主要是,不一樣的接口的成功標識和失敗提示是不一致的。
  另外,不一樣的項目的處理方法也是不一致的,這裏出錯就是簡單的alert
*/

function apiAxios (method, url, params, success, failure) {
  if (params) {
    params = filterNull(params)
  }
  axios({
    method: method,
    url: url,
    data: method === 'POST' || method === 'PUT' ? params : null,
    params: method === 'GET' || method === 'DELETE' ? params : null,
    baseURL: root,
    withCredentials: false
  })
  .then(function (res) {
    if (res.data.success === true) {
      if (success) {
        success(res.data)
      }
    } else {
      if (failure) {
        failure(res.data)
      } else {
        window.alert('error: ' + JSON.stringify(res.data))
      }
    }
  })
  .catch(function (err) {
    let res = err.response
    if (err) {
      window.alert('api error, HTTP CODE: ' + res.status)
    }
  })
}

// 返回在vue模板中的調用接口
export default {
  get: function (url, params, success, failure) {
    return apiAxios('GET', url, params, success, failure)
  },
  post: function (url, params, success, failure) {
    return apiAxios('POST', url, params, success, failure)
  },
  put: function (url, params, success, failure) {
    return apiAxios('PUT', url, params, success, failure)
  },
  delete: function (url, params, success, failure) {
    return apiAxios('DELETE', url, params, success, failure)
  }
}
複製代碼

有關 axios 的更多內容,請參考官方 github: https://github.com/mzabriskie/axios ,中文資料自行百度。

但就是這樣,咱們還不能再 vue 模板文件中使用這個工具,還須要調整一下 main.js 文件。

2.調整 main.js 綁定 api/index.js 文件

此次呢,咱們沒有上來就調整 main.js 文件,由於原始文件就配置得比較好,我就沒有刻意的想要調整它。

原始文件以下:

複製代碼
 1 import Vue from 'vue'
 2 import App from './App'
 3 import router from './router'
 4 
 5 Vue.config.productionTip = false
 6 
 7 /* eslint-disable no-new */
 8 new Vue({
 9   el: '#app',
10   router,
11   template: '<App/>',
12   components: { App }
13 })
複製代碼

咱們插入如下代碼:

1 // 引用API文件
2 import api from './api/index.js'
3 // 將API方法綁定到全局
4 Vue.prototype.$api = api

也就是講代碼調整爲:

複製代碼
import Vue from 'vue'
import App from './App'
import router from './router'

// 引用API文件
import api from './api/index.js'
// 將API方法綁定到全局
Vue.prototype.$api = api

Vue.config.productionTip = false

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

好了,這樣,咱們就能夠在項目中使用咱們封裝的 api 接口調用文件了。

3.測試一下看看能不能調通

咱們來修改一下 src/page/index.vue 文件,將代碼調整爲如下代碼:

複製代碼
 1 <template>
 2   <div>index page</div>
 3 </template>
 4 <script>
 5 export default {
 6   created () {
 7     this.$api.get('topics', null, r => {
 8       console.log(r)
 9     })
10   }
11 }
12 </script>
複製代碼

好,這裏是調用 cnodejs.org 的 topics 列表接口,而且將結果打印出來。

咱們在瀏覽器中打開控制檯,看看 console 下面有沒有輸出入下圖同樣的內容。若是有的話,就說明咱們的接口配置已經成功了。

好,若是你操做正確,代碼沒有格式錯誤的話,那麼如今應該獲得的結果是和我同樣的。若是出錯或者怎麼樣,請仔細的檢查代碼,看看有沒有什麼問題。

6、將接口用webpack代理到本地

咱們已經很是順利的調用到了 cnodejs.org 的接口了。可是,咱們能夠注意到咱們的 src/api/index.js 的第一句,就是:

1 // 配置API接口地址
2 var root = 'https://cnodejs.org/api/v1'

這裏,咱們將接口地址寫死了。

固然,這並非最重要的事情,而是 cnodejs.org 幫咱們把接口處理得很好,解決了跨域的問題。而咱們的實際項目中,不少接口都是不容許咱們這樣跨域請求的。

而咱們的開發環境下,不可能跑到服務器上直接開發,或者在本地直接搞一個服務器環境,這樣就違背了咱們先後端分離開發的初衷了。

如何解決這個問題呢?其實很是好辦,要知道 跨域不是接口的限制 而是瀏覽器爲了保障數據安全作的限制。所以,一種方法能夠解決,那就是打開瀏覽器的限制,讓咱們能夠順利的進行開發。可是無奈的是,最新的 chrome 瀏覽器好像已經關閉了這個選項,那麼咱們只能採用另一種方法了——將接口代理到本地。

1.配置 webpack 將接口代理到本地

好在,vue-cli 腳手架工具,已經充分的考慮了這個問題,咱們只要進行簡單的設置,就能夠實現咱們的目的。

咱們打開 config/index.js 文件,找到如下代碼:

複製代碼
1   dev: {
2     env: require('./dev.env'),
3     port: 8080,
4     autoOpenBrowser: true,
5     assetsSubDirectory: 'static',
6     assetsPublicPath: '/',
7     proxyTable: {},
8     cssSourceMap: false
9   }
複製代碼

其中,proxyTable: {}, 這一行,就是給咱們配置代理的。

根據 cnodejs.org 的接口,咱們把這裏調整爲:

複製代碼
1 proxyTable: {
2   '/api/v1/**': {
3     target: 'https://cnodejs.org', // 你接口的域名
4     secure: false,
5     changeOrigin: false,
6   }
7 }
複製代碼

OK,咱們這樣配置好後,就能夠將接口代理到本地了。

更多接口參數配置,請參考 https://github.com/chimurai/http-proxy-middleware#options

webpack 接口配置文檔 https://webpack.js.org/configuration/dev-server/#devserver-proxy

2.從新配置 src/api/index.js 文件

好,上面已經代理成功了,可是咱們的 src/api/index.js 文件,仍是直接調用的人家的地址呢,咱們要調整爲咱們的地址,調整以下:

1 // 配置API接口地址
2 var root = '/api/v1'

以前我有一篇博文,說過如何配置開發接口地址和生產接口地址,當時是利用了 webpack 的不一樣的配置文件來進行配置的。若是咱們採用這種代理模式呢,那麼就沒有必要那麼作了。由於咱們的系統放到生產環境的時候,通常是沒有這個跨域問題的。這個問題通常僅僅是存在於咱們的開發環境下面。

值得注意的事情是,配置完成後,是不會當即生效的,咱們須要重啓咱們的項目。

咱們按 ctrl + c 中止掉以前的服務,而後從新輸入命令 npm run dev 重啓項目,就能夠了。

如上圖所示,咱們能夠清晰的看到,咱們跑的服務,先開啓了一個代理。

從新跑起來以後,咱們看下咱們的項目在瀏覽器中的表現:

咱們打開瀏覽器控制檯,切換到 network 選項卡中,選中咱們調用的接口 topics 接口,咱們能夠清晰的看到,咱們讀取的接口地址是咱們的本地代理過來的地址。

狀態碼爲 304 表明這個數據沒有發生變化,直接讀取本地緩存了。關於 http 狀態碼 的部分,請參考 百度百科 http 狀態碼,這裏不作過多的說明。

咱們再看一下數據是否是正常的過來了。切換到 Previdw 選項卡查看:

Previdw

沒有問題,數據過來了。

好,到這裏,咱們已經順利的將接口代理到本地,而且數據讀取出來了。咱們開始準備下面的工做吧!

7.初識*.vue文件,即VUE組件

*.vue 文件,是一個自定義的文件類型,用類 HTML 語法描述一個 Vue 組件。每一個 .vue文件包含三種類型的頂級語言塊 <template><script> 和 <style>。這三個部分分別表明了 html,js,css

其中 <template> 和 <style> 是支持用預編譯語言來寫的。好比,在咱們的項目中,咱們能夠用 scss 預編譯,咱們能夠這樣寫的:

1 <style lang="scss">

html 也有本身的預編譯語言, vue 也是支持的,不過通常來講,咱們前端人員仍是比較中意 html 原生語言,因此,我就不過多闡述了。

另外,我在 App.vue 文件中,已經用一句 @import "./style/style"; 將咱們的樣式給寫到指定的地方去了。因此,在後面全部的個人文章中,是不會出現這個部分的內容的。全部樣式,都會在 src/style/ 文件夾中對應的位置去寫。 
我這樣作的好處是,不須要重複的引入各類 scss 基礎文件,而且作到了項目的樣式代碼的可管控

1.一個常見的 *.vue 文件代碼解析

首先,咱們來簡單看一下:

複製代碼
 1 <template>
 2   <div>
 3     <Header></Header>
 4     <div class="article_list">
 5       <ul>
 6         <li></li>
 7       </ul>
 8     </div>
 9     <Footer></Footer>
10   </div>
11 </template>
12 <script>
13 import Header from '../components/header.vue'
14 import Footer from '../components/footer.vue'
15 export default {
16   components: { Header, Footer },
17   data () {
18     return {
19       list: []
20     }
21   },
22   created () {
23     this.getData()
24   },
25   methods: {
26     getData () {
27       this.$api.get('topics', null, r => {
28         console.log(r)
29       })
30     }
31   }
32 }
33 </script>
34 <style>
35   .article_list {margin: auto;}
36 </style>
複製代碼

好,以上就是一個簡單的 *.vue 文件的基本結構。咱們一部分一部分的來解釋。

如下,我再也不稱呼它爲 *.vue 文件了。改爲爲 vue 組件。

2.template 部分

首先,一個 vue 組件,他的 template 則表明它的 html 結構,相信你們能夠理解了。可是須要注意的是,咱們不是說把代碼包裹在 <template></template> 中就能夠了,而是必須在裏面放置一個 html 標籤來包裹全部的代碼。 本例子中,咱們採用了 <div></div> 標籤。vue2.x 開始,就必須這樣去寫。這是規定

你們看到 <Header></Header> 這個代碼的時候確定很奇怪,這是個什麼玩意兒。其實,這是一個自定義組件。咱們在其餘地方寫好了一個組件,而後就能夠用這種方式引入進來。

一樣 <Footer></Footer> 也是一個組件。再也不累述。

其餘的內容,咱們就想這麼寫就怎麼寫了。和寫咱們的 html 代碼沒有什麼太大的區別。

3.script 部分

首先,咱們須要兩個自定義組件,咱們先引用進來。以下格式,比較好理解吧。

1 import Header from '../components/header.vue'
2 import Footer from '../components/footer.vue'

其次,除了引用的文件,咱們將全部的代碼包裹於以下的代碼中間:

1 export default {
2   // 這裏寫你的代碼,外面要包起來。
3 }

4.style 部分

這裏比較簡單,就是針對咱們的 template 裏內容出現的 html 元素寫一些樣式。如上,個人代碼:

1 <style>
2   .article_list {margin: auto;}
3 </style>

就是給咱們的 .article_list 元素隨便加了一個樣式。

參考資料:《vue 模板語法

8、渲染列表

1.製做 header.vue 和 footer.vue 組件文件。

不是本篇文章的重點,可是仍是有比較講一下。在第三篇博文中,咱們規劃了咱們的項目文件結構,當時保留了一個 components 的空文件夾。這裏,就是準備放咱們的自定義組件的。

首先,咱們去建立兩個空文本文件,分別是 header.vue 文件和 footer.vue 文件。

而後,往裏面輸入下面的內容:

header.vue

1 <template>
2   <header class="header">
3     <h1 class="logo">Vue Demo by DEMO</h1>
4   </header>
5 </template>

footer.vue

1 <template>
2   <footer class="copy">
3     Copy &copy; DEMO
4 </footer> 5 </template>

很是簡單的兩個文件,表示咱們的組件已經弄好了

2.編寫 src/page/index.vue 文件

複製代碼
 1 <template>
 2   <div>
 3     <Header></Header>
 4     <div class="article_list">
 5       <ul>
 6         <li v-for="i in list" :key="i.id">
 7           <time v-text="i.create_at"></time>
 8           <router-link :to="'/content/' + i.id">
 9             {{ i.title }}
10           </router-link>
11         </li>
12       </ul>
13     </div>
14     <Footer></Footer>
15   </div>
16 </template>
17 <script>
18 import Header from '../components/header.vue'
19 import Footer from '../components/footer.vue'
20 export default {
21   components: { Header, Footer },
22   data () {
23     return {
24       list: []
25     }
26   },
27   created () {
28     this.getData()
29   },
30   methods: {
31     getData () {
32       this.$api.get('topics', null, r => {
33         this.list = r.data
34       })
35     }
36   }
37 }
38 </script>
複製代碼

如上,代碼,我就把頁面渲染出來了。咱們看下實際的效果:

如上,我先用了一個 v-for 的循環,來循環數據。這裏能夠參考:https://cn.vuejs.org/v2/api/#v-for 文檔。

在 time 標籤中,我使用了 v-text="i.create_at" 來渲染時間數據。參考文檔: https://cn.vuejs.org/v2/api/#v-text

router-link 是 VueRouter2 「聲明式導航」的寫法,在實際轉換爲 html 標籤的時候,會轉化爲 <a></a>,裏面的 to 屬性,就至關於 a 的 href 屬性。參考文檔:https://router.vuejs.org/zh-cn/essentials/getting-started.html

3.編寫 src/utils/index.js 文件

如上面的圖片所示,因爲拿到的數據是一個標準的時間格式,直接渲染在頁面上,這個效果不是很理想。所以,咱們能夠把時間給處理一下,而後再渲染出來。

這裏,咱們能夠直接在 getData () {...} 後面再寫一個方法便可。可是,在一個項目中,若是全部的地方都是這樣的時間格式,咱們在每個組件中都來寫這樣的處理方法,很顯然就顯得咱們比較愚蠢了。

所以,咱們能夠獨立出來寫一個方法,而後在全部的地方均可以使用,這樣就比較方便了。

還記得咱們在第三篇博文中,咱們創建了一個 src/utils/index.js 的空文本文件嗎?這裏,咱們要用上了。

直接給代碼以下:

複製代碼
 1 export default {
 2   goodTime (str) {
 3     let now = new Date().getTime()
 4     let oldTime = new Date(str).getTime()
 5     let difference = now - oldTime
 6     let result = ''
 7     let minute = 1000 * 60
 8     let hour = minute * 60
 9     let day = hour * 24
10     let month = day * 30
11     let year = month * 12
12     let _year = difference / year
13     let _month = difference / month
14     let _week = difference / (7 * day)
15     let _day = difference / day
16     let _hour = difference / hour
17     let _min = difference / minute
18 
19     if (_year >= 1) {
20       result = '發表於 ' + ~~(_year) + ' 年前'
21     } else if (_month >= 1) {
22       result = '發表於 ' + ~~(_month) + ' 個月前'
23     } else if (_week >= 1) {
24       result = '發表於 ' + ~~(_week) + ' 周前'
25     } else if (_day >= 1) {
26       result = '發表於 ' + ~~(_day) + ' 天前'
27     } else if (_hour >= 1) {
28       result = '發表於 ' + ~~(_hour) + ' 個小時前'
29     } else if (_min >= 1) {
30       result = '發表於 ' + ~~(_min) + ' 分鐘前'
31     } else {
32       result = '剛剛'
33     }
34     return result
35   }
36 }
複製代碼

好,代碼噁心了點,我拿我之前寫的代碼改的,沒有深刻優化,你們就隨便看看,大概就是這麼個東西。

寫好代碼以後,咱們保存文件。可是此時,咱們還不能使用咱們的這個方法函數。咱們必須在 main.js 中將咱們的方法函數給綁定上。以下代碼:

1 // 引用工具文件
2 import utils from './utils/index.js'
3 // 將工具方法綁定到全局
4 Vue.prototype.$utils = utils

好了,這樣,咱們寫的這個函數,就能夠隨便被咱們調用了。咱們再來修改一下咱們上面的 index.vue 中的代碼,將 time 調整爲:

1 <time v-text="$utils.goodTime(i.create_at)"></time>

而後,咱們再來看一下實際的效果:

vue demo by fungleo

好,咱們已經看到,時間已經搞的挺好的了。

9、把內容頁面渲染出來

前面咱們從文章中留下的引子 <router-link :to="'/content/' + i.id"> 應該知道,咱們仍是要作內容頁面的。

1.編寫內容頁面

複製代碼
 1 <template>
 2   <div>
 3     <myHeader></myHeader>
 4     <h2 v-text="dat.title"></h2>
 5     <p v-if="dat.author">做者:{{dat.author.loginname}}發表於:{{$utils.goodTime(dat.create_at)}}</p>
 6     <hr>
 7     <article v-html="dat.content"></article>
 8     <h3>網友回覆:</h3>
 9     <ul>
10       <li v-for="i in dat.replies">
11         <p>評論者:{{i.author.loginname}}評論於:{{$utils.goodTime(i.create_at)}}</p>
12         <article v-html="i.content"></article>
13       </li>
14     </ul>
15     <myFooter></myFooter>
16   </div>
17 </template>
18 <script>
19 import myHeader from "../components/header.vue";
20 import myFooter from "../components/footer.vue";
21 export default {
22   components: { myHeader, myFooter },
23   data() {
24     return {
25       id: this.$route.params.id,
26       dat: {}
27     };
28   },
29   created() {
30     this.getData();
31   },
32   methods: {
33     getData() {
34       this.$api.get("topic/" + this.id, null, r => {
35         this.dat = r.data;
36       });
37     }
38   }
39 };
40 </script>
複製代碼

好,咱們這邊把代碼寫進 src/page/content.vue 文件。而後保存,我在咱們先前的列表頁面隨便點開一篇文章,而後咱們看下結果:

10、打包項目併發布到子目錄

咱們已經完成了咱們設想的項目的開發。可是,咱們作好的這套東西,是基於 nodejs 開發的。而咱們最終但願,咱們開發的項目,生成好一堆文件,而後隨便經過任何一個 http 服務就能跑起來,也就是,還原成咱們熟悉的 html+css+js 的模式。

1.打包項目

們進入到終端,而且進入到咱們的開發目錄:

 cd ~/Site/MyWork/vue-demo-cnodejs

而後運行以下代碼,進行打包:

npm run build

運行結果以下:

 

好,咱們已經打包好了。文件打包位置於項目目錄裏面的 dist 文件夾內。

可是,咱們從上圖能夠看到,咱們生成了一些 .map 的文件。這就有點噁心了。當咱們的項目變得比較大的時候,這些文件,第一個是,很是大,第二個,編譯時間很是長。因此,咱們要把這個文件給去掉。

咱們編輯 /config/index.js 文件,找到其中的

1 productionSourceMap: true,

修改成:

1 productionSourceMap: false,

而後咱們從新運行打包命令:

npm run build

 

沒用的 map 文件已經沒有了。

好,咱們能夠從上圖中看出,有一個 tip 。它告訴咱們,打包出來的文件,必須在 http 服務中運行,不然,不會工做。

2.安裝 http-server 啓動 http 服務

咱們進入 dist 文件夾,而後啓動一個 http 服務,來看看能夠不能夠訪問。

你可能不知道如何啓動這樣一個 http 服務,或者,你如今已經到 apache 裏面去進行配置去了。不用那麼麻煩,咱們有 nodejs 環境,只要全局安裝一個 http-server 服務就行了呀。

npm install http-server -g

好,經過這個命令,咱們就安裝好了。安裝好了以後正常咱們就可以使用 http-server 命令來跑服務了。可是,這個世界不正常的時候是不少的嘛!

在終端裏面輸入,

http-server

看可否正常啓動,仍是爆 -bash: http-server: command not found 錯誤,這裏,是說沒有找到這個命令,沒有關係,這是表示,咱們的 nodejs 的程序執行路徑,沒有添加到環境變量中去。

首先,如上圖所示,咱們的 http-server 安裝到了 /usr/local/Cellar/node/7.6.0/bin/ 這個目錄下面,咱們只要把這個目錄,添加到環境變量便可。

請注意,你的安裝路徑可能和個人是不一致的,請注意調整。

咱們在終端內執行下面兩個命令,就能夠了。

echo 'export PATH="$PATH:/usr/local/Cellar/node/7.6.0/bin/"' >> ~/.bash_profile

. ~/.bash_profile

第一條命令是追加環境變量,第二個命令是,使咱們的追加當即生效。

固然,你也能夠直接編輯 ~/.bash_profile 文件,把上面命令中的單引號裏面的內容插入到文件最後面,而後執行第二個命令生效。隨便。

好,一個插曲結束。咱們要把咱們打包出來的東西跑起來呀!

cd dist

http-server -p 3000

若是你是嚴格按照個人教程來的,那麼如今已經能夠順利的跑起來了。咱們在瀏覽器中輸入 http://127.0.0.1:3000 就應該能夠訪問了。

固然,會報錯,說是接口找不到,404錯誤。由於咱們把接口給經過代理的方式開啓到了本地,可是這裏咱們並無開啓代理,因此就跑不起來了。很正常的。

這是由於示例的接口的問題。實際開發你還要按照個人這個作。只不過,最終代碼放到真實的服務器環境去和後端接口在一個 http 服務下面的話,就不存在這個問題了。

好,咱們就跑起來了。

3.將項目打包到子目錄

剛剛,咱們是將文件,打包爲根目錄訪問的。也就是說,必須在 dist 文件夾下面啓動一個服務,才能把項目跑起來。

可是咱們開發的大多數項目,多是必須跑在二級目錄,甚至更深層次的目錄的。怎麼作呢?

咱們編輯 config/index.js 文件,找到:

assetsPublicPath: '/',

把 '/' 修改成你要放的子目錄的路徑就好了。這裏,我要放到 /dist/ 目錄下面。因而,我就把這裏修改成

1 assetsPublicPath: '/dist/',

而後,從新運行

 

npm run build

進行打包。

很快,就打包好了。

還記得,咱們在項目文件夾中用 npm run dev 就能夠開啓一個 http 服務嗎?而且那裏,咱們還代理了接口的。

好,咱們就這麼作。

而後咱們訪問二級目錄 /dist/ 咱們就能夠看到效果了。

注意,我訪問的不是根目錄,而是 /dist/ 這個子目錄哦,這裏是訪問的咱們打包的文件的。

複製代碼
1 ├── index.html
2 └── static
3     ├── css
4     │   └── app.d41d8cd98f00b204e9800998ecf8427e.css
5     └── js
6         ├── app.8ffccad49e36e43a4e9b.js
7         ├── manifest.7a471601ff5a8b26ee49.js
8         └── vendor.057dd4249604e1e9c3b5.js
複製代碼

好,到這裏,咱們的打包工做,就講完了。

實際開發中,你只須要把 dist 文件夾中打包好的文件,給運維他們,讓他們去部署到真實的服務器環境就行了。

11、打包項目圖片等資源的處理

1.在 vue 文件中,引用圖片

例如,咱們將一張圖片放到資源目錄 /static/image/lyf.jpg 咱們在 vue 文件中用下面的代碼來使用這張圖片。

1 <img src="static/image/lyf.jpg" alt="劉亦菲">

注意,最前面不要加 / 若是是這樣操做的話,會變成相對根目錄調用圖片。若是你的項目要打包到子目錄的話,這樣作就會出現問題。

2.在 css 文件中,引用圖片的處理

仍是上面那張圖片,咱們須要在 css 中來引用,如何來寫呢?

.love {
  background-image: url('../static/image/lyf.jpg');
}

好,這裏爲何要加上 ../ 呢?

若是是最終打包到根目錄的話,可使用 / 這種路徑。這個是徹底能夠理解的。

但,若是是打包到子目錄,咱們必須看下生成的最終路徑:

複製代碼
├── index.html
└── static
    ├── css
    │   └── app.a7a745952a8ca7f8c9413d53b431b8c8.css
    ├── image
    │   └── lyf.jpg
    ├── img
    │   └── lyf.9125a01.jpg
    └── js
        ├── app.39ccc604caeb34166b49.js
        ├── manifest.b1ad113c36e077a9b54d.js
        └── vendor.0b8d67613e49db91b787.js
複製代碼

如上,咱們能夠看到這個 css 相對 圖片 的路徑的地址。

你要疑問了,這樣的相對路徑,咱們可使用 ../image/lyf.jpg 來進行調用呀。嗯,看上去能夠,可是,若是是這樣的話,在開發模式中又會出錯了。

因此,仍是要用 '../static/image/lyf.jpg' 這樣的路徑方式來調用圖片。

字體圖標,js 文件等,都是這樣的路數。不在贅述。

本文地址http://www.cnblogs.com/zhaowy/

版權聲明:本文爲原創文章,版權歸 做者全部,歡迎分享本文,轉載請保留出處!

相關文章
相關標籤/搜索