当前位置: 首页 > Web前端 > HTML5

单页路由切换原理-简单实现

时间:2023-04-05 22:57:20 HTML5

前言最近在学习react的时候,在使用react-router-dom的时候,不知道history原理和路由切换实现。学习后总结一下吧!如果你只是使用react内置的历史记录,你可能不会使用下面的原则。但是当你需要使用自己的历史或者使用第三方的历史时,你需要了解它的原理。在react中,如果想在非组件中灵活的切换路由,那么就需要使用自定义的history。//app.jsximportReactfrom'react'import'./App.scss'import{BrowserRouter}from'react-router-dom'importhistoryfrom'./history'importXtContentfrom'./layout/content'importLoginfrom'./components/loginModal'functionApp(){return(

)}exportdefaultApp//history.js//这里使用第三方创建historyfrom'@/history';//setaxiosgeneralconstservice=axios.create({timeout:5000,headers:{'Content-Type':'application/json;charset=UTF-8'},withCredentials:true})//响应拦截service.interceptors.response.use(response=>{//当服务端定义的响应码为0时请求成功if(response.data.code===200){//使用Promise.resolve正常响应返回rnPromise.resolve(response.data)}elseif(response.data.code===1002){//当服务端定义的响应码code为1401时,不登录message.error('登录无效,请重新登录!')///////////登录失败切换登录页面**history.push('/Login')**/////////窗口。localStorage.removeItem('userInfo')returnPromise.reject(response.data)//使用Promise.reject抛出错误和异常}else{message.error(response.data.message)returnPromise.reject(response.data)}},error=>{if(error&&error.response){letres={}res.code=error.response.statusres.msg=throwErr(error.response.status,error.response)//throwErr捕获服务器的http状态码定义在utils工具类方法message.error(res.msg)returnPromise.reject(res)}returnPromise.reject(error)})方式在React/Vue路由中,会有两个modeshash和history,其实在上面,都是针对浏览器的路由模式设置的。其基本原理其实就是监听浏览器提供的两种模式的变化,从而映射出相应的路由组件render。简单实现路由切换hash,基本符合上述理论,性能不错,但一般用不到,不支持H5历史时回退到hash即可。其在浏览器上的路由形式http://localhost#/test与正常路由相比略显怪异不美观(不推荐)。核心:监听hash变化并触发回调//window.addEventListener('hashchange',callback)//模拟实现类Router{constructor(){//存储hash和callBack的映射this.routes={};//当前路由this.currentUrl='';//存储历史this.history=[];//作为一个指针,默认指向this.history的末尾,根据向后和向前指向history中不同的hashthis.currentIndex=this.history.length-1;this.backIndex=this.history.length-1this.refresh=this.refresh.bind(this);this.backOff=this.backOff.bind(this);//默认不返回操作this.isBack=false;//监听加载后加载路由window.addEventListener('load',this.refresh,false);//监听哈希变化//window.addEventListener('hashchange',this.refresh,false);}//添加路由映射到路由实例route(path,callback){this.routes[path]=callback||功能(){};}//根据渲染刷新(){console.log('refresh')this.currentUrl=location.hash.slice(1)||'/';this.history.push(this.currentUrl);this.currentIndex++;如果(!this.isBack){this.backIndex=this.currentIndex}this.routes[this.currentUrl]();console.log('指针:',this.currentIndex,'history:',this.history);this.isBack=false;}//后退功能backOff(){//后退操作设置为trueconsole.log(this.currentIndex)console.log(this.backIndex)this.isBack=true;这个.backIndex<=0?(this.backIndex=0):(this.backIndex=this.backIndex-1);location.hash=`#${this.history[this.backIndex]}`;}}//调用window.router=newRouter()router.route('/',function(){console.log('')changeContent('')})router.route('/Home1',function(){console.log('Home1')changeContent('Home1')})router.route('/Home2',function(){console.log('Home2')changeContent('Home2')})router.route('/Home3',function(){console.log('Home3')changeContent('Home3')})historyhistoryAPI(pushStatereplaceState)会在浏览器地址上切换路由,修改历史记录不会刷新页面。路由形式是浏览器标准的,所以当你切换到某个路由localhost/test然后刷新浏览器(F5),浏览器会向服务器请求/test下对应的资源,但是goose路由是在on上实现的前端,服务端找不到资源。该模式下,服务端接收到的get(contentType=text/html)需要)请求统一返回index.html,以node-koa为例constKoa=require('koa')//处理前端路由历史模式的节点插件consthistory=require('koa2-connect-history-api-fallback')constapp=newKoa()//设置contentType为text/html,application/xhtml+xml并统一返回静态资源文件下的index.htmlapp.use(history({htmlAcceptHeaders:['text/html','application/xhtml+xml']}))*koa2-connect-history-api-fallback见https://github.com/davezuko/koa-connect-history-api-fallback/***state:与historyState对象相关联,当popstate事件被触发时,该对象将传递给回调函数。无需传递null。*title:新页面的标题不需要传null。*url:切换到的路径,必须与当前URL保持相同的域。**///新增一条记录history.pushState(state,title,url)//替换当前的记录history.replaceState(state,title,url)####现实#####*核心window.addEventListener('popstate',callBack)classRouters{constructor(){this.routes={};这个._bindPopState();}init(path){history.replaceState({path:path},null,path);this.routes[path]&&this.routes[path]();}route(path,callback){this.routes[path]=callback||功能(){};}go(path){history.pushState({path:path},null,path);this.routes[path]&&this.routes[path]();}_bindPopState(){window.addEventListener('popstate',e=>{constpath=e.state&&e.state.path;this.routes[path]&&this.routes[path]();});}}window.Router=newRouters();Router.init(location.pathname);//路由绑定Router.route('/',function(){console.log('/')});Router.route('/blue',function(){console('blue');});Router.route('/green',function(){console('green');});//一个标签绑定事件,并阻止默认事件a.addEventListener('click',e=>{if(e.target.tagName==='A'){e.preventDefault();Router.go(e.target.getAttribute('href'));}});总结本文只是简单的介绍一下,路由的原理变化,并没有结合React/Vue来完成一个框架路由的实现,后续学习后会补上!参考哈希路由历史路由