经过前一段时间磕路由的官方文档及做了一些实验,我终于是个废人了。现在对路由的了解,可能是由之前的‘人畜不分’阶段变成了‘这是个会做什么东西的人’阶段。前路漫漫,继续磕吧!刚嘛嘚!!
现在单页应用盛行,前端路由也成为目前各个框架的基础标配,然后就搞得路由也是一大难题,越来越复杂,对于我这个小菜鸡来说,啃这个骨头,还是挺费头发的。
今天总结两个牛掰哄哄的两个框架(React和Vue)的hash模式和history模式。
先介绍一下,前端路由、hash模式及history模式到底是什么玩意儿
前端路由 :在服务端,就是url和处理函数之间的映射关系。在web前端单页应用中,就是url和UI之间的映射关系,在无需刷新页面的情况下,url变化会引起UI更新。
那么要实现前端路由,就要搞清楚怎么去检测url是否变化?url变化的时候,怎么实现页面不刷新?
接下来就有意思了,该hash和history出场了
hash模式:使用hash模式,在url中会出现"#",那么hash值就是url中从"#"号开始到结束的部分(常用做锚点在页面进行导航),改变url中hash部分就不会引起页面刷新。hash模式是使用hashchange事件监听url的变化的。
那么我们怎么去改变url去触发hashchange事件呢?
1,通过标签改变url;2,通过浏览器的前进后退改变url;3,通过window.location改变url。(目前也就这3种方式可以改变url。)
history模式:相较于url中多一个“#”看起来丑丑的hash模式,history模式更优雅一点。history模式提供pushState和replaceState两种方发去改变url的path部分,同样,页面是不会刷新的。
history模式监听url变化稍稍复杂一 nei nei,但也是可以实现滴。
history 提供popstate 事件:通过浏览器前进后退改变 URL 时会触发 popstate 事件,but,通过pushState/replaceState或标签改变 URL 不会触发 popstate 事件。好在我们可以拦截 pushState/replaceState的调用和标签的点击事件来检测 URL 变化,所以监听 URL 变化可以实现,只是没有 hashchange 那么方便。
那么接下来,就是嗨皮的时候了—React实现前端路由!
直接上代码!
基于hash模式的前端路由实现!
<HashRouter>
<ul>
<li>
<Link to="/home">home</Link>
</li>
<li>
<Link to="/about">about</Link>
</li>
</ul>
<Route path="/home" render={() => <h2>Home</h2>} />
<Route path="/about" render={() => <h2>About</h2>} />
</HashRouter>
HashRouter的实现
export default class HashRouter extends React.Component {
state = {
currentPath: utils.extractHashPath(window.location.href)
};
onHashChange = e => {
const currentPath = utils.extractHashPath(e.newURL);
console.log("onHashChange:", currentPath);
this.setState({ currentPath });
};
componentDidMount() {
window.addEventListener("hashchange", this.onHashChange);
}
componentWillUnmount() {
window.removeEventListener("hashchange", this.onHashChange);
}
render() {
return (
{this.props.children}
);
}
}
Router的实现
export default ({ path, rander }) => (
{({currentPath}) => currentPath === path && render()}
);
基于history模式的前端路由实现
<HistoryRouter>
<ul>
<li>
<Link to="/home">home</Link>
</li>
<li>
<Link to="/about">about</Link>
</li>
</ul>
<Route path="/home" render={() => <h2>Home</h2>} />
<Route path="/about" render={() => <h2>About</h2>} />
</HistoryRouter>
HistoryRouter 实现:
export default class HistoryRouter extends React.Component {
state = {
currentPath: utils.extractUrlPath(window.location.href)
};
onPopState = e => {
const currentPath = utils.extractUrlPath(window.location.href);
console.log('onPopState', currentPath);
this.setState({ currentPath });
};
componentDidMount() {
window.addEventListener('popState', this.onPopState);
}
componentWillMount() {
window.removeEventListener('popState', this.onPopState);
}
render() {
return (
{this.props.children}
);
}
}
Route实现
export default ({ path, render }) => (
{({currentPath}) => currentPath === path && render()}
);
Link 实现:
export default ({ to, ...props }) => (
{({ onPopState }) => (
href=""
{...props}
onClick={e => {
e.preventDefault();
window.history.pushState(null, "", to);
onPopState();
}}
/>
)}
);
呼呼。。。React框架 Over。爬起来继续肝Vue框架,Begin!!!
Vue实现前端路由
持续暴击,直接上代码
基于hash模式的前端路由实现!
<div>
<ul>
<li><router-link to="/home">home</router-link></li>
<li><router-link to="/about">about</router-link></li>
</ul>
<router-view></router-view>
</div>
const routes = {
'/home': {
template: '<h2>Home</h2>'
},
'/about': {
template: '<h2>About</h2>'
}
}
const app = new Vue({
el: '.vue.hash',
components: {
'router-view': RouterView,
'router-link': RouterLink
},
beforeCreate () {
this.$routes = routes
}
})
router-view 实现:
<template>
<component :is="routeView" />
</template>
<script>
import utils from '~/utils.js'
export default {
data () {
return {
routeView: null
}
},
created () {
this.boundHashChange = this.onHashChange.bind(this)
},
beforeMount () {
window.addEventListener('hashchange', this.boundHashChange)
},
mounted () {
this.onHashChange()
},
beforeDestroy() {
window.removeEventListener('hashchange', this.boundHashChange)
},
methods: {
onHashChange () {
const path = utils.extractHashPath(window.location.href)
this.routeView = this.$root.$routes[path] || null
console.log('vue:hashchange:', path)
}
}
}
</script>
router-link 实现:
<template>
<a @click.prevent="onClick" href=''><slot></slot></a>
</template>
<script>
export default {
props: {
to: String
},
methods: {
onClick () {
window.location.hash = '#' + this.to
}
}
}
</script>
基于history模式的前端路由实现
<div>
<ul>
<li><router-link to="/home">home</router-link></li>
<li><router-link to="/about">about</router-link></li>
</ul>
<router-view></router-view>
</div>
const routes = {
'/home': {
template: '<h2>Home</h2>'
},
'/about': {
template: '<h2>About</h2>'
}
}
const app = new Vue({
el: '.vue.history',
components: {
'router-view': RouterView,
'router-link': RouterLink
},
created () {
this.$routes = routes
this.boundPopState = this.onPopState.bind(this)
},
beforeMount () {
window.addEventListener('popstate', this.boundPopState)
},
beforeDestroy () {
window.removeEventListener('popstate', this.boundPopState)
},
methods: {
onPopState (...args) {
this.$emit('popstate', ...args)
}
}
})
router-view 实现:
<template>
<component :is="routeView" />
</template>
<script>
import utils from '~/utils.js'
export default {
data () {
return {
routeView: null
}
},
created () {
this.boundPopState = this.onPopState.bind(this)
},
beforeMount () {
this.$root.$on('popstate', this.boundPopState)
},
beforeDestroy() {
this.$root.$off('popstate', this.boundPopState)
},
methods: {
onPopState (e) {
const path = utils.extractUrlPath(window.location.href)
this.routeView = this.$root.$routes[path] || null
console.log('[Vue] popstate:', path)
}
}
}
</script>
router-link 实现:
<template>
<a @click.prevent="onClick" href=''><slot></slot></a>
</template>
<script>
export default {
props: {
to: String
},
methods: {
onClick () {
history.pushState(null, '', this.to)
this.$root.$emit('popstate')
}
}
}
</script>
OVER!!!!人已废,头已秃!!一定要动手自己搞一遍,对,没错,不能我一个人秃。
参考网址:
https://router.vuejs.org/zh/guide/
下面的文章需要复制,微信或者QQ打开
https://mp.weixin.qq.com/s?src=12×tamp=1610411470&signature=3EMThyz-2dQgllJuVZe8JMOLwaZ7wUUOf444ES23KSngX1fUjNbeRVGa5JBmUybjrNscncAuqsY9yeOeDMCjFcrq39NrDE659203AXKpWHXzpD-jhcqr9*0EpUc-3Mwy&ver=2823&article_id=1336672358&rowkey=6845f84f53d56314&_wv=2147532945&ref=kandian&_pflag=24