vue+ts下集----ts配置路由、路由守卫、数据交互-axios、登录验证逻辑、状态管理

### 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
    未完待续……




猜你喜欢

转载自www.cnblogs.com/wuqilang/p/12508315.html