一、使用vue-cli搭建項目 註意:在mac執行該命令會報錯 改用管理員許可權執行以下命令即可 $ sudo npm install -g vue-cli$ vue init webpack tcloud$ cd tcloud$ npm run dev 完成了利用腳手架創建並啟動一個vue的項目,可 ...
一、使用vue-cli搭建項目
$ npm install -g vue-cli
註意:在mac執行該命令會報錯
改用管理員許可權執行以下命令即可
$ sudo npm install -g vue-cli
$ vue init webpack tcloud
$ cd tcloud
$ npm run dev
完成了利用腳手架創建並啟動一個vue的項目,可訪問http://localhost:8080 看到下圖界面說明項目啟動成功。
二、引入vuex並實現數據持久化
1.首先對目錄結構調整後如下:
- assets 前端靜態資源 包括圖片、樣式、和js插件
- components 可復用的組件
- lang 國際化/多語言環境配置文件 cn.js 業務相關文本翻譯-簡體 tw.js 業務相關文本翻譯-繁體
- pages 業務組件
- router 路由配置文件
- vuex store相關配置
- App.vue 根組件
- main.js 入口文件
2.安裝vuex
$ npm install vuex --save
3.創建store文件
import Vue from 'vue' import Vuex from 'vuex' Vue.use(Vuex) const state = { test: 1, lang: 'cn' } const mutations = { add: (state, data) => { state.selectGoods.push(data) state.test++ } } const actions = { addTest: ({ commit }, data) => { commit('add', data) } } export default new Vuex.Store({ state, mutations, actions })
4.在入口文件main.js中引入store
import store from './store/store'
// 並掛載到根實例中
new Vue({
el: '#app',
store,
router,
components: { App },
template: '<App/>'
})
5.vuex-persistedstate實現數據持久化
vuex可以進行全局的狀態管理,但刷新後刷新後數據會消失
- 安裝
$ npm install vuex-persistedstate --save
- 在store.js中引入及配置
import createPersistedState from "vuex-persistedstate" const store = new Vuex.Store({ // ... plugins: [createPersistedState({ storage: window.sessionStorage, // 不設置預設存儲到localStorage reducer(val) { return { // 指定需要持久化的state lang: val.lang } } })]
- 生效後在瀏覽器Storage中展示效果
三、實現多語言環境-簡繁體轉換
1.安裝vue-i18n
$ npm install vue-i18n --save
2.準備業務相關文本的翻譯文件
3.創建VueI18n 實例
代碼如下
import Vue from 'vue' import VueI18n from 'vue-i18n' import cnlocale from './cn' import twlocale from './tw' import store from '@/vuex/store' Vue.use(VueI18n) const i18n = new VueI18n({ locale: store.state.lang || 'cn', messages: { cn: { ...cnlocale }, tw: { ...twlocale } } }) export default i18n
4.在main.js中引入vue-i18n
import i18n from './lang/index' // 把 i18n 掛載到 vue 根實例上 new Vue({ el: '#app', i18n, axios, store, router, components: { App }, template: '<App/>' })
5.引用
// 在HTML模板中引用 <van-button @click="logout" type="default">{{$t('log.out')}}</van-button> // 在 js 模板中使用 this.$t('log.in')
6.解決切換語言後刷新界面時出現一瞬間白屏的問題
利用在app.vue的<router-view></router-view>加上v-if屬性和provide/inject,具體代碼實現如下:
// App.vue文件 <template> <div id="app"> <router-view v-if="isAlive" /> </div> </template> <script> export default { name: 'App', provide () { return { reload: this.reload } }, data () { return { isAlive: true } }, methods: { reload () { this.isAlive = false this.$nextTick(function () { this.isAlive = true }) } } } </script>
接下來在需要刷新的組件中註入reload函數
<template> <button @click="refresh"></button> </template> <script> export default{ name: 'refresh', inject: ['reload'], methods: { refresh () { this.reload() } } } </script>
四、實現登錄攔截
1.路由攔截
首先在定義路由的時候就需要多添加一個自定義欄位requireAuth
,用於判斷該路由的訪問是否需要登錄。如果用戶已經登錄(token存在),則順利進入路由, 否則就進入登錄頁面。
const routes = [ { path: '/', name: '/', component: Index }, { path: '/repository', name: 'repository', meta: { requireAuth: true, // 添加該欄位,表示進入這個路由是需要登錄的 }, component: Repository }, { path: '/login', name: 'login', component: Login } ];
定義完路由後,我們主要是利用vue-router
提供的鉤子函數beforeEach()
對路由進行判斷
router.beforeEach((to, from, next) => { if (to.meta.requireAuth) { // 判斷該路由是否需要登錄許可權 if (store.state.token) { // 通過vuex state獲取當前的token是否存在 next(); } else { next({ path: '/login', query: {redirect: to.fullPath} // 將跳轉的路由path作為參數,登錄成功後跳轉到該路由 }) } } else { next(); } })
每個鉤子方法接收三個參數:
- to: Route: 即將要進入的目標 路由對象
- from: Route: 當前導航正要離開的路由
- next: Function: 一定要調用該方法來 resolve 這個鉤子。執行效果依賴 next 方法的調用參數。
- next(): 進行管道中的下一個鉤子。如果全部鉤子執行完了,則導航的狀態就是 confirmed (確認的)。
- next(false): 中斷當前的導航。如果瀏覽器的 URL 改變了(可能是用戶手動或者瀏覽器後退按鈕),那麼 URL 地址會重置到 from 路由對應的地址。
- next('/') 或者 next({ path: '/' }): 跳轉到一個不同的地址。當前的導航被中斷,然後進行一個新的導航
2.axios攔截器
當前token失效了,但是token依然保存在本地,這時候你去訪問需要登錄許可權的路由時,實際上應該讓用戶重新登錄。 這時候就需要結合 http 攔截器 + 後端介面返回的http 狀態碼來判斷
// http request 攔截器 axios.interceptors.request.use( config => { if (store.state.token) { // 判斷是否存在token,如果存在的話,則每個http header都加上token config.headers.Authorization = `token ${store.state.token}`; } return config; }, err => { return Promise.reject(err); }); // http response 攔截器 axios.interceptors.response.use( response => { return response; }, error => { if (error.response) { switch (error.response.status) { case 401: // 返回 401 清除token信息並跳轉到登錄頁面 store.commit(types.LOGOUT);router.currentRoute.name !== 'login' && router.replace({
path: 'login', query: {redirect: router.currentRoute.fullPath} }) } } return Promise.reject(error.response.data) // 返回介面返回的錯誤信息 });