綱要
當瀏覽器開始new Vue()階段時,會依序經過以下步驟,且每個步驟都可以根據需要的階段來掛載methods:
beforeCreate()
觀察data()
結構與初始化 events
created()
是否有"el"的 option 被調用,假如有則判斷是否有"template"元素出現,沒有的話則 view model 呼叫 mount 掛載 el 。如果有 template
,將 template
中的 html 模板編譯到 render()
中,若沒有 template
出現在環境則編譯 el 上一層的 HTML 作為 template
模板。
注意:created()
階段時頁面 DOM 還不會生成
beforeMount()
Vue掛載初始化並處理好的組件設定與事件之前,會建構一個vm.$el
屬性物件替換el。
mounted()
掛載階段,如果data有被更動,則進入beforeUpdate()
。
beforeUpdate()
將VDOM重新render並更新。
updated()
更新data後的狀態。
beforeDestroy()
當mounted()
後如果有呼叫vm.$destroy()
的行為,則進入beforeDestroy()
此時拆卸watcher
(比如compted的getter或watch)和子組件、以及事件偵聽後進入destroyed()
消滅。
注意,假如你也有跟我一樣要把 Home 設定起始畫面就是 Dashboard 才跟著做,如果要改成獨立分頁,寫在跟 home 平行同層物件下即可。
{
path: 'newpage' //路徑。也就是網址打什麼後綴字會出現
name: 'newPage', //名稱,router切換頁面$router.push('newPage')會使用這個名字
component: () => import './views/newPage.vue' // 將新增頁面的vue檔案拉到這
}
除了不需要 Call API 取得 Data List 或 Select Options 而會將設定寫入 data() 外,儘早讓各位同學習慣從 JSON Server 模擬環境 Get 資料,提前安排 Axios + vue-axios 在這個禮拜講解實作一次。這個例子只是方便大家從JSON Server中取資料來操作一遍,實際環境專案使用的封裝方式最後會提到。
先安裝以下套件:
npm install axios
npm install vue-axios
npm install json-server
然後在專案的根目錄下新增 db.json
,並且新增一些內容。GitHub範例
接下來開啟終端程式輸入 json-server --watch db.json
就會看到這個畫面
\{^_^}/ hi!
Loading db.json
Done
Resources
http://localhost:3000/posts
http://localhost:3000/comments
http://localhost:3000/profile
http://localhost:3000/tableData ##剛剛在db.json新增的資料
Home
http://localhost:3000
1. main.js當中引入並且設定global prototype
/* main.js */
import axios from 'axios'
import api from '@/service/api' // 第二步驟會用到
import VueAxios from 'vue-axios'
// 教學專案採用element UI組件來切版和建置表單,所以先裝好
import ElementUI from 'element-ui'
import 'element-ui/lib/theme-chalk/index.css'
// 套用並設定prototype
Vue.use(ElementUI)
Vue.use(VueAxios, axios)
Vue.config.productionTip = false
Vue.prototype.$api = api // 定義api這個常數給AXIOS存取json-server或實際api環境用
2. 在src裡面創建一個叫做「service」的目錄,此目錄下再創建一個「api.js」
/* api.js */
import axios from 'axios'
axios.defaults.baseURL = 'http://localhost:3000/'
const api = {
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
get: (url, params) => {
return new Promise((resolve, reject) => {
axios.get(url, {
params: params
})
.then((response) => {
resolve(response.data)
})
.catch((error) => {
reject(error)
})
})
},
post: (url, params) => {
return new Promise((resolve, reject) => {
axios.post(url, params)
.then((response) => {
resolve(response.data)
})
.catch((error) => {
reject(error)
})
})
},
put: (url, params) => {
return new Promise((resolve, reject) => {
axios.put(url, params)
.then((response) => {
resolve(response.data)
})
.catch((error) => {
reject(error)
})
})
},
delete: (url, params) => {
return new Promise((resolve, reject) => {
axios.delete(url)
.then((response) => {
resolve(response.data)
})
.catch((error) => {
reject(error)
})
})
}
}
export default api
3. 封裝好axios後回到頁面檔案
<template>
<!--ApiTemp.vue-->
<div>
API測試
</div>
</template>
<script>
export default {
data() {
return{
tableData: [] //宣告個空陣列
}
},
methods: {
async packageGetData() {
const url = 'tableData' // json-server API 位置
let res = await this.$api.get(url)
this.tableData = [...res] // 透過ES6語法將res的內容直接繼承到tableData
console.log(res)
},
},
created() {
this.packageGetData() // 在created 階段把API資料叫進來
}
}
</script>
接著在開發人員工具畫面的Console中就可以看到我們從 tableData
Get 回來的資料了。
實際專案使用Axios多以POST為主,包含取得資料(GET)和修改(UPDATE)、刪除(DELETE)等行為都是給一個包裝好指定參數的物件,送到後端驗證之後回傳新的結果,真正在有後端同事配合的狀況下,會需要一些環境變數,也要把串接的CODE改寫,包含封裝和攔截器設定等。
QS套件
通常主要用來處理原生form物件POST行為當中 application/x-www-form-urlencoded 編碼上的問題,先轉字串後再使用這個套件做Qs.stringify
,但說句實話,「Server Side 可以完全無視這件事」,僅在這稍稍提一下它的存在是幹嘛的。
npm install qs
.env.development
這邊視部署情況去更改不同檔名的參數,比如QAT就是staging,PROD就是production
ENV = 'development'
VUE_APP_BASE_API = 'http://my-api-server.com'
VUE_APP_VERSION = '0.0.0'
api.js
import axios from 'axios'
import Cookies from 'js-cookie'
// QS用不用其實都可以,前面說過這個機制Server Side可以無視
import Qs from 'qs'
export function request(config) {
const service = axios.created({
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
timeout: 60000,
transformRequest: [(data) => {
let ret = ''
const tempData = getJwtData(data)
for (const it in tempData) {
ret += encodeURIComponent(it) + '=' + encodeURIComponent(tempData[it]) + '&';
}
return ret
}]
})
const getJwtData = (data) => {
// 如果jwt的key中含有空字串或者undefined,刪除該條jwt
for (const key in data) {
if (data.hasOwnProperty(key)) {
const val = data[key]
if (val === '' || val === undefined){
delete data[key]
}
}
}
const userInfo = Cookies.get('userInfo')
let token = ''
if (userInfo) {
token = JSON.parse(userInfo).token
}
const jwt = token + '.' + encodeURIComponent(btoa(encodeURIComponent(JSON.stringify(data))))
return {data:jwt}
}
// --->
// 設置 request 攔截器
axios.interceptors.request.use((config) => {
const token = JSON.parse(Cookies.get('userInfo').token)
// token本身是會過期的,需要返回狀態查詢是不是過期
token && (config.headers.Authorization = token)
return config
})
// 設置 response 攔截器
axios.interceptors.response.use(
(response) => {
// 如果回應200表示正常連線,可以返回資料結果,反之reject
if (response.status === 200) {
return Promise.resolve(response);
} else {
return Promise.reject(response);
}
},
// 根據不同的回應碼來訂製不同的錯誤訊息
(error) => {
if (error && error.response) {
switch (error.response.status) {
case 400:
error.message = 'Request Error!'
break
case 401:
error.message = 'No permission, need login.'
break
case 403:
error.message = 'Access denied!'
break
case 404:
// 自動帶入 request 地址的寫法
error.message = `Address not exist: ${error.response.config.url}`
break
case 408:
error.message = 'Request timeout!'
break
case 500:
error.message = 'Server inside error!'
break
case 501:
error.message = 'Service not allowed!'
break
case 502:
error.message = 'Bad gateway!'
break
case 503:
error.message = 'No service!'
break
case 504:
error.message = 'Gateway timeout!'
break
case 505:
error.message = 'http version not supported!'
break
default:
break
}
}
Message({
message: error.message,
type: 'error',
duration: 5 * 1000
})
console.log('error',error)
return Promise.reject(error)
}
)
return service(config)
}
api_path.js
import request from '@/api' // api.js
export const GetDataList = (data) =>
request({
url: '/post/tableData',
method: 'post',
data,
})
component.vue
<template>
<div id="page">
<el-table :data="tableData" >
...
...
</el-table>
</div>
</template>
<script>
import { GetDataList } from '@/api_path'
export default {
data() {
return {
tableData: [],
currentPage: 1,
pageLimit: 20
}
},
computed: {
getLanguage() {
return this.$store.lang
}
},
methods: {
async fetchDataList() {
const jwt = {
"language": this.getLanguage(),
"page": this.currentPage,
"page_limit": this.pageLimit
}
console.log('post jwt: ', jwt)
let res = await GetDataList(jwt)
if (res.result == '1') {
this.tableData = res.data
console.log('get result: ', res.data)
} else {
alert(res.data.errMessage)
}
}
},
created() {
// created 階段就開始發出request
this.fetchDataList()
}
}
</script>
VueJS
Axios