vue-router如何实现修改url但不加载HTML

一、背景和意义

vue-router中vue中的常用组件,其在切换页面时,不会重新请求获取新页面的HTML代码,与常见的页面重定向不一样。本文参照相关源码简要介绍其实现方式。

二、vue-router的使用

在vue中,使用vue-router的方法为:

html 复制代码
<template>
...
<button @click="toUserInfoPage()" ...>跳转到个人中心</button>
...
</template>

<script>
import { useRouter } from 'vue-router'

const router = useRouter();
...
function toUserInfoPage() {
  router.push({ name: "userInfo" });
}
...
</script>

当点"跳转到个人中心"的按钮之后,地址栏上的URL会变成/userInfo,但浏览器并没有请求/userInfo页面的html代码,看上去很流畅。

三、vue-router相关源码解读

创建Router对象的代码是在node_modules\vue-router\dist\vue-router.mjs文件中的createRouter方法,需要注意的是它是在vue初始化插件的时候调用,而不是在const router = useRouter()这段代码中调用。createRouter函数的调用在前,const router = useRouter()只是获取之前创建Router对象。

createRouter方法的大致结构如下:

javascript 复制代码
function createRouter(options) {
  ...
  function push(to) {
    return pushWithRedirect(to);
  }
  function pushWithRedirect(to, redirectedFrom) {
    // pushWithRedirect的实现代码比较复杂,这里先省略
  }
  ...
  const router = {
    ...
    push,
    ...
  };
  return router;
}

接下来在前面的例子中,当点"跳转到个人中心"的按钮之后,调用router.push({ name: "userInfo" })方法,这里的push方法也就是createRouter中定义的push方法。

在调用push方法时,push方法会调用pushWithRedirect方法,该方法的大致结构为:

javascript 复制代码
function pushWithRedirect(to, redirectedFrom) {
    ...
    return (failure ? Promise.resolve(failure) : navigate(toLocation, from))
            .catch((error) => ...)
            .then((failure) => {
            if (failure) {
                ...
            }
            else {
                // if we fail we don't finalize the navigation
                failure = finalizeNavigation(toLocation, from, true, replace, data);
            }
            ...
            return failure;
        });
}

中pushWithRedirect中的Promise是先写catch再写then,这与很多人的习惯写法不太一样。这里调用了一个finalizeNavigation方法,该方法的大致结构为:

javascript 复制代码
function finalizeNavigation(toLocation, from, isPush, replace, data) {
    ...
    // change URL only if the user did a push/replace and if it's not the initial navigation because
    // it's just reflecting the url
    if (isPush) {
        // on the initial navigation, we want to reuse the scroll position from
        // history state if it exists
        if (replace || isFirstNavigation)
            routerHistory.replace(toLocation.fullPath, assign({
                scroll: isFirstNavigation && state && state.scroll,
            }, data));
        else
            routerHistory.push(toLocation.fullPath, data);
    }
    ...
}

前面调用router.push({ name: "userInfo" })方法时,会走routerHistory.push(toLocation.fullPath, data)这个代码分支。routerHistory则是useHistoryStateNavigation这个方法创建的一个对象,该方法的结构为:

javascript 复制代码
function useHistoryStateNavigation(base) {
    const { history, location } = window;
    ...
    function changeLocation(to, state, replace) {
        ...
        try {
            // BROWSER QUIRK
            // NOTE: Safari throws a SecurityError when calling this function 100 times in 30 seconds
            history[replace ? 'replaceState' : 'pushState'](state, '', url);
            ...
        } catch (err) {
            ...
        }
    }
    function push(to, data) {
        ...
        changeLocation(to, state, false);
        ...
    }
    return {
        ...
        push,
        ...
    };
}

也就是push方法又调用了一个changeLocation方法,第三个参数replace传false。那么changeLocation就会调用window.history.pushState修改浏览器的url地址,使用该方法修改url地址时则不会请求相关页面的HTML代码。

另外这里有一行注释:// NOTE: Safari throws a SecurityError when calling this function 100 times in 30 seconds,也就是在Safari浏览器中,如果频繁调用window.history.pushState可能会报错,vue-router加了一个try...catch错误处理,我们自己在使用window.history.pushState实现其他功能时,也可以像vue-router那样做一下错误处理。

相关推荐
灵感__idea1 小时前
Hello 算法:贪心的世界
前端·javascript·算法
GreenTea3 小时前
一文搞懂Harness Engineering与Meta-Harness
前端·人工智能·后端
killerbasd4 小时前
牧苏苏传 我不装了 4/7
前端·javascript·vue.js
吴声子夜歌4 小时前
ES6——二进制数组详解
前端·ecmascript·es6
码事漫谈5 小时前
手把手带你部署本地模型,让你Token自由(小白专属)
前端·后端
ZC跨境爬虫5 小时前
【爬虫实战对比】Requests vs Scrapy 笔趣阁小说爬虫,从单线程到高效并发的全方位升级
前端·爬虫·scrapy·html
爱上好庆祝5 小时前
svg图片
前端·css·学习·html·css3
橘子编程5 小时前
JavaScript与TypeScript终极指南
javascript·ubuntu·typescript
王夏奇5 小时前
python中的__all__ 具体用法
java·前端·python
叫我一声阿雷吧6 小时前
JS 入门通关手册(45):浏览器渲染原理与重绘重排(性能优化核心,面试必考
javascript·前端面试·前端性能优化·浏览器渲染·浏览器渲染原理,重排重绘·reflow·repaint