了解Vue Router实现原理

本文详细解析了Vue Router的hash模式与history模式的实现原理,包括如何利用hashchange和popstate事件监听URL变化,以及pushState和replaceState方法的应用。此外,文章还介绍了在vue项目中实现路由按需加载的三种方式,如es提案的import()和webpack的require.ensure()。
摘要由CSDN通过智能技术生成

一.vueRouter实现方式:

vue-router是通过hash和History interface两种方式实现前端路由,更新视图但不重新请求页面,在vue-router中,mode参数决定采用哪一种方式来实现路由跳转。

mode参数:

  • 默认hash
  • history(注:如果浏览器不支持history新特性,则采用hash方式)
  • 如果不在浏览器环境中则使用abstract(node环境下)
    当你选择了mode类型之后,程序会根据你选择的mode类型创建不同的history对象(HashHistory或HTML5History或AbstractHistory)

hash模式:

1. vue-router 默认 hash 模式 —— 使用 URL 的 hash 来模拟一个完整的 URL,于是当 URL 改变时,页面不会重新加载。
2. hash虽然出现在URL中,但不会被包括在HTTP请求中。它是用来指导浏览器动作的,对服务器端完全无用,因此,改变hash不会重新加载页面
3. 每一次改变hash(window.location.hash),都会在浏览器的访问历史中增加一个记录
4. hash 模式的原理是 onhashchange 事件(监测hash值变化)

hash 路由模式的实现主要是基于下面几个特性:

  • URL 中 hash 值只是客户端的一种状态,也就是说当向服务器端发出请求时,hash 部分不会被发送;
  • hash 值的改变,都会在浏览器的访问历史中增加一个记录。因此我们能通过浏览器的回退、前进按钮控制hash 的切换;
  • 可以通过 a 标签,并设置 href 属性,当用户点击这个标签后,URL 的 hash 值会发生改变;或者使用 JavaScript 来对 loaction.hash 进行赋值,改变 URL 的 hash 值;
  • 我们可以使用 hashchange 事件来监听 hash 值的变化,从而对页面进行跳转(渲染)。

HashHistory替换路由有两种方式:HashHistory.push() 和 HashHistory.replace():

  • HashHistory.push() 将新路由添加到浏览器访问历史的栈项
$router.push() // 调用方法  push()等方法只是一个代理实际是调用的具体history对象的对应方法
HashHistory.push() // 根据Hash模式调用,设置hash并添加到浏览器历史记录(添加到栈项)(window.location.hash = xxx)
History.transitonTo() //transitionTo()方法是父类中定义的是用来处理路由变化中的基础逻辑的,  监测更新,更新则调用History.updateRoute()
History.updateRoute() // 更新路由
{app._route = route} // 替换当前app路由
vm.render() // 更新视图
  • HashHistory.replace
replace() 方法与push()方法不同之处在于,它并不是将新路由添加到浏览器访问历史的栈项,而是替换当前路由

history

- 分利用了html5 history interface 中新增的 pushState() 和 replaceState() 方法
- 这两个方法应用于浏览器记录栈,在当前已有的 back、forward、go 基础之上,它们提供了对历史记录修改的功能。
- 只是当它们执行修改时,虽然改变了当前的 URL ,但浏览器不会立即向后端发送请求。

HTML5History替换路由两种方式:pushState()和replaceState()

  • window.history.pushState(stateObject, title, URL)

  • window.history.replaceState(stateObject, title, URL)

hash模式基本类似,只不过将对window.location.hash直接进行赋值和window.location.replace()分别改为了调用history.pushState()和history.replaceState()方法。

history 路由模式的实现主要基于存在下面几个特性:

  • pushState 和 repalceState 两个 API 来操作实现 URL 的变化 ;
  • 我们可以使用 popstate 事件来监听 url 的变化,从而对页面进行跳转(渲染);
  • history.pushState() 或 history.replaceState() 不会触发 popstate 事件,这时我们需要手动触发页面跳转(渲染)。

异同:

  • pushState设置新的URL可以是与当前URL同源的任意URL;而hash只能修改#后面的部分,故只可以设置与当前同文档的URL
  • pushState设置的新URL可以与当前URL一模一样,这样也会把记录添加到栈中;而hash设置的新值必须与原来不一样才会触发记录添加到栈中
  • pushState通过stateObject可以添加任意类型的数据到记录中,而hash只可添加短字符串
  • pushState可以额外设置title属性供后续使用
  • 比如用户直接在地址栏中输入并回车,浏览器重启重新加载应用等。hash模式仅改变hash部分的内容,而hash部分是不会包含在HTTP请求中的。history模式会将url修改的和正常请求后端的url一样,如果后端没有配置对应的(/user/id)路由处理,则会返回404错误

当你使用 history 模式时,URL 就像正常的 url,例如 http://yoursite.com/user/id,也好看!

不过这种模式要玩好,还需要后台配置支持。因为我们的应用是个单页客户端应用,如果后台没有正确的配置,当用户在浏览器直接访问 http://oursite.com/user/id 就会返回 404,这就不好看了。
所以呢,你要在服务端增加一个覆盖所有情况的候选资源:如果 URL 匹配不到任何静态资源,则应该返回同一个 index.html 页面,这个页面就是你 app 依赖的页面

const router = new VueRouter({
  mode: 'history',
  routes: [
    { path: '*', component: NotFoundComponent }
  ]
})

vue项目实现路由按需加载(路由懒加载)的3种方式

  • vue-router配置路由,使用vue的异步组件技术,可以实现按需加载。
        {
            path: '/promisedemo',
            name: 'PromiseDemo',
            component: resolve => require(['../components/PromiseDemo'], resolve)
        }
  • es提案的import()
// 下面2行代码,没有指定webpackChunkName,每个组件打包成一个js文件。
const ImportFuncDemo1 = () => import('../components/ImportFuncDemo1')
const ImportFuncDemo2 = () => import('../components/ImportFuncDemo2')
// 下面2行代码,指定了相同的webpackChunkName,会合并打包成一个js文件。
// const ImportFuncDemo = () => import(/* webpackChunkName: 'ImportFuncDemo' */ '../components/ImportFuncDemo')
// const ImportFuncDemo2 = () => import(/* webpackChunkName: 'ImportFuncDemo' */ '../components/ImportFuncDemo2')
export default new Router({
    routes: [
        {
            path: '/importfuncdemo1',
            name: 'ImportFuncDemo1',
            component: ImportFuncDemo1
        },
        {
            path: '/importfuncdemo2',
            name: 'ImportFuncDemo2',
            component: ImportFuncDemo2
        }
    ]
})
  • webpack提供的require.ensure()
        {
            path: '/promisedemo',
            name: 'PromiseDemo',
            component: resolve => require.ensure([], () => resolve(require('../components/PromiseDemo')), 'demo')
        },
        {
            path: '/hello',
            name: 'Hello',
            // component: Hello
            component: resolve => require.ensure([], () => resolve(require('../components/Hello')), 'demo')
        }

参考:
【源码拾遗】从vue-router看前端路由的两种实现
vue项目实现按需加载的3种方式:vue异步组件、es提案的import()、webpack的require.ensure()

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值