VueRouter总结

478 阅读5分钟

这是我参与更文挑战的第9天,活动详情查看: 更文挑战

VueRouter总结

单页面的跳转核心思想:改变 url 不刷新页面

VueRouter总共分为三种模式

  • Hash模式
  • History模式
  • abstract模式 (abstract 模式针对的是没有浏览器环境的情况. 比如 Weex 客户端开发,内部是没有浏览器 API 的,那么 Vue-Router 自身会对环境做校验,强制切换到 abstract 模式,如果默认在 Vue-Router 的配置项中不写 mode 的值,在浏览器环境下会默认启用 Hash 模式,在移动客户端下使用 abstract 模式。)

Hash模式

特点

  1. VueRouter的默认模式
  2. 浏览器的兼容性强,甚至可以兼容低版本的IE浏览器
  3. 比History模式要更方便在服务器端部署,因为没有URL重定向的问题
  4. 运用在了单页面开发的路由模式上(只在一个页面切换对应组件就行)
  5. 地址栏里有个#image-20210518173320264
  6. #号后面内容的改变,不会引起页面对服务端的请求,所以也就不会重新加载页面。

应用场景

​ 浏览器上看到这样一种场景,点击某个文字,网页会跳转到某一个固定的位置,并且页面不会刷新。这便是浏览器的 a 标签锚点。Hash 模式被运用在了单页面开发的路由模式上,下面我们来简单实现一个通过 Hash 去控制页面组件的展示。

Hash 模式被运用在了单页面开发的路由模式上,下面我们来简单实现一个通过 Hash 去控制页面组件的展示。 浏览器原生方法为我们提供了一个监听事件 hashchange,它能监听到的改变如下:

  • 点击 a 标签改变 URL 地址;
  • 浏览器的前进后退行为;
  • 通过 window.location 方法改变地址栏;

hashchange:HTML5增加了hashchange 事件,用于在URL散列值(URL最后# 后面的部分)发生变化时通知开发者。也就是说每次URL的散列值变化的时候这个事件都会触发

案例:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <div>
        <ul>
            <!-- 因为是锚点,所以点击还是在当前页面 -->
            <li><a href="#/page1">page1</a></li>
            <li><a href="#/page2">page2</a></li>
        </ul>
        <div id="route-view"></div>
    </div>
    <script type="text/javascript">
        //当HTML文档被完全加载和解析完成后
        window.addEventListener("DOMContentLoaded",Load)
        //当地址栏发生变化的时候触发hashchange
        window.addEventListener("hashchange",HashChange)
        var routeView = null;
        function Load(){
            routeView = document.getElementById('route-view');
            // console.log('routeView_1',routeView);
            // console.log("1")
            //网页加载完成后先调用一次hashchange函数
            HashChange();
            
        }
        function HashChange(){
            console.log('location.hash',location.hash);
            switch(location.hash){
                case '#/page1':
                    routeView.innerHTML = 'page1'
                    return
                case '#/page2':
                    routeView.innerHTML = 'page2'
                    return 
                default:
                    routeView.innerHTML = 'page1'
                    console.log('routeView',routeView);
                    return
            }
        }
    </script>
</body>
</html>

div的routeview:告诉你当前在哪块

page1,page2: 相当于页面的容器组件

首先页面加载完成后,触发load函数,因为浏览器加载完成是不执行hashchange的,下面要显示一个默认在哪个页面,所以要在load函数里执行HashChange。然后点击a标签跳转锚点,因为是a标签锚点,所以点击实际还是在当前页面,根据a标签的href改变了URL的散列值(也就是#后内容),自动触发了hashchange事件,然后触发HashChange,然后根据URL的散列值给id为route-view的div改值。可以改值 也可以干很多事情 只不过是这个案例仅仅改值。

location.hash是什么

比如当前的URL是https://anblog.top#2333回车 在控制台输入

location.hash
//"#2333"

Histroy模式

特点

  1. 无法监听到pushState 、replaceState、 a标签这三种变化。
  2. 可以监听到浏览器的前进和后退。
  3. 好看,没有#
  4. 需要和后端配合,不然就是404.

vue-router默认hash模式 —— 使用 URL 的 hash 来模拟一个完整的 URL,于是当 URL 改变时,页面不会重新加载。

如果觉得hash有#很丑,我们可以用路由的 history 模式,这种模式充分利用 history.pushState API 来完成 URL 跳转而无须重新加载页面。

无法监听到pushState 、replaceState、 a标签这三种变化的解决方法:把页面上的a标签全部遍历一次,阻止a标签的默认事件

实现一个案例

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <div>
        <ul>
            <li><a href="/page1">page1</a></li>
            <li><a href="/page2">page2</a></li>
        </ul>
        <div id="route-view"></div>
    </div>
    <script>
        //页面加载完毕后执行load
        window.addEventListener('DOMContentLoaded',load)
        //声明PopChange为popstate的回调函数 每次触发popstate就会执行PopChange
        window.addEventListener('popstate',PopChange)
        var routeView = null
        function load(){
            routeView = document.getElementById('route-view')
            PopChange()
            // 获取所有有href属性的a标签节点
            var aList = document.querySelectorAll('a[href]')
            //遍历a标签节点数组,组织默认事件,添加点击事件回调函数
            //foreach对数组每一项都运行传入的函数,没有返回值
            aList.forEach(aNode => aNode.addEventListener('click',function(e){
                e.preventDefault();//阻止a标签的默认事件
                var href = aNode.getAttribute('href')
                //浏览器对象history history.pushState(state,title,url) 
                // 可以让开发者改变浏览器URL而不会加载新页面。为此,可以使用history.pushState() 方法。
                //state: 一个与指定网址相关的状态对象,popState事件触发时,该对象会传入回调函数。如果不需要这个对象,可填null
                //title: 新页面的标题,但是所有浏览器都忽略这个值,可填null
                //url: 新的网址,必须与当前页面处在同一个域
                history.pushState(null, null, href)
                PopChange()
            }))
        }
        //改变那个div的显示
        function PopChange() {
            //window的location属性 
            //window.location.href 返回当前页面的 href (URL)
            // window.location.hostname 返回 web 主机的域名
            // window.location.pathname 返回当前页面的路径或文件名
            // window.location.protocol 返回使用的 web 协议(http: 或 https:)
            // window.location.assign 加载新文档
            console.log('location',location);
            switch(location.pathname) {
                case '/page1':
                    routeView.innerHTML = 'page1'
                    return
                case '/page2':
                    routeView.innerHTML = 'page2'
                    return
                default: 
                    routeView.innerHTML = 'page1'
                    return
            }
        }
    </script>
</body>
</html>

通过案例可以发现,给a标签都绑定上回调函数,每次点击a标签执行回调函数,同时执行的回调函数内还有popstate的回调函数PopChange()popstate主要是监听除了pushStatereplaceState之外的地址栏变化(比如location.hash变了,或者浏览器前进后退都会触发),通过history.pushState把url拼接好。然后用回调函数进行页面id为route-view的div的修改。但所有的前提是做好配置,如果没有配置好后端,一刷新就是Cannot GET xxx ,就比如上面的例子,点击到page1,一刷新就是Cannot GET /page1.

路由使用

引入Vue-Router

案例

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <script src="https://cdn.bootcss.com/vue/2.6.11/vue.min.js"></script>
  <script src="https://cdn.bootcss.com/vue-router/3.1.3/vue-router.min.js"></script>
  <title>Vue Router</title>
</head>
<body>
  <div id="app">
    <ul>
      <!-- 使用 router-link 组件来导航. -->
      <!-- 通过传入 `to` 属性指定链接. -->
      <!-- <router-link> 默认会被渲染成一个 `<a>` 标签 -->
      <router-link to="/page1">Go to Page1</router-link>
      <br/>
      <router-link to="/page2">Go to Page2</router-link>
    </ul>
    <!-- 路由出口 -->
    <!-- 路由匹配到的组件将渲染在这里 -->
    <router-view></router-view>
  </div>
  <script>
      //定义路由组件,也可以从别的文件import进来
      const Page1 = {
          template: '<div>Page1</div>'
      }
      const Page2 = {
          template: '<div>Page2</div>'
      }
      //定义路由
      //每个路由需要映射一个组件,
      //component也可以是Vue.extend()创建的组件构造器
      //或者只是一个组件配置对象
      const routes = [
          { path: '/page1',component: Page1 },
          { path: '/page2',component: Page2 }
      ]
      //3.创建VueRouter实例 
      const router = new VueRouter({
          routes:routes
      })
      //4.创建和挂载根实例
      //通过router配置参数注入路由,从而让整个应用有路由功能
      const app = new Vue({
          router:router
      }).$mount('#app')

  </script>
</body>
</html>

运行后可以发现,地址栏有个#, VueRouter确实默认是hash模式

image-20210519083709427

获取全局路由跳转参数的变化

<script>
...
    //4.创建和挂载根实例
    const app = new Vue({
        router:router,
        watch: {
            $route(to, from) {
                console.log('to',to);
                console.log('from',from);
            }
        }
    }).$mount('#app')
</script>

image-20210519084330685

添加监听后,可以拿到to和from两个参数,to代表跳转后的页面参数,from代表你从哪个页面跳转来的,得到这两个参数,我们就可以设置一级二级页面,用来制作过场动画,也可以添加页面顶部的页面加载进度条。

获取路由中带的参数

路由传递参数有两种方法,分别是通过传递to和from中的query参数和params参数来实现的

通过传递参数:传递$route的query参数

router-link标签添加参数

<router-link :to="{path:'/page1', query:{ id:111 }}">Go to Page1</router-link>

从下图看,to和from就是对应路由的$route

image-20210519101317087

通过路由中带参数:传递$route的Params参数

route-link组件

<router-link to="/page2/222">Go to Page2</router-link>

定义路由组件

const Page2 = {
    //   2.通过params
    template: '<div>Page2 {{$route.params.id}}</div>'
}

定义路由

const routes = [
          { path: '/page1',component: Page1 },
           //   2.通过params
          { path: '/page2/:id',component: Page2 }
      ]

image-20210519093040900

可以看到修改了

重定向页面

当用户输入一个不存在的路由,Vue-Router无法匹配到的时候,需要默认回到首页,这就要用到重定向匹配,代码如下

const routes = [
  { path: '/page1', component: Page1 },
  { path: '/page2', component: Page2 },
  { path: '*', redirect: '/page1' }
]

这样当你输入了不存在的路由就会自动跳转到page1。

参考:

router.vuejs.org/zh/guide/#j…

segmentfault.com/a/119000001…

juejin.cn/book/684473…