location.hash
读写hashchange
监听<!DOCTYPE html>
<html lang="en">
<body>
<button id="myBtn">按钮</button>
<script>
const btn = document.getElementById('myBtn');
window.addEventListener('DOMContentLoaded', () => {
console.log(location.hash);
});
btn.addEventListener('click', () => {
location.hash = '#/lance';
});
window.addEventListener('hashchange', () => {
console.log(location.hash);
})
</script>
</body>
</html>
popstate
监听浏览器的前进后退index.html
让vue接管路由<!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>Document</title>
</head>
<body>
<button id="myBtn">按钮</button>
<script>
const btn = document.getElementById('myBtn');
window.addEventListener('DOMContentLoaded', () => {
console.log(location.pathname);
});
btn.addEventListener('click', () => {
const state = { name: 'user' };
history.pushState(state, '', 'user');
// state, title, url
});
window.addEventListener('popstate', () => {
console.log(location.pathname);
});
</script>
</body>
</html>
class VueRouter
install()
,Vue.use()
时需要调用
install
时,会把 Vue 构造函数传给我们Vue.mixin
-> beforeCreate 中:
this.$options.router
,也就是 new VueRouter 实例);找到后调用 init 方法开始执行window.addEventListener
=> DOMContentLoaded
、hashchange
)router-link
、router-view
my-router/index.js
let Vue;
class VueRouter {
constructor(options) {
this.$options = options;
this.routeMap = {};
this.vm = new Vue({
data() {
return {
currentPath: '/'
}
}
});
}
init() {
// 1. 监听hash值变化
this.bindEvent();
// 2. 创建路由映射表
this.createHashMap();
// console.log(this.routeMap);
// {/: {path: '/', name: 'Home', component: {…}}, /about: {path: '/about', name: 'About', component: {...}}
// 3. 注册全局路由组件 router-link、router-view
this.initRouteComponent();
}
bindEvent() {
// 页面加载完监听
window.addEventListener('DOMContentLoaded', this.handleHashChange.bind(this), false);
// hash值变化后监听
window.addEventListener('hashchange', this.handleHashChange.bind(this), false);
}
handleHashChange() {
console.log('handleHashChange-hash:', window.location.hash);
const hash = this.getHashValue();
// vm实例下的属性发生改变,会导致重新渲染
this.vm.currentPath = hash;
}
// 获取hash值
getHashValue() {
// console.log("getHashValue-hash:", window.location.hash.slice(1));
return window.location.hash.slice(1) || '/';
}
// 创建路由映射表
createHashMap() {
// 把 routes数组 转 hash 方式存储
this.$options.routes.forEach(item => {
this.routeMap[item.path] = item;
});
}
// 初始化全局路由组件
initRouteComponent() {
Vue.component('router-view', {
render: h => {
const component = this.routeMap[this.vm.currentPath].component;
// return h('h1', 'Hello JS++');
return h(component);
}
});
Vue.component('router-link', {
props: {
to: String,
},
render(h) {
// h函数: 标签名, 属性集合
// this.$slots.default: 拿到插槽内容
return h('a', {
attrs: {
href: '#' + this.to
}
}, this.$slots.default);
}
});
}
// install 得是个静态方法
// 因为Vue需要调用install (Vue.install)
// 但调用时不需要通过new来实例化
// Vue在调用install时,会传入参数:Vue构造函数
static install(_Vue) {
Vue = _Vue;
// console.log(Vue);
// console.log('vue router install');
Vue.mixin({
beforeCreate() {
// 这里会打印两次,因为有俩vue实例(main.js中new Vue,App.vue中的vue),vue会给它们分别添加 beforeCreate 钩子
// console.log('mixin里的一些数据');
// 打印后会发现,只有根组件root才有 router 实例,也就是 new VueRouter 这个实例
// 所以后边我们需要判断,当有router实例时,才执行上边的 init 方法
console.log('当前vue实例:', this.$options.name, this.$options.router);
// 找到根Vue实例,然后取出里边的router实例,并执行init方法
if (this.$options.router) {
this.$options.router.init();
}
}
});
}
}
export default VueRouter;