返回顶部
首页 > 资讯 > 精选 >Vue-Router的实现原理是什么
  • 767
分享到

Vue-Router的实现原理是什么

2023-07-04 17:07:36 767人浏览 八月长安
摘要

这篇文章主要介绍“Vue-Router的实现原理是什么”的相关知识,小编通过实际案例向大家展示操作过程,操作方法简单快捷,实用性强,希望这篇“Vue-Router的实现原理是什么”文章能帮助大家解决问题。路由既然我们在分析路由,我们首先来说

这篇文章主要介绍“Vue-Router的实现原理是什么”的相关知识,小编通过实际案例向大家展示操作过程,操作方法简单快捷,实用性强,希望这篇“Vue-Router的实现原理是什么”文章能帮助大家解决问题。

路由

既然我们在分析路由,我们首先来说说什么是路由,什么是后端路由、什么是前端路由。

路由就是根据不同的 url 地址展示不同的内容或页面,早期路由的概念是在后端出现的,通过服务器端渲染后返回页面,随着页面越来越复杂,服务器端压力越来越大。后来ajax异步刷新的出现使得前端也可以对url进行管理,此时,前端路由就出现了。(学习视频分享:WEB前端开发编程基础视频)

我们先来说说后端路由

后端路由

后端路由又可称之为服务器端路由,因为对于服务器来说,当接收到客户端发来的Http请求,就会根据所请求的URL,来找到相应的映射函数,然后执行该函数,并将函数的返回值发送给客户端。

对于最简单的静态资源服务器,可以认为,所有URL的映射函数就是一个文件读取操作。 对于动态资源,映射函数可能是一个数据库读取操作,也可能是进行一些数据的处理,等等。

然后根据这些读取的数据,在服务器端就使用相应的模板来对页面进行渲染后,再返回渲染完毕的html页面。早期的jsp就是这种模式。

前端路由

刚刚也介绍了,在前后端没有分离的时候,服务端都是直接将整个 HTML 返回,用户每次一个很小的操作都会引起页面的整个刷新(再加上之前的网速还很慢,所以用户体验可想而知)。

在90年代末的时候,微软首先实现了 ajax(Asynchronous javascript And XML) 这个技术,这样用户每次的操作就可以不用刷新整个页面了,用户体验就大大提升了。

虽然数据能异步获取不用每个点击都去请求整个网页,但是页面之间的跳转还是会加载整个网页,体验不是特别好,还有没有更好的方法呢?

至此异步交互体验的更高级版本 SPA单页应用 就出现了。单页应用不仅仅是在页面交互是无刷新的,连页面跳转都是无刷新的。既然页面的跳转是无刷新的,也就是不再向后端请求返回 HTML页面。

页面跳转都不从后端获取新的HTML页面,那应该怎么做呢?所以就有了现在的前端路由。

可以理解为,前端路由就是将之前服务端根据 url 的不同返回不同的页面的任务交给前端来做。在这个过程中,js会实时检测url的变化,从而改变显示的内容。

前端路由优点是用户体验好,用户操作或页面跳转不会刷新页面,并且能快速展现给用户。缺点是首屏加载慢,因为需要js动态渲染展示内容。而且由于内容是js动态渲染的所以不利于SEO

下面我们正式进入Vue-Router原理分析阶段。

分析Vue-Router.install方法

我们先来看看install.js,这个方法会在Vue.use(VueRouter)的时候被调用。

// install.jsimport View from './components/view'import Link from './components/link'export let _Vueexport function install (Vue) {  // 不会重复安装  if (install.installed && _Vue === Vue) return  install.installed = true  _Vue = Vue  const isDef = v => v !== undefined  // 为router-view组件关联路由组件  const reGISterInstance = (vm, callVal) => {    let i = vm.$options._parentVnode    // 调用vm.$options._parentVnode.data.registerRouteInstance方法    // 而这个方法只在router-view组件中存在,router-view组件定义在(../components/view.js @71行)    // 所以,如果vm的父节点为router-view,则为router-view关联当前vm,即将当前vm做为router-view的路由组件    if (isDef(i) && isDef(i = i.data) && isDef(i = i.registerRouteInstance)) {      i(vm, callVal)    }  }  Vue.mixin({    beforeCreate () {      // 这里只会进来一次,因为只有Vue根实例才会有router属性。      if (isDef(this.$options.router)) {        // 所以这里的this就是Vue根实例        this._routerRoot = this        this._router = this.$options.router        this._router.init(this)        // 将 _route 变成响应式        Vue.util.defineReactive(this, '_route', this._router.history.current)      } else {        // 子组件会进入这里,这里也是把Vue根实例保存带_routerRoot属性上        this._routerRoot = (this.$parent && this.$parent._routerRoot) || this      }      // 为router-view组件关联路由组件      registerInstance(this, this)    },    destroyed () {      // destroyed hook触发时,取消router-view和路由组件的关联      registerInstance(this)    }  })  // 在原型上注入$router、$route属性,方便快捷访问  Object.defineProperty(Vue.prototype, '$router', {    // 上面说到每个组件的_routerRoot都是Vue根实例,所以都能访问_router    get () { return this._routerRoot._router }  })  // 每个组件访问到的$route,其实最后访问的都是Vue根实例的_route  Object.defineProperty(Vue.prototype, '$route', {    get () { return this._routerRoot._route }  })  // 注册router-view、router-link两个全局组件  Vue.component('RouterView', View)  Vue.component('RouterLink', Link)  const strats = Vue.config.optionMergeStrategies  // use the same hook merging strategy for route hooks  strats.beforeRouteEnter = strats.beforeRouteLeave = strats.beforeRouteUpdate = strats.created}

主要做了如下几件事情:

避免重复安装

为了确保 install 逻辑只执行一次,用了 install.installed 变量做已安装的标志位。

传递Vue引用减少打包体积

用一个全局的 _Vue 来接收参数 Vue,因为作为 Vue插件Vue 对象是有依赖的,但又不能去单独去 import Vue,因为那样会增加包体积,所以就通过这种方式拿到 Vue 对象。

注册全局混入

Vue-Router 安装最重要的一步就是利用 Vue.mixin,在beforeCreatedestroyed生命周期函数中注入路由逻辑。

Vue.mixin我们知道就是全局 mixin,所以也就相当于每个组件的beforeCreatedestroyed生命周期函数中都会有这些代码,并在每个组件中都会运行。

Vue.mixin({  beforeCreate () {    if (isDef(this.$options.router)) {      this._routerRoot = this      this._router = this.$options.router      this._router.init(this)      Vue.util.defineReactive(this, '_route', this._router.history.current)    } else {      this._routerRoot = (this.$parent && this.$parent._routerRoot) || this    }    registerInstance(this, this)  },  destroyed () {    registerInstance(this)  }})

在这两个钩子中,this是指向当时正在调用钩子的vue实例

这两个钩子中的逻辑,在安装流程中是不会被执行的,只有在组件实例化时执行到钩子时才会被调用

先看混入的 beforeCreate 钩子函数

它先判断了this.$options.router是否存在,我们在new Vue({router})时,router才会被保存到到Vue根实例$options上,而其它Vue实例$options上是没有router的,所以if中的语句只在this === new Vue({router})时,才会被执行,由于Vue根实例只有一个,所以这个逻辑只会被执行一次。

对于根 Vue 实例而言,执行该钩子函数时定义了 this._routerRoot 表示它自身(Vue根实例);this._router 表示 VueRouter 的实例 router,它是在 new Vue 的时候传入的;

另外执行了 this._router.init() 方法初始化 router,这个逻辑在后面讲初始化的时候再介绍。

然后用 defineReactive 方法把 this._route 变成响应式对象,保证_route变化时,router-view会重新渲染,这个我们后面在router-view组件中会细讲。

我们再看下else中具体干了啥

主要是为每个组件定义_routerRoot,对于子组件而言,由于组件是树状结构,在遍历组件树的过程中,它们在执行该钩子函数的时候 this._routerRoot 始终指向的离它最近的传入了 router 对象作为配置而实例化的父实例(也就是永远等于根实例)。

所以我们可以得到,在每个vue组件都有 this._routerRoot === vue根实例this._routerRoot._router === router对象

对于 beforeCreatedestroyed 钩子函数,它们都会执行 registerInstance 方法,这个方法的作用我们也是之后会介绍。

添加$route、$router属性

接着给 Vue 原型上定义了 $router$route 2 个属性的 get 方法,这就是为什么我们可以在任何组件实例上都可以访问 this.$router 以及 this.$route

Object.defineProperty(Vue.prototype, '$router', {get () { return this._routerRoot._router }})Object.defineProperty(Vue.prototype, '$route', {get () { return this._routerRoot._route }})

我们可以看到,$router其实返回的是this._routerRoot._router,也就是vue根实例上的router,因此我们可以通过this.$router来使用router的各种方法。

$route其实返回的是this._routerRoot._route,其实就是this._router.history.current,也就是目前的路由对象,这个后面会细说。

注册全局组件

通过 Vue.component 方法定义了全局的 <router-link><router-view> 2 个组件,这也是为什么我们在写模板的时候可以直接使用这两个标签,它们的作用我想就不用笔者再说了吧。

钩子函数的合并策略

最后设置路由组件的beforeRouteEnterbeforeRouteLeavebeforeRouteUpdate守卫的合并策略。

总结

那么到此为止,我们分析了 Vue-Router 的安装过程,Vue 编写插件的时候通常要提供静态的 install 方法,我们通过 Vue.use(plugin) 时候,就是在执行 install 方法。Vue-Routerinstall 方法会给每一个组件注入 beforeCreatedestoryed 钩子函数,在beforeCreate 做一些私有属性定义和路由初始化工作。并注册了两个全局组件,然后设置了钩子函数合并策略。在destoryed 做了一些销毁工作。

下面我们再来看看Vue-Router的实例化。

分析init方法

前面我们提到了在 install 的时候会执行 VueRouterinit 方法( this._router.init(this) ),那么接下来我们就来看一下 init 方法做了什么。

init (app: any ) {  // ...  this.apps.push(app)  // ...  // main app previously initialized  // return as we don't need to set up new history listener  if (this.app) {    return  }  this.app = app  const history = this.history    if (history instanceof HTML5History || history instanceof HashHistory) {    const handleInitialScroll = routeOrError => {      const from = history.current      const expectScroll = this.options.scrollBehavior      const supportsScroll = supportsPushState && expectScroll      if (supportsScroll && 'fullPath' in routeOrError) {        handleScroll(this, routeOrError, from, false)      }    }        // 1.setupListeners 里会对 hashchange或popstate事件进行监听    const setupListeners = routeOrError => {      history.setupListeners()      handleInitialScroll(routeOrError)    }    // 2.初始化导航    history.transitionTo(      history.getCurrentLocation(),      setupListeners,      setupListeners    )  }  // 3.路由全局监听,维护当前的route   // 当路由变化的时候修改app._route的值  // 由于_route是响应式的,所以修改后相应视图会同步更新  history.listen(route => {    this.apps.forEach(app => {      app._route = route    })  })}

这里主要做了如下几件事情:

设置了路由监听

const setupListeners = routeOrError => {  history.setupListeners()  handleInitialScroll(routeOrError)}

这里会根据当前路由模式监听hashchangepopstate事件,当事件触发的时候,会进行路由的跳转。(后面说到路由模式的时候会细说)

初始化导航

history.transitionTo(  history.getCurrentLocation(),  setupListeners,  setupListeners)

进入系统会进行初始化路由匹配,渲染对应的组件。因为第一次进入系统,并不会触发hashchange或者popstate事件,所以第一次需要自己手动匹配路径然后进行跳转。

路由全局监听

history.listen(route => {  this.apps.forEach(app => {    app._route = route  })})

当路由变化的时候修改app._route的值。由于_route是响应式的,所以修改后相应视图会同步更新。

总结

这里主要是做了一些初始化工作。根据当前路由模式监听对应的路由事件。初始化导航,根据当前的url渲染初始页面。最后切换路由的时候修改_route,由于_route是响应式的,所以修改后相应视图会同步更新。

分析VueRouter实例化

实例化就是我们new VueRouter({routes})的过程,我们来重点分析下VueRouter的构造函数。

constructor (options: RouterOptions = {}) {  // ...    // 参数初始化  this.app = null  this.apps = []  this.options = options  this.beforeHooks = []  this.resolveHooks = []  this.afterHooks = []  // 创建matcher  this.matcher = createMatcher(options.routes || [], this)  // 设置默认模式和做不支持 H5 history 的降级处理  let mode = options.mode || 'hash'  this.fallback =    mode === 'history' && !supportsPushState && options.fallback !== false  if (this.fallback) {    mode = 'hash'  }  if (!inBrowser) {    mode = 'abstract'  }  this.mode = mode  // 根据不同的 mode 实例化不同的 History 对象  switch (mode) {    case 'history':      this.history = new HTML5History(this, options.base)      break    case 'hash':      this.history = new HashHistory(this, options.base, this.fallback)      break    case 'abstract':      this.history = new AbstractHistory(this, options.base)      break    default:      if (process.env.NODE_ENV !== 'production') {        assert(false, `invalid mode: ${mode}`)      }  }}

这里主要做了如下几件事情:

初始化参数

我们看到在最开始有些参数的初始化,这些参数到底是什么呢?

this.app 用来保存根 Vue 实例。

this.apps 用来保存持有 $options.router 属性的 Vue 实例。

this.options 保存传入的路由配置,也就是前面说的RouterOptions

this.beforeHooksthis.resolveHooksthis.afterHooks 表示一些钩子函数。

this.fallback 表示在浏览器不支持 historyapi的情况下,根据传入的 fallback 配置参数,决定是否回退到hash模式。

this.mode 表示路由创建的模式。

创建matcher

matcher,匹配器。简单理解就是可以通过url找到我们对应的组件。这一块内容较多,这里笔者就不再详细分析了。

确定路由模式

路由模式平时都会只说两种,其实在vue-router总共实现了 hashhistoryabstract 3 种模式。

VueRouter会根据options.modeoptions.fallbacksupportsPushStateinBrowser来确定最终的路由模式。

如果没有设置mode就默认是hash模式。

确定fallback值,只有在用户设置了mode:history并且当前环境不支持pushState且用户没有主动声明不需要回退(没设置fallback值位undefined),此时this.fallback才为true,当fallbacktrue时会使用hash模式。(简单理解就是如果不支持history模式并且只要没设置fallbackfalse,就会启用hash模式)

如果最后发现处于非浏览器环境,则会强制使用abstract模式。

实例化路由模式

根据mode属性值来实例化不同的对象。VueRouter的三种路由模式,主要由下面的四个核心类实现

  • History

    • 基础类

    • 位于src/history/base.js

  • HTML5History

    • 用于支持pushState的浏览器

    • src/history/html5.js

  • HashHistory

    • 用于不支持pushState的浏览器

    • src/history/hash.js

  • AbstractHistory

    • 用于非浏览器环境(服务端渲染)

    • src/history/abstract.js

HTML5HistoryHashHistoryAbstractHistory三者都是继承于基础类History

这里我们详细分析下HTML5HistoryHashHistory类。

HTML5History类

当我们使用history模式的时候会实例化HTML5History类

// src/history/html5.js...export class HTML5History extends History {  _startLocation: string  constructor (router: Router, base: ?string) {    // 调用父类构造函数初始化    super(router, base)    this._startLocation = getLocation(this.base)  }  // 设置监听,主要是监听popstate方法来自动触发transitionTo  setupListeners () {    if (this.listeners.length > 0) {      return    }    const router = this.router    const expectScroll = router.options.scrollBehavior    const supportsScroll = supportsPushState && expectScroll        // 若支持scroll,初始化scroll相关逻辑    if (supportsScroll) {      this.listeners.push(setupScroll())    }    const handleRoutingEvent = () => {      const current = this.current      // 某些浏览器,会在打开页面时触发一次popstate       // 此时如果初始路由是异步路由,就会出现`popstate`先触发,初始路由后解析完成,进而导致route未更新       // 所以需要避免      const location = getLocation(this.base)      if (this.current === START && location === this._startLocation) {        return      }            // 路由地址发生变化,则跳转,如需滚动则在跳转后处理滚动      this.transitionTo(location, route => {        if (supportsScroll) {          handleScroll(router, route, current, true)        }      })    }        // 监听popstate事件    window.addEventListener('popstate', handleRoutingEvent)    this.listeners.push(() => {      window.removeEventListener('popstate', handleRoutingEvent)    })  }  // 可以看到 history模式Go方法其实是调用的window.history.go(n)  go (n: number) {    window.history.go(n)  }  // push方法会主动调用transitionTo进行跳转  push (location: RawLocation, onComplete?: Function, onAbort?: Function) {    const { current: fromRoute } = this    this.transitionTo(location, route => {      pushState(cleanPath(this.base + route.fullPath))      handleScroll(this.router, route, fromRoute, false)      onComplete && onComplete(route)    }, onAbort)  }  // replace方法会主动调用transitionTo进行跳转  replace (location: RawLocation, onComplete?: Function, onAbort?: Function) {    const { current: fromRoute } = this    this.transitionTo(location, route => {      replaceState(cleanPath(this.base + route.fullPath))      handleScroll(this.router, route, fromRoute, false)      onComplete && onComplete(route)    }, onAbort)  }  ensureURL (push?: boolean) {    if (getLocation(this.base) !== this.current.fullPath) {      const current = cleanPath(this.base + this.current.fullPath)      push ? pushState(current) : replaceState(current)    }  }  getCurrentLocation (): string {    return getLocation(this.base)  }}export function getLocation (base: string): string {  let path = window.location.pathname  const pathLowerCase = path.toLowerCase()  const baseLowerCase = base.toLowerCase()  // base="/a" shouldn't turn path="/app" into "/a/pp"  // https://GitHub.com/vuejs/vue-router/issues/3555  // so we ensure the trailing slash in the base  if (base && ((pathLowerCase === baseLowerCase) ||    (pathLowerCase.indexOf(cleanPath(baseLowerCase + '/')) === 0))) {    path = path.slice(base.length)  }  return (path || '/') + window.location.search + window.location.hash}

可以看到HTML5History类主要干了如下几件事。

  • 继承于History类,并调用父类构造函数初始化。

  • 实现了setupListeners方法,在该方法中检查了是否需要支持滚动行为,如果支持,则初始化滚动相关逻辑,监听了popstate事件,并在popstate触发时自动调用transitionTo方法。

  • 实现了go、push、replace等方法,我们可以看到,history模式其实就是使用的history api

// 可以看到 history模式go方法其实是调用的window.history.go(n)go (n: number) {  window.history.go(n)}// push、replace调用的是util/push-state.js,里面实现了push和replace方法// 实现原理也是使用的history api,并且在不支持history api的情况下使用location apiexport function pushState (url?: string, replace?: boolean) {  ...  const history = window.history  try {    if (replace) {      const stateCopy = extend({}, history.state)      stateCopy.key = getStateKey()      // 调用的 history.replaceState      history.replaceState(stateCopy, '', url)    } else {      // 调用的 history.pushState      history.pushState({ key: setStateKey(genStateKey()) }, '', url)    }  } catch (e) {    window.location[replace ? 'replace' : 'assign'](url)  }}export function replaceState (url?: string) {  pushState(url, true)}

总结

所以history模式的原理就是在js中路由的跳转(也就是使用pushreplace方法)都是通过history apihistory.pushStatehistory.replaceState两个方法完成,通过这两个方法我们知道了路由的变化,然后根据路由映射关系来实现页面内容的更新。

对于直接点击浏览器的前进后退按钮或者js调用 this.$router.go()this.$router.forward()this.$router.back()、或者原生js方法history.back()history.go()history.forward()的,都会触发popstate事件,通过监听这个事件我们就可以知道路由发生了哪些变化然后来实现更新页面内容。

注意history.pushStatehistory.replaceState这两个方法并不会触发popstate事件。在这两个方法里面他是有手动调用transitionTo方法的。

接下来我们再来看看HashHistory类

HashHistory类

当我们使用hash模式的时候会实例化HashHistory类

//src/history/hash.js...export class HashHistory extends History {  constructor (router: Router, base: ?string, fallback: boolean) {    super(router, base)    // check history fallback deeplinking    if (fallback && checkFallback(this.base)) {      return    }    ensureSlash()  }  setupListeners () {    if (this.listeners.length > 0) {      return    }    const router = this.router    const expectScroll = router.options.scrollBehavior    const supportsScroll = supportsPushState && expectScroll    if (supportsScroll) {      this.listeners.push(setupScroll())    }    const handleRoutingEvent = () => {      const current = this.current      if (!ensureSlash()) {        return      }      this.transitionTo(getHash(), route => {        if (supportsScroll) {          handleScroll(this.router, route, current, true)        }        if (!supportsPushState) {          replaceHash(route.fullPath)        }      })    }    // 事件优先使用 popstate    // 判断supportsPushState就是通过return window.history && typeof window.history.pushState === 'function'    const eventType = supportsPushState ? 'popstate' : 'hashchange'    window.addEventListener(      eventType,      handleRoutingEvent    )    this.listeners.push(() => {      window.removeEventListener(eventType, handleRoutingEvent)    })  }    // 其实也是优先使用history的pushState方法来实现,不支持再使用location修改hash值  push (location: RawLocation, onComplete?: Function, onAbort?: Function) {    const { current: fromRoute } = this    this.transitionTo(      location,      route => {        pushHash(route.fullPath)        handleScroll(this.router, route, fromRoute, false)        onComplete && onComplete(route)      },      onAbort    )  }  // 其实也是优先使用history的replaceState方法来实现,不支持再使用location修改replace方法  replace (location: RawLocation, onComplete?: Function, onAbort?: Function) {    const { current: fromRoute } = this    this.transitionTo(      location,      route => {        replaceHash(route.fullPath)        handleScroll(this.router, route, fromRoute, false)        onComplete && onComplete(route)      },      onAbort    )  }  // 也是使用的history go方法  go (n: number) {    window.history.go(n)  }  ensureURL (push?: boolean) {    const current = this.current.fullPath    if (getHash() !== current) {      push ? pushHash(current) : replaceHash(current)    }  }  getCurrentLocation () {    return getHash()  }}function checkFallback (base) {  const location = getLocation(base)  if (!/^\/#/.test(location)) {    window.location.replace(cleanPath(base + '/#' + location))    return true  }}function ensureSlash (): boolean {  const path = getHash()  if (path.charAt(0) === '/') {    return true  }  replaceHash('/' + path)  return false}// 获取 # 后面的内容export function getHash (): string {  // We can't use window.location.hash here because it's not  // consistent across browsers - Firefox will pre-decode it!  let href = window.location.href  const index = href.indexOf('#')  // empty path  if (index < 0) return ''  href = href.slice(index + 1)  return href}function getUrl (path) {  const href = window.location.href  const i = href.indexOf('#')  const base = i >= 0 ? href.slice(0, i) : href  return `${base}#${path}`}function pushHash (path) {  if (supportsPushState) {    pushState(getUrl(path))  } else {    window.location.hash = path  }}function replaceHash (path) {  if (supportsPushState) {    replaceState(getUrl(path))  } else {    window.location.replace(getUrl(path))  }}

可以看到HashHistory类主要干了如下几件事。

  • 继承于History类,并调用父类构造函数初始化。这里比HTML5History多了回退操作,所以,需要将history模式的url替换成hash模式,即添加上#,这个逻辑是由checkFallback实现的

  • 实现了setupListeners方法,在该方法中检查了是否需要支持滚动行为,如果支持,则初始化滚动相关逻辑。 监听了popstate事件或hashchange事件,并在相应事件触发时,调用transitionTo方法实现跳转。

通过const eventType = supportsPushState ? 'popstate' : 'hashchange'我们可以发现就算是hash模式优先使用的还是popstate事件。

  • 实现了go、push、replace等方法。

我们可以看到,hash模式实现的push、replace方法其实也是优先使用history里面的方法,也就是history api

// 可以看到 hash 模式go方法其实是调用的window.history.go(n)go (n: number) {  window.history.go(n)}// 在支持新的history api情况下优先使用history.pushState实现// 否则使用location apifunction pushHash (path) {  if (supportsPushState) {    pushState(getUrl(path))  } else {    window.location.hash = path  }}// 在支持新的history api情况下优先使用history.replaceState实现// 否则使用location apifunction replaceHash (path) {  if (supportsPushState) {    replaceState(getUrl(path))  } else {    window.location.replace(getUrl(path))  }}

在浏览器链接里面我们改变hash值是不会重新向后台发送请求的,也就不会刷新页面。并且每次 hash 值的变化,还会触发hashchange 这个事件。

所以hash模式的原理就是通过监听hashchange事件,通过这个事件我们就可以知道 hash 值发生了哪些变化然后根据路由映射关系来实现页面内容的更新。(这里hash值的变化不管是通过js修改的还是直接点击浏览器的前进后退按钮都会触发hashchange事件)

对于hash模式,如果是在浏览器支持history api情况下,hash模式的实现其实是和history模式一样的。只有在不支持history api情况下才会监听hashchange事件。这个我们可以在源码中看出来。

Vue-Router的实现原理是什么

关于“Vue-Router的实现原理是什么”的内容就介绍到这里了,感谢大家的阅读。如果想了解更多行业相关的知识,可以关注编程网精选频道,小编每天都会为大家更新不同的知识点。

--结束END--

本文标题: Vue-Router的实现原理是什么

本文链接: https://lsjlt.com/news/346539.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

猜你喜欢
  • Vue-Router的实现原理是什么
    这篇文章主要介绍“Vue-Router的实现原理是什么”的相关知识,小编通过实际案例向大家展示操作过程,操作方法简单快捷,实用性强,希望这篇“Vue-Router的实现原理是什么”文章能帮助大家解决问题。路由既然我们在分析路由,我们首先来说...
    99+
    2023-07-04
  • vue-router实现原理的示例分析
    这篇文章将为大家详细讲解有关vue-router实现原理的示例分析,小编觉得挺实用的,因此分享给大家做个参考,希望大家阅读完这篇文章后可以有所收获。大致流程可以看成这样:浏览器发出请求服务器监听到80端口(...
    99+
    2024-04-02
  • 一文聊聊Vue-Router的实现原理
    路由既然我们在分析路由,我们首先来说说什么是路由,什么是后端路由、什么是前端路由。路由就是根据不同的 url 地址展示不同的内容或页面,早期路由的概念是在后端出现的,通过服务器端渲染后返回页面,随着页面越来越复杂,服务器端压力越来越大。后来...
    99+
    2023-05-14
    vue-router Vue
  • Vue插槽的实现原理是什么
    这篇文章主要介绍“Vue插槽的实现原理是什么”,在日常操作中,相信很多人在Vue插槽的实现原理是什么问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”Vue插槽的实现原理是什么”的疑惑有所帮助!接下来,请跟着小编...
    99+
    2023-06-20
  • Vue keep-alive的实现原理是什么
    这篇“Vue keep-alive的实现原理是什么”文章的知识点大部分人都不太理解,所以小编给大家总结了以下内容,内容详细,步骤清晰,具有一定的借鉴价值,希望大家阅读完这篇文章能有所收获,下面我们一起来看看这篇“Vue ...
    99+
    2023-06-30
  • vue-router的工作原理
    本篇内容主要讲解“vue-router的工作原理”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“vue-router的工作原理”吧!单页面应用的工作原理我理解的单...
    99+
    2024-04-02
  • vue中v-model的实现原理是什么
    这篇文章主要介绍vue中v-model的实现原理是什么,文中介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们一定要看完!v-model的实现原理是什么?为什么要使用VueVue是一款友好的、多用途且高性...
    99+
    2024-04-02
  • Angular中的ActivatedRoute和Router原理是什么
    这篇“Angular中的ActivatedRoute和Router原理是什么”文章的知识点大部分人都不太理解,所以小编给大家总结了以下内容,内容详细,步骤清晰,具有一定的借鉴价值,希望大家阅读完这篇文章能有所收获,下面我们一起来看看这篇“A...
    99+
    2023-07-06
  • Vue中Watcher和Scheduler的实现原理是什么
    这篇文章主要介绍“Vue中Watcher和Scheduler的实现原理是什么”,在日常操作中,相信很多人在Vue中Watcher和Scheduler的实现原理是什么问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答...
    99+
    2023-06-21
  • MySQL中Router高可用的原理是什么
    今天就跟大家聊聊有关MySQL中Router高可用的原理是什么,可能很多人都不太了解,为了让大家更加了解,小编给大家总结了以下内容,希望大家根据这篇文章可以有所收获。Mysql route介绍什么是mysq...
    99+
    2024-04-02
  • vue-router实现路由懒加载的方法是什么
    这篇文章主要讲解了“vue-router实现路由懒加载的方法是什么”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“vue-router实现路由懒加载的方法是什么”吧!在Web应用程序中,系统的...
    99+
    2023-07-04
  • 什么是Vue-Router路由
    这篇文章给大家介绍什么是Vue-Router路由,内容非常详细,感兴趣的小伙伴们可以参考借鉴,希望对大家能有所帮助。Vue Router是Vue.js 官方的路由管理器。它和Vue.js的核心深度集成,可以非常方便的用于SPA应用程序的开发...
    99+
    2023-06-22
  • Vue 3中响应式的实现原理是什么
    本篇文章给大家分享的是有关Vue 3中响应式的实现原理是什么,小编觉得挺实用的,因此分享给大家学习,希望大家阅读完这篇文章后可以有所收获,话不多说,跟着小编一起来看看吧。1. 实现响应式响应基本类型变量首先...
    99+
    2024-04-02
  • Vue中的Router路由是什么
    这篇文章主要讲解了“Vue中的Router路由是什么”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“Vue中的Router路由是什么”吧!一、前端路由的概念与原理(1)什么是路由路由(英文:r...
    99+
    2023-06-30
  • Vue.$nextTick的原理是什么
    这篇文章主要介绍了Vue.$nextTick的原理是什么的相关知识,内容详细易懂,操作简单快捷,具有一定借鉴价值,相信大家阅读完这篇Vue.$nextTick的原理是什么文章都会有所收获,下面我们一起来看看吧。Vue中DOM更新机制当你气势...
    99+
    2023-07-05
  • 深入了解vue-router原理并实现一个小demo
    目录插件编写的基本方法需求分析我们先看看vue-router的使用步骤由此我们看看vue-router内部做了什么?实现思路首先我们看看如何将$router挂载到组件上​​如何实现那...
    99+
    2024-04-02
  • CAS的实现原理是什么
    本篇内容主要讲解“CAS的实现原理是什么”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“CAS的实现原理是什么”吧!悲观锁与乐观锁悲观锁总是假设最坏的情况,线程a...
    99+
    2024-04-02
  • LongAdder的实现原理是什么
    LongAdder的实现原理是什么,相信很多没有经验的人对此束手无策,为此本文总结了问题出现的原因和解决方法,通过这篇文章希望你能解决这个问题。AtomicLong的实现原理图:LongAdder是JDK8...
    99+
    2024-04-02
  • SSH的实现原理是什么
    本篇内容介绍了“SSH的实现原理是什么”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!SSH是一种协议标准,它的主要目的是实现远程登录和提供安...
    99+
    2023-06-17
  • CountDownLatch的实现原理是什么
    这篇文章主要讲解了“CountDownLatch的实现原理是什么”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“CountDownLatch的实现原理是什么”吧! 前言CountDo...
    99+
    2023-06-15
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作