一、SPA
不是指水療。是 single page web application
的縮寫。中文翻譯為 單頁應用程序 或 單頁Web應用,更多解釋請自行搜索。
所有的前端人員都應該明白我們的頁面的 url
構成:http://www.fengcms.com/index.html?name=fungleo&old=32#mylove/is/world/peace
如上的 url
由以下部分組成:協議、域名、文件名稱、get參數、錨點
1、http://
規定了頁面采用的協議。
2、www.fengcms.com
為頁面所屬的域名。
3、index.html
為讀取的文件名稱。
4、?name=fungleo&old=32
給頁面通過 GET
方式傳送的參數
5、#mylove/is/world/peace
為頁面的錨點區域
前面四個發生改變的時候,會觸發瀏覽器的跳轉亦或是刷新行為,而更改 url
中的錨點,並不會出現這種行為,因此,幾乎所有的 spa
應用都是利用錨點的這個特性來實現路由的轉換。以我們的 vue
項目為例,它的本地 url
結構一般為以下格式:http://localhost:8080/#/setting/task,可以明顯的看到我們所謂的路由地址是在
#
號后面的,也就是利用了錨點的特性。(個人理解)
二、RESTful 風格接口
實際情況是,我們在前后端在約定接口的時候,可以約定各種風格的接口,但是,RESTful
接口是目前來說比較流行的,並且在運用中比較方便和常見的接口。雖然它有一些缺陷,目前 github
也在主推 GraphQL
這種新的接口風格,但目前國內來說還是 RESTful
接口風格比較普遍。並且在掌握了 RESTful
接口風格之后,會深入的理解這種接口的優缺點,到時候,你自然會去想解決方案,並且在項目中實行新的更好的理念。了解程序開發的都應該知道,我們所做的大多數操作都是對數據庫的四格操作 “增刪改查” 對應到我們的接口操作分別是:
post
插入新數據
delete
刪除數據
put
修改數據
get
查詢數據
注意:這里是我們約定,並非這些動作只能干這件事情。從表層來說,除get
外的其他方法,沒有什么區別,都是一樣的。從深層來說包括 get
在內的所有方法都是一模一樣的,沒有任何區別。但是,我們約定,每種動作對應不同的操作,這樣方便我們統一規范我們的所有操作。
假設,我們的接口是 /api/v1/love
這樣的接口,采用 RESTful
接口風格對應操作是如下的:
1、get
操作 /api/v1/love:
獲取 /api/v1/love
的分頁列表數據,得到的主體,將是一個數組,我們可以用數據來遍歷循環列表
2、post
操作 /api/v1/love:
我們會往 /api/v1/love
插入一條新的數據,我們插入的數據,將是JOSN
利用對象傳輸的。
3、get
操作 /api/v1/love/1:
我們獲取到一個 ID 為 1 的的數據,數據一般為一個對象,里面包含了 1 的各項字段信息。
4、put
操作 /api/v1/love/1:
我們向接口提交了一個新的信息,來修改 ID 為 1 的這條信息
5、delete
操作 /api/v1/love/1:
我們向接口請求,刪除 ID 為 1 的這一條數據
由上述例子可知,我們實現了5種操作,但只用了兩個接口地址, /api/v1/love
和 /api/v1/love/1
。所以,采用這種接口風格,可以大幅的簡化我們的接口設計。
三、配置 static 目錄
這個目錄比較簡單,一般搞成下面這個樣子:
├── css // 放一些第三方的樣式文件
├── font // 放字體圖標文件
├── image // 放圖片文件,如果是復雜項目,可以在這里面再分門別類
└── js // 放一些第三方的JS文件,如 jquery
你可能很奇怪,我們不是把樣式和 JS
都寫到里面去么,為什么還要在這邊放呢?
因為,如果是放在 src
目錄里面,則每次打包的時候,都需要打包的。這會增加我們打包項目的時間長度。而且,一些第三方的文件,我們一般是不會去修改的,也沒必要 npm
安裝,直接引用就好了。你可以根據自己的情況,對這些可以不進行打包而直接引用的文件提煉出來,放在資源目錄里面直接調用,這樣會大大的提高我們的項目的打包效率。
四、封裝 axios 工具,編輯 src/api/index.js 文件
首先,我們要使用 axios
工具,就必須先安裝 axios
工具。執行下面的命令進行安裝
npm install axios -D
從之前整理的系統結構里,我們新建了一個 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) } }
但就是這樣,我們還不能再 vue
模板文件中使用這個工具,還需要調整一下 main.js
文件,我們插入標紅的代碼:
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
接口調用文件了。
export default { created () { this.$api.get('topics', null, r => { console.log(r) }) } }
注意:webpack代理之后,接口不需要定死,需要改成:('/api/v1'代理里面的路徑)
// 配置API接口地址
var root = '/api/v1'
此外,還要注意一點,就是this重定向的問題
var v = this v.$api.get('topics', null, function (r) { v.list = r.data })
五、公用工具函數
我們可以獨立出來寫一個方法,然后在所有的地方都可以使用,這樣就比較方便了。我們建立了一個 src/utils/index.js
的空文本文件,我們編寫src/utils/index.js 文件
export default { goodTime (str) { let now = new Date().getTime() let oldTime = new Date(str).getTime() let difference = now - oldTime let result = '' let minute = 1000 * 60 let hour = minute * 60 let day = hour * 24 let month = day * 30 let year = month * 12 let _year = difference / year let _month = difference / month let _week = difference / (7 * day) let _day = difference / day let _hour = difference / hour let _min = difference / minute if (_year >= 1) { result = '發表於 ' + ~~(_year) + ' 年前' } else if (_month >= 1) { result = '發表於 ' + ~~(_month) + ' 個月前' } else if (_week >= 1) { result = '發表於 ' + ~~(_week) + ' 周前' } else if (_day >= 1) { result = '發表於 ' + ~~(_day) + ' 天前' } else if (_hour >= 1) { result = '發表於 ' + ~~(_hour) + ' 個小時前' } else if (_min >= 1) { result = '發表於 ' + ~~(_min) + ' 分鍾前' } else { result = '剛剛' } return result } }
寫好代碼之后,我們保存文件。但是此時,我們還不能使用我們的這個方法函數。我們必須在 main.js
中將我們的方法函數給綁定上。如下代碼:
// 引用工具文件
import utils from './utils/index.js'
// 將工具方法綁定到全局
Vue.prototype.$utils = utils
還記得我們先前是如何將我們的接口請求函數給綁定上的嗎?這里其實是采用了同樣的方法。這樣,我們寫的這個函數,就可以隨便被我們調用了。我們再來修改一下我們的 index.vue
中的代碼,將 time
調整為:<time v-text="$utils.goodTime(i.create_at)"></time>
我們在 script
區域,引用一個函數是使用 this.getData
或者 this.list
這樣的代碼引用的。但是在 template
中,我們是不加 this
的。
六、去掉 map 文件
當我們npm run build的時候,會生成了一些 .map
的文件,當我們的項目變得比較大的時候,這些文件第一個是非常大,第二個編譯時間非常長。所以,我們要把這個文件給去掉。
我們編輯 /config/index.js
文件,找到其中的
productionSourceMap: true, //修改為:
productionSourceMap: false,
重新運行打包命令,沒用的 map
文件已經沒有了。