在技术的世界,没有奇迹,只有精妙的,使人咂舌的技术运用。 ---- 南方小菜语
看到一句话,前端的革命性事件:ajax实现主动请求局部刷新,路由控制权的掌控;前者很好理解,后者越以为很让人惊喜,以往本身开发项目的固态思惟:javascript
一如前端路由深似海,今后再无进度条css
首先先不聊怎么实现,先思考html
即点击连接后url发生变化,每一个变化对应一个挂载点的内容(很天然的,咱们须要一个路由表,即路径与挂载点内容的k-v,可用经过json实现)前端
传统后端路由每次跳转都刷新页面,另发起一个新的请求,会给用户带来的白屏、耗时等较差体验。所以前端路由采用的是当即加载的方式,再也不向服务器请求,而是加载路由对应的组件;而这种思路的实现主要采用两种方案:hashchange 以及 historyvue
htmljava
<div>
<a href="javascript:;" data-href="/">home</a>
<a href="javascript:;" data-href="/book">book</a>
<a href="javascript:;" data-href="/movie">movie</a>
<div id="content"></div>
</div>
复制代码
jsajax
//路由类
class Router {
constructor(opts) {
//路由表
this.routes = {},
this.init();
this.bindEvent();
opts.forEach(item => {
this.route(item.path, () => {
document.getElementById('content').innerHTML = item.component;
})
})
}
init() {
//页面初始化时渲染路由
window.addEventListener('load', this.updateView.bind(this));
// 当活动历史记录条目更改时, 将触发popstate事件。
// 若是被激活的历史记录条目是经过对history.pushState() 的调用建立的,
// 或者受到对history.replaceState() 的调用的影响,
// popstate事件的state属性包含历史条目的状态对象的副本。
window.addEventListener('popstate', this.updateView.bind(this));
}
// 路由渲染
updateView() {
const currentUrl = window.location.pathname || '/';
this.routes[currentUrl] && this.routes[currentUrl]();
}
// 配置路由
route(path, fn) {
this.routes[path] = fn;
}
push(url){
window.history.pushState({},null,url);
this.updateView()
}
// 为超连接绑定事件
bindEvent() {
const _this = this;
const links = document.getElementsByTagName('a');
[].forEach.call(links, link => {
link.addEventListener('click', function () {
const url = this.getAttribute('data-href');
console.log(url);
_this.push(url);
})
})
}
}
//实例化路由
const router = new Router([{
path: '/',
component: 'home'
}, {
path: '/movie',
component: 'movie'
}, {
path: '/book',
component: 'book'
}])
复制代码
hash也存在下面几个特性:数据库
URL中hash值只是客户端的一种状态,也就是说当向服务器端发出请求时,hash部分不会被发送。 hash值的改变,都会在浏览器的访问历史中增长一个记录。所以咱们能经过浏览器的回退、前进按钮控制hash的切换。 咱们能够使用hashchange事件来监听hash的变化。json
出发hsah变化的方式也有两种,一种是经过a标签,并设置href属性,当用户点击这个标签后,URL就会发生改变,也就会触发hashchange事件了后端
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
</head>
<body>
<a href="#/" data-href="/">home</a>
<a href="#/book" data-href="/">book</a>
<a href="#/movie" data-href="/">movie</a>
<div id="content">
</div>
<script src="https://cdn.bootcss.com/vue/2.6.10/vue.min.js"></script>
<script>
// window.onload = function (params) {
// window.location.href += '#/'
// }
const Home = {
template: '<div>home</div>'
}
const Book = {
template: '<div>book</div>'
}
const Movie = {
template: '<div>movie</div>'
}
class Router {
constructor(opts) {
// this.path = opts.path;
// this.component = opts.component;
// this.routes = opts.routes;
this.routes = {
}
// console.log(opts);
opts.forEach(item => {
this.route(item.path,()=>{
document.getElementById('content').innerHTML = item.component;
})
})
console.log(this.routes);
this.init()
}
bindEvent() { }
init() {
window.addEventListener('load',this.updateView.bind(this))
window.addEventListener('hashchange', this.updateView.bind(this))
}
updateView(e) {
// console.log(e,'updated');
// console.log(e.newURL.indexOf(e.oldURL));
// console.log(e.newURL.substring(e.newURL.indexOf(e.oldURL)));
const hashTag = window.location.hash.slice(1) || '/'
console.log(window.location.hash.slice(1));
this.routes[hashTag] && this.routes[hashTag]()
}
route(path,cb){
this.routes[path] = cb;
}
}
new Router([
{
path: '/',
component: 'home',
},
{
path: '/book',
component: 'book'
},
{
path: '/movie',
component: 'movie'
}
])
</script>
</body>
</html>
复制代码