当前位置: 首页 > Web前端 > vue.js

大前端进阶-Vue-router原理

时间:2023-03-31 20:21:17 vue.js

vue-router是vue项目的重要组成部分,用于构建单页面应用。单页应用基于路由和组件。路由用于设置访问路径和映射路径和组件。路由的本质是建立URL和页面之间的映射关系。hash模式hash模式是vue-router的默认模式。hash指的是url描述点。当描述点发生变化时,浏览器只会修改访问历史,不会访问服务器重新获取页面。因此,可以监听点值的变化,根据点值渲染指定的dom。实现原理改变描述点,通过location.hash="/hashpath"修改浏览器的hash值。监听描述点的变化可以通过监听hashchange事件来监听hash值的变化。window.addEventListener('hashchange',()=>{consthash=window.location.hash.substr(1)//根据hash值渲染不同的dom})history模式hash模式下,url可能在以下形式:http://localhost:8080/index.html#/book?bookid=1#和?在上面的url中,这会使url看起来很奇怪。因此,您可以使用历史模式。这种模式下,url会是如下图:http://localhost:8080/book/1实现原理改变urlH5的历史对象提供了两个方法,pushState和replaceState。调用这两个方法时,url会发生变化,浏览器访问历史也会发生变化,但浏览器不会向后台发送请求。//第一个参数:数据对象,监听变化时可以获取//第二个参数:title标题//第三个参数:跳转地址history.pushState({},"",'/a')监听url变化可以通过监听popstate事件来监听历史变化,当浏览器的前进或后退功能被点击时触发。window.addEventListener("popstate",()=>{constpath=window.location.pathname//可以根据不同的路径渲染不同的dom})服务器支持使用hash模式时,如果手动刷新浏览器,页面也可以正常显示。但是在历史模式下,刷新浏览器时会出现问题。比如访问http://localhost:8080/book/1,服务器会检查是否有对应的html可以匹配到这个路径。单页应用下,服务器端只有一个index.html,此时无法匹配。将提示404。为了解决这个问题,服务器需要支持历史模式。node服务在nodejs服务中,可以引入connect-history-api-fallback插件:constpath=require('path')//导入处理历史模式的模块consthistory=require('connect-history-api-fallback')//importexpressconstexpress=require('express')constapp=express()//注册处理历史模式的中间件app.use(history())//处理静态资源、网站的中间件根目录../webapp.use(express.static(path.join(__dirname,'../web')))//启动服务器,端口为3000app.listen(3000,()=>{console.log('serverisstarted,port:3000')})nginx服务在nginx服务中,可以修改配置文件如下,增加对历史模式的支持:location/{roothtml;indexindex.htmlindex.htm;#新建添加内容#尝试读取$uri(当前请求的路径),如果读取不到,读取首页$uri/这个文件夹下#如果读取不到,返回index.html中根目录try_files$uri$uri//index.html;}实现自定义VueRouterVueRouter的核心是通过Vue.use注册插件,在插件的install方法中获取用户配置的router对象-在。当浏览器地址发生变化时,根据router对象匹配对应的路由,获取组件,将组件渲染到视图中。主要有3点:如何在install方法中获取vue实例上的router属性。可以使用Vue.mixin在声明循环函数beforeCreate中混入,在beforeCreate函数中,可以获取Vue实例上的属性,赋值给Vue原型链。_Vue.mixin({beforeCreate(){if(this.$options.router){_Vue.prototype.$router=this.$options.router}}})如何触发updatehash模式:通过location修改hash值。hash,触发更新。通过监听hashchange事件,浏览器向前或向后移动以触发更新。history模式下:通过history.pushState修改浏览器地址触发更新。通过监听popstate事件,浏览器向前或向后移动以触发更新。如何渲染router-view组件通过Vue.observable创建一个monitor对象current,将当前路由保存在router实例上。当浏览器地址改变时,修改当前的监控对象。在router-view组件中监控当前监控对象的变化。当当前发生变化时,获取用户注册的对应组件,并使用h函数将组件渲染成vnodes,然后更新页面视图。完整版//存储全局使用的Vue对象let_Vue=nullclassVueRouter{//vue.use要求插件有install方法staticinstall(Vue){//判断插件是否已经安装if(VueRouter.install.installed){return}VueRouter.install.installed=true_Vue=Vue//将主文件中实例化Vue对象时传入的router对象添加到Vue的原型链中。_Vue.mixin({beforeCreate(){if(this.$options.router){_Vue.prototype.$router=this.$options.router}}})}constructor(options){this.options=options//使用用于快速查找路线this.routeMap={}this.data=_Vue.observable({current:window.location.hash.substr(1)})this.init()}init(){this.createRouteMap()this.initComponents(_Vue)this.initEvent()}createRouteMap(){//遍历所有路由规则,将路由规则解析为键值对存储在routeMap中this.options.routes.forEach(route=>{this.routeMap[route.path]=route.component})}initComponents(Vue){//注册路由器链接组件Vue.component('router-link',{props:{to:String},methods:{clickHandler(e){//修改hashlocation.hash=this.to//修改current,触发视图更新this.$router.data.current=this.toe.preventDefault()}},render(h){returnh('a',{attrs:{href:this.to},on:{click:this.clickHandler}},[this.$slots.default])}})constthat=this//注册路由器-viewpluginVue.component('router-view',{render(h){constcomponent=that.routeMap[that.data.current]returnh(component)}})}initEvent(){//hash变化时修改当前属性,触发组件更新window.addEventListener('hashchange',()=>{this.data.current=window.location.hash.substr(1)})}}exportdefaultVueRouter