服务端路由
解析不同路径,决定不同的资源返回
客户端路由
SPA 页面跳转不会刷新
步骤
监听 url 的变化 获取 url 地址 匹配路由规则
方法
hash
<a href="#kaola">to KAOLA</a>
location.hash="#kaola"
- url 中 hash 值的变化并不会重新加载页面
- hash值的改变,都会在浏览器的访问历史中增加一个记录
- hashchange 事件,监听到 hash 值的变化
- 检测到变化后,通过替换 DOM 的方式来实现页面的更换
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>hash</title>
</head>
<body>
<a href="#">/</a>
<a href="#/hash">hash</a>
<div class="main" id="main"></div>
<script>
var mainbox = document.getElementById('main');
function Router() {
this.routes = {};
this.currentUrl = '';
}
Router.prototype.route = function (path, callback) {
this.routes[path] = callback || function () { };
};
Router.prototype.refresh = function () {
this.currentUrl = location.hash.slice(1) || '/';
this.routes[this.currentUrl]();
};
Router.prototype.init = function () {
window.addEventListener('load', this.refresh.bind(this), false);
window.addEventListener('hashchange', this.refresh.bind(this), false);
}
window.Router = new Router();
window.Router.init();
// 添加路由规则
Router.route('/', function () {
// 设置响应内容
mainbox.innerHTML = 'current page is /'
});
Router.route('/hash', function () {
// 设置响应内容
mainbox.innerHTML = 'current page is hash'
});
</script>
</body>
</html>
history api
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>pushState</title>
</head>
<body>
<p id="menu">
<a href="/profile" title="profile">profile</a>
<a href="/account" title="account">account</a>
</p>
<div class="main" id="main"></div>
<script>
(function () {
var menubox = document.getElementById('menu');
var mainbox = document.getElementById('main');
menubox.addEventListener('click', function (e) {
e.preventDefault();
var elm = e.target;
var uri = elm.href;
var tlt = elm.title;
history.pushState({ path: uri, title: tlt }, null, uri);
mainbox.innerHTML = 'current page is ' + tlt;
})
window.addEventListener('popstate', function (e) {
var state = e.state;
if (state) {
mainbox.innerHTML = 'current page is ' + state.title; // 还原UI
} else {
mainbox.innerHTML = ''
}
})
})()
</script>
</body>
</html>
-
拦截 a 标签 的点击事件,阻止它的默认跳转行为
-
使用 H5 的 history API 更新 URL
-
History.pushState(state, title [, url])- 往历史堆栈的顶部添加一个状态
- 方法接收三个参数:一个状态对象, 一个标题, 和一个(可选的) URL
- pushState 能更新当前 url,并且不引起页面刷新
-
History.replaceState(stateObj, title[, url]); 修改当前历史记录实体
-
window.onpopstate
- 当活动历史记录条目更改时,将触发 popstate 事件
- pushState 和 replaceState 对 url 的修改都不会触发 onpopstate
- 它只会在浏览器某些行为下触发, 比如点击后退、前进按钮、a 标签点击等
-
解决 load 发送请求 404 问题
服务器需要把所有路由都重定向到根页面
-
监听和匹配路由改变以更新页面
-
url 必须与当前的 url 同源
react-router
路由器组件
<BrowserRouter> 和 <HashRouter>
-
路由器组件的作为根容器组件,
<Route>等路由组件必须被包裹在内才能够使用 -
<Router>通过 context 把父组件透传给子孙组件 -
history.listen 就完成了对几种模式路由的监听
路由组件都能感知路由变化,并拿到相应路由信息
BrowserRouter 对应 addEventListener
路由匹配组件
<Route> 和 <Switch>
- 路由匹配组件通过匹配 path,渲染对应组件
- 不同的匹配模式、path写法以及渲染方式
- 匹配模式
- 精确匹配
- 严格匹配
- 大小写敏感
- 路径 path 写法
- 字符串形式
- 命名参数
- 数组形式
- 渲染方式
- 通过子组件渲染
- 通过 props.component 渲染
- 通过 props.render 渲染
- 匹配模式
- Route 对应 onpopstate
导航组件
<Link> 和 <NavLink>
- 导航组件起到类似 a 标签跳转页面的作用
- Link 对应 a
history 库
屏蔽几种模式之间操作会话历史的差别
matchPath
通过 path-to-regexp 实现路由匹配