VueRoute知识点-cnblog

VueRoute 知识点

1. 路由简介

前端路由

  • 根据不同的用户事件渲染不同的页面

后端路由

  • 根据不同的请求url分发不同的服务器资源

单页面spa

  • 基于url的hash变化

2. VueRouter的基本使用

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>

<body>

    <div class="" id="app">

        <router-link to="/user">
            User页面
        </router-link>

        <router-link to="/home">Home</router-link>

        <router-view>

        </router-view>
    </div>
    <script src="./lib/vue-2.6.12.js"></script>
    <script src="./lib/vue-router.min.js"></script>
    <script>

        const User = {
            template: '<div>User页面</div>'
        }

        const Home = {
            template: '<div>Home页面</div>'
        }

        const router = new VueRouter({
            routes: [
                { path: '/user', component: User },
                { path: '/home', component: Home }
            ]
        })

        const vm = new Vue({
            el: '#app',
            data: {

            },

            router
        })

    </script>
</body>

</html>

路由重定向

const router = new VueRouter({
            routes: [
                {path:'/',redirect:'/home'}
                { path: '/user', component: User },
                { path: '/home', component: Home }
            ]
        })

路由嵌套

const router = new VueRouter({
            routes: [
                {path:'/',redirect:'/home'}
                { path: '/user', component: User,
                	children:[
                		{path:'tab1',component:Tab1},
                        {path:'tab2',component:Tab2}     
            		]
                },
                { path: '/home', component: Home }
            ]
        })
  • User组件
const User={
    template:'<div>
    	<router-link>tab1</router-link>
    	<router-link>tab2</router-link>
    	<router-view></router-view>
    </div>'
}

动态路由

const router = new VueRouter({
            routes: [
                {path:'/',redirect:'/home'}
                // 动态路由,允许传递参数
                { path: '/user/:id', component: User,props:true
                	
                	children:[
                		{path:'tab1',component:Tab1},
                        {path:'tab2',component:Tab2}     
            		]
                },
                { path: '/home', component: Home }
            ]
        })
  • 获取路由参数
const User={
    template: '<h1>User 组件 -- 用户id为: {{$route.params.id}}</h1>'
}

// 或者props
const User={
   props:['id']
}

传递对象时路由参数

const router = new VueRouter({
            routes: [
                {path:'/',redirect:'/home'}
                // 动态路由,允许传递参数
                // 值为对象,结构赋值
                { path: '/user/:id', component: User,props: { uname: 'lisi', age: 12 }} 
                	
                	children:[
                		{path:'tab1',component:Tab1},
                        {path:'tab2',component:Tab2}     
            		]
                },
                { path: '/home', component: Home }
            ]
        })

传递的值为函数的类型

const router = new VueRouter({ 
    routes: [       
        // 如果 props 是一个函数,则这个函数接收 route 对象为自己的形参  
        //route就是参数对象。
        { path: '/user/:id',  
        component: User,  
        props: route => ({ uname: 'zs', age: 20, id: route.params.id })} 
    ] 
  }) 
 
  const User = { 
    props: ['uname', 'age', 'id'],    
      template:<div>用户信息:{{ uname + '---' + age + '---' + id}}</div>'  
}

命名路由

const router = new VueRouter({ 
    routes: [       
        
        { path: '/user/:id', 
         //路由命名 
         name:'user',
        component: User,  
        props: route => ({ uname: 'zs', age: 20, id: route.params.id })} 
    ] 
  }) 
  • 模板使用
const user={
    template:'<div>
    	<router-link :to="{name:'user',params:{}}"></router-link>
    </div>'
}

编程式导航

 // 字符串(路径名称)   
router.push('/home')  
// 对象   
router.push({ path: '/home' })  
// 命名的路由(传递参数)  
router.push({ name: '/user', params: { userId: 123 }})   
// 带查询参数,变成 /register?uname=lisi   
router.push({ path: '/register', query: { uname: 'lisi' }}) 

路由守卫

  • 全局路由守卫
const router = new VueRouter({ 
    routes: [       
        
        { path: '/user/:id', 
         //路由命名 
         name:'user',
         
         // 添加元数据,表名改路由是需要权限的
         meta:{
             auth:true
         }
        component: User,  
        props: route => ({ uname: 'zs', age: 20, id: route.params.id })} 
    ] 
  }) 


router.beforeEach((to,from,next)=>{
    if(to.meta.auth){
        // 有权限路由
        if(localStorage.getItem('token')){
            next()
        }else{
            // 重定向到登录页面
            // 登录成功后回跳
            next("/login?redirect="+to.fullPath)
        }
    }else{
        next()
    }
})

const login(){
    
    methods:{
        
        login(){
            localstorage.setItem('token')
            this.$router.push(this.$router.query.redirect)
        }
    }
}
  • 路由独享守卫
const router = new VueRouter({ 
    routes: [       
        
        { path: '/user/:id', 
         //路由命名 
         name:'user',
         
         // 添加元数据,表名改路由是需要权限的
         meta:{
             auth:true
         },
         
         // 守卫写在路由配置里
         beforeEnter(to,from,next){
             // 有权限路由
            if(localStorage.getItem('token')){
                next()
            }else{
                // 重定向到登录页面
                // 登录成功后回跳
                next("/login?redirect="+to.fullPath)
            }
         }
        component: User,  
        props: route => ({ uname: 'zs', age: 20, id: route.params.id })} 
    ] 
  }) 
  • 配置项
beforeRouteEnter
beforeRouteUpdate
beforeRouteLeave
  • 组件内路由守卫
const User={
     beforeRouteEnter(to, from, next) {
          if (window.isLogin) {
            next();
          } else {
            next("/login?redirect=" + to.fullPath);
          }
        },
}

3. addRoutes 动态路由添加

  • 静态路由配置式
  • 动态路由在用户登录时按需添加,添加的都是当前用户可以访问的
const router=new VueRouter({
    routes:[
        // 只配置登录的静态路由
        {path:'/logon',component:Login}
    ]
})

const Login={
    
    methods:{
        // login方法
        login(){
            localStorage.setItem("token",'xxx')
            // 动态添加当前用户可以访问的路由
            this.$router.addRoutes([
                {path:'/',redirect:'/users'},
                {path:'/user',component:User},
                {path:'/home',component:Home},
            ])
            
            // 登录成功后跳转到重定向的地方,或者直接跳转到/
            if(this.$router.query.redirect){
                this.$router.push(this.$router.query.redirect)
            }else{
                this.$router.push("/")
            }
        }
    }
}

// 设置全局的路由守卫

router.beforeEach((to,from,next)=>{
    // 判断用户是否登录
    
    const token=localStorage.getItem("item")
    
    if(token){
        // 去登录页面
        if(to.path==='/login'){
            // 去登录页面
            next("/")
        }else{
            next()
        }
    }else{
        // 没有登录
        if(to.if(to.path==='/login'){
            // 去登录页面
            next()
        }else{
            next("/login?redirect="+to.fullPath)
        }path==='login'){
            // 去登录页面
            next()
        }else{
            next("/login?redirect="+to.fullPath)
        }
    }
    
})

4. 路由组件缓存

<keep-alive></keep-alive>


// 可添加的属性,include确定哪些组件需要缓存
// 属性值为组件的name属性
const Home={
    name:'home',
    ...
}
<keep-alive include="home,user"></keep-alive>

// 可添加的属性,exclude除了这些组件其他组件需要缓存
<keep-alive include="login"></keep-alive>
  • 钩子函数触发
    • 页面属性,如果组件加了缓存:created—>mounted—>activited

13.2 History模式的使用

History模式需要服务器的支持,为什么呢?

因为在单页面的应用中,只有一个页面,也就是index.html这个页面,服务端不存在http://www.test.com/login这样的地址,也就说如果刷新浏览器,

请求服务器,是找不到/login这个页面的,所以会出现404的错误。(在传统的开发模式下,输入以上的地址,会返回login这个页面,而在单页面应用中,只有一个页面为index.html

所以说,在服务端应该除了静态资源外都返回单页应用的index.html

下面我们开始history模式来演示一下对应的问题。

首先添加一个针对404组件的处理

首先在菜单栏中添加一个链接:

 <!-- 左侧菜单栏 -->
          <div class="content left">
            <ul>
              <li><router-link to="/users"> 用户管理</router-link></li>
              <li><router-link to="/rights"> 权限管理</router-link></li>
              <li><router-link to="/goods"> 商品管理</router-link></li>
              <li><router-link to="/orders"> 订单管理</router-link></li>
              <li><router-link to="/settings"> 系统设置</router-link></li>
              <li><router-link to="/about"> 关于</router-link></li>
            </ul>
          </div>

这里我们添加了一个“关于”的链接,但是我们没有为其定义相应的组件,所以这里需要处理404的情况。

  const NotFound = {
        template: `<div>
            你访问的页面不存在!!
          </div>`,
      };

在程序中添加了一个针对404的组件。

 const router = new VueRouter({
        mode: "history",
        const router = new VueRouter({
        mode: "history",
        routes: [
          { path: "/login", component: Login },
          { path: "*", component: NotFound },
          {
            path: "/",
            component: App,
            redirect: "/users",
            children: [
              {
                path: "/users",
                component: Users,
                meta: {
                  auth: true,
                },
                // beforeEnter(to, from, next) {
                //   if (window.isLogin) {
                //     next();
                //   } else {
                //     next("/login?redirect=" + to.fullPath);
                //   }
                // },
              },
              { path: "/userinfo/:id", component: UserInfo, props: true },
              { path: "/rights", component: Rights },
              { path: "/goods", component: Goods },
              { path: "/orders", component: Orders },
              { path: "/settings", component: Settings },
            ],
          },
        ],
      });

在上面的代码中,指定了处理404的路由规则,同时将路由的模式修改成了history模式。同时,启用这里启用了其它的组件的路由规则配置,也就是不在login方法中使用addRoutes方法来动态添加路由规则了。

login 方法修改成如下形式:

 login() {
            // window.isLogin = true;
            window.sessionStorage.setItem("isLogin", true);
            if (this.$route.query.redirect) {
              //   //动态添加路由:
              //   this.$router.addRoutes([
              //     {
              //       path: "/",
              //       component: App,
              //       redirect: "/users",
              //       children: [
              //         {
              //           path: "/users",
              //           component: Users,
              //           meta: {
              //             auth: true,
              //           },
              //           // beforeEnter(to, from, next) {
              //           //   if (window.isLogin) {
              //           //     next();
              //           //   } else {
              //           //     next("/login?redirect=" + to.fullPath);
              //           //   }
              //           // },
              //         },
              //         { path: "/userinfo/:id", component: UserInfo, props: true },
              //         { path: "/rights", component: Rights },
              //         { path: "/goods", component: Goods },
              //         { path: "/orders", component: Orders },
              //         { path: "/settings", component: Settings },
              //       ],
              //     },
              //   ]);
              this.$router.push(this.$route.query.redirect);
            } else {
              this.$router.push("/");
            }
          }

现在已经将前端vue中的代码修改完毕了,下面我们要将页面的内容部署到node.js服务器中。

而且上面的代码中,我们使用了sessionStorage来保存登录用户的信息,不在使用window下的isLogin

对应的data内容下的代码也要修改:

const Login = {
        data() {
          return {
            isLogin: window.sessionStorage.getItem("isLogin"),
          };
        },

路由守卫中的代码进行如下修改:

jsrouter.beforeEach((to, from, next) => {
        //to:去哪个页面,from来自哪个页面,next继续执行.
        if (window.sessionStorage.getItem("isLogin")) {
          //用户已经登录
          if (to.path === "/login") {
            // 用户已经登录了,但是又访问登录页面,这里直接跳转到用户列表页面
            next("/");
          } else {
            //用户已经登录,并且访问其它页面,则运行访问

            next();
          }
        } else {
          //用户没有登录,并且访问的就是登录页,则运行访问登录页
          if (to.path === "/login") {
            next();
          } else {
            //用户没有登录,访问其它页面,则跳转到登录页面。
            next("/login?redirect=" + to.fullPath);
          }
        }
      });

在上面的代码中,我们也是通过sessionStorage来获取登录信息。

index.html完整代码如下:

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <title>基于vue-router的案例</title>
    <script src="./lib/vue.js"></script>
    <script src="https://unpkg.com/vue-router/dist/vue-router.js"></script>
    
  </head>
  <body>
    <div id="app"><router-view></router-view></div>
    <script>
      const App = {
        template: `<div>
        <!-- 头部区域 -->
        <header class="header">传智后台管理系统</header>
        <!-- 中间主体区域 -->
        <div class="main">
          <!-- 左侧菜单栏 -->
          <div class="content left">
            <ul>
              <li><router-link to="/users"> 用户管理</router-link></li>
              <li><router-link to="/rights"> 权限管理</router-link></li>
              <li><router-link to="/goods"> 商品管理</router-link></li>
              <li><router-link to="/orders"> 订单管理</router-link></li>
              <li><router-link to="/settings"> 系统设置</router-link></li>
              <li><router-link to="/about"> 关于</router-link></li>
            </ul>
          </div>
          <!-- 右侧内容区域 -->
          <div class="content right"><div class="main-content">
            <keep-alive include='goods'>
             <router-view />
             </keep-alive>
             </div></div>
        </div>
        <!-- 尾部区域 -->
        <footer class="footer">版权信息</footer>
      </div>`,
      };
      const Users = {
        data() {
          return {
            userlist: [
              { id: 1, name: "张三", age: 10 },
              { id: 2, name: "李四", age: 20 },
              { id: 3, name: "王五", age: 30 },
              { id: 4, name: "赵六", age: 40 },
            ],
          };
        },
        methods: {
          goDetail(id) {
            console.log(id);
            this.$router.push("/userinfo/" + id);
          },
        },
        template: `<div>
          <h3>用户管理区域</h3>
          <table>
            <thead>
              <tr><th>编号</th><th>姓名</th><th>年龄</th><th>操作</th></tr>
            </thead>
            <tbody>
              <tr v-for="item in userlist" :key="item.id">
                <td>{{item.id}}</td>
                <td>{{item.name}}</td>
                <td>{{item.age}}</td>
                <td>
                  <a href="javascript:;" @click="goDetail(item.id)">详情</a>
                </td>
              </tr>
            </tbody>
          </table>
        </div>`,
        // beforeRouteEnter(to, from, next) {
        //   if (window.isLogin) {
        //     next();
        //   } else {
        //     next("/login?redirect=" + to.fullPath);
        //   }
        // },
      };
      //用户详情组件
      const UserInfo = {
        props: ["id"],
        template: `<div>
            <h5>用户详情页 --- 用户Id为:{{id}}</h5>
            <button @click="goback()">后退</button>
          </div>`,
        methods: {
          goback() {
            // 实现后退功能
            this.$router.go(-1);
          },
        },
      };

      const Rights = {
        template: `<div>
          <h3>权限管理区域</h3>
        </div>`,
      };
      const Goods = {
        name: "goods",
        template: `<div>
          <h3>商品管理区域</h3>
        </div>`,
        created() {
          console.log(new Date());
        },
      };
      const Orders = {
        template: `<div>
          <h3>订单管理区域</h3>
        </div>`,
      };
      const Settings = {
        template: `<div>
          <h3>系统设置区域</h3>
        </div>`,
      };
      const NotFound = {
        template: `<div>
            你访问的页面不存在!!
          </div>`,
      };
      const Login = {
        data() {
          return {
            isLogin: window.sessionStorage.getItem("isLogin"),
          };
        },

        template: `<div>
            <button @click="login" v-if="!isLogin">登录</button>
            <button @click="logout" v-else>注销</button>
            </div>`,
        methods: {
          login() {
            // window.isLogin = true;
            window.sessionStorage.setItem("isLogin", true);
            if (this.$route.query.redirect) {
              //   //动态添加路由:
              //   this.$router.addRoutes([
              //     {
              //       path: "/",
              //       component: App,
              //       redirect: "/users",
              //       children: [
              //         {
              //           path: "/users",
              //           component: Users,
              //           meta: {
              //             auth: true,
              //           },
              //           // beforeEnter(to, from, next) {
              //           //   if (window.isLogin) {
              //           //     next();
              //           //   } else {
              //           //     next("/login?redirect=" + to.fullPath);
              //           //   }
              //           // },
              //         },
              //         { path: "/userinfo/:id", component: UserInfo, props: true },
              //         { path: "/rights", component: Rights },
              //         { path: "/goods", component: Goods },
              //         { path: "/orders", component: Orders },
              //         { path: "/settings", component: Settings },
              //       ],
              //     },
              //   ]);
              this.$router.push(this.$route.query.redirect);
            } else {
              this.$router.push("/");
            }
          },
          logout() {
            this.isLogin = window.isLogin = false;
          },
        },
      };

      // 创建路由对象
      const router = new VueRouter({
        mode: "history",
        routes: [
          { path: "/login", component: Login },
          { path: "*", component: NotFound },
          {
            path: "/",
            component: App,
            redirect: "/users",
            children: [
              {
                path: "/users",
                component: Users,
                meta: {
                  auth: true,
                },
                // beforeEnter(to, from, next) {
                //   if (window.isLogin) {
                //     next();
                //   } else {
                //     next("/login?redirect=" + to.fullPath);
                //   }
                // },
              },
              { path: "/userinfo/:id", component: UserInfo, props: true },
              { path: "/rights", component: Rights },
              { path: "/goods", component: Goods },
              { path: "/orders", component: Orders },
              { path: "/settings", component: Settings },
            ],
          },
        ],
      });
      //实现全局守卫
      // router.beforeEach((to, from, next) => {
      //   //to:去哪个页面,from来自哪个页面,next继续执行.
      //   //判断哪个路由需要进行守卫,这里可以通过元数据方式
      //   if (to.meta.auth) {
      //     if (window.isLogin) {
      //       next();
      //     } else {
      //       next("/login?redirect=" + to.fullPath);
      //     }
      //   } else {
      //     next();
      //   }
      // });

      router.beforeEach((to, from, next) => {
        //to:去哪个页面,from来自哪个页面,next继续执行.
        if (window.sessionStorage.getItem("isLogin")) {
          //用户已经登录
          if (to.path === "/login") {
            // 用户已经登录了,但是又访问登录页面,这里直接跳转到用户列表页面
            next("/");
          } else {
            //用户已经登录,并且访问其它页面,则运行访问

            next();
          }
        } else {
          //用户没有登录,并且访问的就是登录页,则运行访问登录页
          if (to.path === "/login") {
            next();
          } else {
            //用户没有登录,访问其它页面,则跳转到登录页面。
            next("/login?redirect=" + to.fullPath);
          }
        }
      });

      const vm = new Vue({
        el: "#app",
        router,
      });
    </script>
  </body>
</html>

当然,项目的目录结构做了一定的调整,如下图所示:

image-20200826223502724

web目录下面,存放的是index.html,在webserver目录下面存放的是node代码。

下面看一下具体的node代码的实现。

app.js文件中的代码如下:

const path = require("path");
//导入处理history模式的模块
const history = require("connect-history-api-fallback");
const express = require("express");
const app = express();
//注册处理history模式的中间件
// app.use(history())
//处理静态资源的中间件,处理web目录下的index.html
app.use(express.static(path.join(__dirname, "../web")));
app.listen(3000, () => {
  console.log("服务器开启");
});

connect-history-api-fallback模块的安装如下(注意在上面的代码中还没有使用该模块)

npm install --save connect-history-api-fallback

下面还需要安装express

npm install express

启动服务

node app.js

现在在地址栏中输入:http://localhost:3000就可以访问网站了。

并且当我们去单击左侧的菜单的时候,可以实现页面的切换,同时单击“关于”的时候,会出现NotFound组件中的内容。

经过测试发现好像没有什么问题,那这是什么原因呢?你想一下当我们单击左侧菜单的时候,路由是怎样工作的呢?

因为现在我们开启了路由的history模式,而该模式是通过HTML5中的history中的api来完成路由的操作的,也就是当我们单击菜单的时候,是通过history.pushState( ) 方法来修改地址栏中的地址,实现组件的切换,而且还会把地址保存的历史记录中(也就是可以单击浏览器中后退按钮,实现后退等操作),但是它并不会向服务器发送请求。

所以说现在整个操作都是在客户端完成的。

但是,当我刷新了浏览器以后,会出现怎样的情况呢?

image-20200826224843519

上图的含义就是,当单击浏览器中的刷新按钮的时候,会向服务器发送请求,要求node服务器处理这个地址,但是服务器并没有处理该地址,所以服务器会返回404

以上就是如果vue-router开启了history模式后,出现的问题。

下面解决这个问题,在服务端启用connect-history-api-fallback模块就可以了,如下代码所示:

const path = require("path");
//导入处理history模式的模块
const history = require("connect-history-api-fallback");
const express = require("express");
const app = express();
//注册处理history模式的中间件
app.use(history());
//处理静态资源的中间件
app.use(express.static(path.join(__dirname, "../web")));
app.listen(3000, () => {
  console.log("服务器开启");
});

服务端的代码做了修改以后,一定要服务端重新启动node app.js

然后经过测试以后发现没有问题了。

那么现在你考虑一下,具体的工作方式是什么?

当我们在服务端开启对history模式的支持以后,我们刷新浏览器,会想服务器发送请求,例如:http://localhost:3000/orders

服务器接收该请求,那么用于服务器开启了history模式,然后服务器会检查,根据该请求所访问的页面是不存在的,所以会将单页面应用的index.html返回给浏览器。浏览器接收index.html页面后,会判断路由地址,发现地址为orders,所以会加载该地址对应的组件内容。

5. hash模式和history模式

  • hash模式:
    • URL#后面的内容作为路径地址,地址发生变化不会发起请求,但会触发hashchange事件
    • 监听hashchange事件,根据路由地址找到新组件重新渲染
  • history模式
    • history.pushState()改变地址栏,不会发送请求
    • 监听popstate事件,监听浏览器历史操作变化,记录改变后的地址,单击前进或者是后退按钮的时候触发该事件
    • 根据当前路由地址找到对应组件渲染

6.nginx配置history模式

 location / {
            root   html;
            index  index.html index.htm;
			try_files $uri $uri/ /index.html;
        }
  • 路由查找规则
    • 单页面应用,查找路由,比如查找/user,会尝试查找user.html,查找不到,就会找到html页面下的index.html,这样就实现了history模式

7. Vue运行时版和完整版

  • Vue-Cli创建的默认是运行时版本,不支持template模板
    • 不支持下述代码
Vue.component("router-link",{
    template:"<a><slot></slot></a>"
})
  • 完整版具有编译器,可以识别
    • vue.config.js中配置位置版
const { defineConfig } = require('@vue/cli-service')
module.exports = defineConfig({
  transpileDependencies: true,

  // 修改为完整版vue
  runtimeCompiler: true
})

使用render函数解决template不识别的问题

Vue.component('router-link', {
      props: {
        to: String
      },

      methods: {
        clickHandle (e) {
          // 阻止默认行为
          e.preventDefault()

          // 因为是history模式,调用history.pushState
          history.pushState({}, '', this.$props.to)

          // data属性同步更新
          self.data.current = this.$props.to
        }
      },

      // template: '<a :href="to"><slot></slot></a>'
      render (h) {
        // 直接渲染a标签会导致点击时发送页面刷新
        // 我们给a添加click的事件处理函数
        return h(
          'a',
          {
            attrs: {
              href: this.$props.to
            },

            on: {
              click: this.clickHandle
            }
          },

          [this.$slots.default]
        )
      }
    })

8. vue-router 手写版本1


// 实现vue-router的插件

// 我们先看看vue-router的基本使用
// import Vue from 'vue'
// import VueRouter from 'vue-router'
// Vue.use(VueRouter)

// const router = new VueRouter({
//   routes: [
//     { path: '/user', component: User },
//     { path: '/home', component: Home }
//   ]
// })

// new Vue({
//   router,
//   render: h => h(App)
// }).$mount('#app')

/*
   自己实现一个vue-router

*/

// 定义成插件模式,实现install方法 ,使用 VueRouter.install(Vue)
let _Vue = null

export default class VueRouter {
  // 1.判断插件是否已经安装过

  // new Vue({
  //   router,
  //   render: h => h(App)
  // }).$mount('#app')
  // 当我们在new Vue 时,把router对象挂载上去
  static install (Vue) {
    // console.log(Vue)
    if (VueRouter.install.installed) {
      return
    }

    VueRouter.install.installed = true

    // 2.将Vue实例保存到_Vue全局变量中
    _Vue = Vue
    // 3.没有安装过,挂载router对象到Vue的原型上
    // 直接挂载不行,this指向为VueRouter,我们如果用call,this是Vue实例还没有被创建出来(生命周期)
    // _Vue.prototype.$router=this.$options.router
    _Vue.mixin({
      // 这个生命周期是,vue实例已经创建完成
      // this.$options===>{
      //   router,
      //   render: h => h(App)
      // }

      beforeCreate () {
        // console.log(this.$options, 'options')
        if (this.$options.router) {
          // 这个就是传递进去的router,组件创建时时没有router这个选项的
          _Vue.prototype.$router = this.$options.router

          // 挂载成功后,进行路由解析和router-link创建,注意这里的this为vue实例
          this.$options.router.init()
        }
      }
    })
  }

  // 解析routes对象
  createRouteMap () {
    this.options.routes.forEach((route) => {
      this.routeMap[route.path] = route.component
    })
  }

  // 创建router-link组件
  initComponents (Vue) {
    const self = this
    Vue.component('router-link', {
      props: {
        to: String
      },

      methods: {
        clickHandle (e) {
          // 阻止默认行为
          e.preventDefault()

          // 因为是history模式,调用history.pushState
          history.pushState({}, '', this.$props.to)

          // data属性同步更新
          self.data.current = this.$props.to
        }
      },

      // template: '<a :href="to"><slot></slot></a>'
      render (h) {
        // 直接渲染a标签会导致点击时发送页面刷新
        // 我们给a添加click的事件处理函数
        return h(
          'a',
          {
            attrs: {
              href: this.$props.to
            },

            on: {
              click: this.clickHandle
            }
          },

          [this.$slots.default]
        )
      }
    })

    // 创建Router-view组件

    Vue.component('router-view', {

      // template: '<a :href="to"><slot></slot></a>'
      render (h) {
        // console.log('router-view render')
        // 根据routeMap获取对应的组件
        // console.log(self.data.current)
        // console.log(self.routeMap)
        console.log(self)
        const component = self.routeMap[self.data.current]
        return h(component)
      }
    })
  }

  // 处理前进和后退按钮,当我们点击浏览器的前进后退按钮时,popstate事件会被触发
  // 我们的数据,也就是this.data.current也需要同步更新
  initEvents () {
    window.addEventListener('popstate', () => {
      // 使用箭头函数后,this指向不在是window,而是VueRouter实例
      // 获取一下当前的路由路径
      this.data.current = window.location.pathname
    })
  }

  // 我们需要在new Vue() 当vue实例被创建之后指向解析routes对象和创建router-link组件

  init () {
    this.createRouteMap()
    this.initComponents(_Vue)
    this.initEvents()
  }

  // 构造函数
  // const router = new VueRouter({
  //   routes: [
  //     { path: '/user', component: User },
  //     { path: '/home', component: Home }
  //   ]
  // })

  constructor (options) {
    // 根据传入的选项进行路由规则解析
    this.options = options

    // 我们设置一个map,存储路由地址到组件的映射
    this.routeMap = {}
    // 设置当前路由的路由地址,响应式
    this.data = _Vue.observable({
      current: '/'
    })
  }
}

9. vue-router 版本2

', {

  // template: '<a :href="to"><slot></slot></a>'
  render (h) {
    // console.log('router-view render')
    // 根据routeMap获取对应的组件
    // console.log(self.data.current)
    // console.log(self.routeMap)
    console.log(self)
    const component = self.routeMap[self.data.current]
    return h(component)
  }
})

}

// 处理前进和后退按钮,当我们点击浏览器的前进后退按钮时,popstate事件会被触发
// 我们的数据,也就是this.data.current也需要同步更新
initEvents () {
window.addEventListener(‘popstate’, () => {
// 使用箭头函数后,this指向不在是window,而是VueRouter实例
// 获取一下当前的路由路径
this.data.current = window.location.pathname
})
}

// 我们需要在new Vue() 当vue实例被创建之后指向解析routes对象和创建router-link组件

init () {
this.createRouteMap()
this.initComponents(_Vue)
this.initEvents()
}

// 构造函数
// const router = new VueRouter({
// routes: [
// { path: ‘/user’, component: User },
// { path: ‘/home’, component: Home }
// ]
// })

constructor (options) {
// 根据传入的选项进行路由规则解析
this.options = options

// 我们设置一个map,存储路由地址到组件的映射
this.routeMap = {}
// 设置当前路由的路由地址,响应式
this.data = _Vue.observable({
  current: '/'
})

}
}




### 9. vue-router 版本2

- 看文件夹下codes
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值