zl程序教程

您现在的位置是:首页 >  工具

当前栏目

路由模式的区别

路由模式 区别
2023-09-14 09:02:36 时间

前端路由原理?两种路由的实现方式有什么区别?

1.一般比较

hash
history
abstract
​ 前端路由主要应用在SPA(单页面开发)项目中。在无刷新的情况下,根据不同的URL来显示不同的组件或者内容。

1.hash模式

www.test.com/#/就是 Hash URL,当#后面的哈希值发生变化时,可以通过hashchange事件来监听到 URL 的变化,从而进行跳转页面,并且无论哈希值如何变化,服务端接收到的 URL 请求永远是www.test.com。Hash 模式相对来说更简单,并且兼容性也更好。每一次改变#后的部分,都会在浏览器的访问历史中增加一个记录,使用"后退"按钮,就可以回到上一个位置。

2.history模式

History模式是HTML5 新推出的功能,主要使用history.pushState和history.replaceState改变 URL。通过 History 模式改变 URL 同样不会引起页面的刷新,只会更新浏览器的历史记录。当用户做出浏览器动作时,比如点击后退按钮时会触发popState事件。

*popstate 事件*
当用户点击浏览器的「前进」、「后退」按钮时,就会触发popstate事件。你可以监听这一事件,从而作出反应。

这里e.state就是当初pushState时传入的第一个参数,state 对象可以是任何可以序列化的东西。由于火狐会将这些对象存储在用户的磁盘上,所以用户在重启浏览器之后这些state对象会恢复。

*replaceState 方法*
有时,你希望不添加一个新记录,而是替换当前的记录(比如对网站的 landing page),则可以使用replaceState方法。这个方法和pushState的参数完全一样。

history.pushState() 和 history.replaceState()这两个API都有三个参数,分别是:

*a. 状态对象(state object)* — 一个JavaScript对象,与用 pushState() 方法创建的新历史记录条目关联。无论何时用户导航到新创建的状态,popstate 事件都会被触发,并且事件对象的state 属性都包含历史记录条目的状态对象的拷贝。

*b. 标题(title)* — FireFox 浏览器目前会忽略该参数,虽然以后可能会用上。考虑到未来可能会对该方法进行修改,传一个空字符串会比较安全。或者,你也可以传入一个简短的标题,标明将要进入的状态。

*c. 地址(URL)* — 新的历史记录条目的地址。浏览器不会在调用 pushState() 方法后加载该地址,但之后,可能会试图加载,例如用户重启浏览器。新的 URL 不一定是绝对路径;如果是相对路径,它将以当前 URL 为基准;传入的 URL 与当前 URL 应该是同源的,否则,pushState() 会抛出异常。该参数是可选的;不指定的话则为文档当前 URL。

两个API对比:

相同之处: 是两个 API 都会操作浏览器的历史记录,而不会引起页面的刷新。

不同之处在于: pushState 会增加一条新的历史记录,而 replaceState 则会替换当前的历史记录。

2.延伸以及扩展问题

​ 两种路由模式的区别

1.Hash 模式只可以更改 # 后面的内容,History 模式可以通过 API 设置任意的同源 URL

2.History 模式可以通过 API 添加任意类型的数据到历史记录中,Hash 模式只能更改哈希值,也就是字符串

3.Hash模式下, 多次刷新为通一个页面的话,记录只添加一次

4.Hash 模式无需后端配置,并且兼容性好。History 模式在用户手动输入地址或者刷新页面的时候会发起 URL 请求,后端需要配置 index.html 页面用于匹配不到静态资源的时候

3项目中体现经验的点

​ 当使用HTML5 history,刷新页面时会出现404。是因为当前url服务端无法找到,所以,要在服务端增加一个覆盖所有情况的候选资源:如果 URL 匹配不到任何静态资源,则应该返回同一个 index.html 页面,这个页面就是你 app 依赖的页面。同时需要在前端这边处理404。

hash模式

<body>
        <a href="#/">首页</a>
		<a href="#/home">主页</a>
		<a href="#/list">列表</a>
		<div id="box"></div>
	</body>
	<script>
		class Route{
			constructor({routes}) {
			    let box=document.getElementById("box");
				this.routes=routes;
				this.init()
				this.events={};
				this.routes.forEach((item,i)=>{
					this.events[item.path]=function(){
						box.innerHTML=item.component;
					}
				})
			}
			init(){
				window.addEventListener("hashchange",this.updateVide.bind(this));
			}
			updateVide(){
				//console.log(this.events[path])
				let path=window.location.hash.slice(1)
				this.events[path]()
			}
		}
		
		new Route({
			routes:[
				{
					path:"/",
					component:"首页"
				},
				{
					path:"/home",
					component:"主页"
				},
				{
					path:"/list",
					component:"列表"
				}
			]
		})
	</script>

history模式

<body>
		<a href="javascript:;" data-to="/">首页</a>
		<a href="javascript:;" data-to="/home">主页</a>
		<a href="javascript:;" data-to="/list">列表</a>
		<div id="box"></div>
	</body>
	<script>
		class Route{
			 constructor({routes}) {
			     this.routes=routes;
				 this.initHistory();
				 this.init()
			 }
			 initHistory(){
				 console.log(window,"1111")
				 window.addEventListener("popstate",()=>{
					 console.log(window.location,'kkkk')
					 this.updateView(window.location.pathname)
				 })
			 }
			 init(){
				let as=document.querySelectorAll("a");
				let _this=this;
				[].forEach.call(as,(item)=>{
					item.onclick=function(){
						let path=item.getAttribute("data-to");
						//{}其实就是路由传递的一些信息,比如query,search这些
						//null,是想要修改的html标签
						//path才是路由地址
						window.history.pushState({},null,path);
						_this.updateView(path);
					}
				})
			 }
			 updateView(path){
				 let box=document.getElementById("box")			 box.innerHTML=this.routes.filter(item=>item.path===path)[0].component
			 }
		}
		
		new Route({
			routes:[
				{
					path:"/",
					component:"首页"
				},
				{
					path:"/home",
					component:"主页"
				},
				{
					path:"/list",
					component:"列表"
				}
			]
		})
	</script>

*获取千锋教育学习视频资料+源码笔记 ,进学习交流群

请添加下方微信(备注CSDN推荐)
请添加图片描述