### ts配置路由
①安裝:npm i vue-router -S
②src下新建pages/Home.vue(還有Goods.vue、Detail.vue等頁面):
<template> <div class="home"> <h2>首頁</h2> </div> </template> <script lang="ts"> import Vue from 'vue'; import {Component} from "vue-property-decorator"; @Component({}) export default class Home extends Vue{ } </script>
③src下新建plugins/router.ts:(注意Reg.vue和Detail.vue分別是以import和require的方式實現路由懶加載)
import Vue from "vue"; import VueRouter from "vue-router"; Vue.use(VueRouter);// 安裝插件 import Home from "../pages/Home.vue"; import Goods from "../pages/Goods.vue"; import User from "../pages/User.vue"; import Login from "../pages/Login.vue"; import NoPage from "../pages/NoPage.vue"; let routes=[ {path:"/home",component:Home}, {path:"/goods",component:Goods}, {path:"/user",component:User}, {path:"/login",component:Login}, {path:"/reg",component:()=>import("../pages/Reg.vue")}, {path:"/detail",component:(resolve:any)=>{require(["../pages/Detail.vue"],resolve)}}, {path:"*",component:NoPage}, {path:"/",redirect:"/home"}, ]; let router=new VueRouter({ mode:"history", routes }); export default router;
④main.js中引入router並注冊:
import router from "./plugins/router" new Vue({ render: h => h(App), router }).$mount('#app')
⑤App.vue中開辟路由空間:
<router-view></router-view>
### 路由守衛
router.ts中:
/* 全局守衛 */ router.beforeEach((to,from,next)=>{ console.log("全局前置守衛") next(); }) router.afterEach((to,from)=>{ console.log("全局后置守衛") }) // 路由獨享守衛 {path:"/user",component:User,beforeEnter: (to:Route, from:Route, next:Function) => { console.log("路由獨享前置守衛") next(); }},
注意:設置路由獨享守衛時,定義的Route類型是ts自動引入的(import VueRouter, { Route } from "vue-router";)
組件內部守衛:(注意這里的Route類型是手動引入的)
(1)User.vue中:
import {Route} from "vue-router"; @Component({ /* 這里寫自定義指令、過濾器、守衛鈎子函數 */ beforeRouteEnter (to:Route, from:Route, next:Function) { // 由於寫在裝飾器中,鈎子函數可以自動推測出to、from、next的類型,所以可以加類型也可以不加 console.log("組件內前置守衛") next(); } })
(2)Reg.vue中:
import {Route} from "vue-router"; @Component({ beforeRouteLeave (to:Route, from:Route, next:Function) { console.log("組件內后置守衛") next(); } })
### 數據交互-axios
安裝:npm i axios @types/axios -S
注意:不是所有的插件都帶有類型聲明文件,只有類型聲明文件才能保證支持ts,沒有類型聲明文件的插件需要安裝類型聲明文件。
(1)axios初步使用:
①public下新建data/user.json:
{ "data":[ {"username":"wxm"} ] }
②Home.vue中:
import axios from "axios"; export default class Home extends Vue{ mounted():void { axios({ url:"/data/user.json" // public中的數據可以直接訪問 }).then( res=>console.log(res.data) ) } }
(2)訪問json-server數據:
需要先將json-server開啟數據服務,再設置url:url:"http://localhost:3000/data"
(3)訪問tiantian-api數據:
①開啟tiantian-api數據服務:npm run start
②設置跨域代理(根目錄下新建vue.config.js):
module.exports={ devServer:{ proxy:{ "/v3":{ target:"http://localhost:3000", changeOrigin:true } } } }
③代理地址替代原地址:
url:"/v3/homepage"
(4)axios攔截器:
①plugins下新建axios.ts:
import axios, { AxiosRequestConfig, AxiosResponse } from "axios"; import router from './router'; import { TUser } from '@/types'; //請求攔截器 axios.interceptors.request.use((config:AxiosRequestConfig):AxiosRequestConfig=>{ /* 抓取token,攜帶到響應頭 顯示loading */ let user:TUser=window.localStorage.getItem("user"); user=user?JSON.parse(user):""; config.headers={token:user?.token}// 攜帶到請求頭 return config; },(error)=>{ return Promise.reject(error) }) //響應攔截器 axios.interceptors.response.use((response:AxiosResponse<any>):AxiosResponse<any>=>{ /* token過期,跳轉login,保留當前地址 關閉loading */ // 判斷如果有錯誤(token過期),並且當前路徑不是login,則跳轉到login頁面,並且將當前的全路徑帶過去 if(response.data.err==2 && !router.currentRoute.fullPath.includes("/login")){ router.push({path:"/login",query:{path:router.currentRoute.fullPath}}); } return response; },(error)=>{ return Promise.reject(error) }) // 對外暴露 export default axios;
②Home.vue中使用時用封裝的axios替代原來的axios:
import axios from "../plugins/axios";
(5)將axios掛載到window下:
①src/types/index.ts中:
// 定義全局變量,重定義了Window接口 declare global{ interface Window{ axios(config:AxiosRequestConfig):AxiosPromise<any> } }
②axios攔截器中對外暴露的時候添加:
window.axios=axios;
③main.js中引入:
import "./plugins/axios"
④Home.vue中使用時不用引入任何的axios,直接用window.axios()使用:
mounted():void { window.axios({ url:"/v3/homepage" }).then( res=>console.log(res.data) ) }
### 登錄驗證邏輯
①axios.ts的響應攔截器中利用router.currentRoute.fullPath可以拿到當前要去往的路由,保留當前地址:
// 判斷如果有錯誤(token過期),並且當前路徑不是login,則跳轉到login頁面,並且將當前的全路徑帶過去 if(response.data.err==2 && !router.currentRoute.fullPath.includes("/login")){ router.push({path:"/login",query:{path:router.currentRoute.fullPath}}); }
②Login.vue中點擊登錄時進行請求,如果沒有錯誤,則將token存到localStorage中,並且跳轉到響應攔截器中保留的路由:
<button @click="login">登錄</button>
export default class Login extends Vue{ public login():void { window.axios({ url:"/api/login", method:"post", data:{username:"chenghao",password:"chenghao123"} }).then( res=>{ if(res.data.err==0){ // 種token到localStorage中 window.localStorage.setItem("user",JSON.stringify(res.data)) // 跳轉到之前的頁面 this.$router.replace(this.$route.query.path as string) } } ) } }
### 狀態管理
①安裝:npm i vuex vuex-class -S
未完待續……