ルーティングルーティングのフロントエンドとバックエンドへのルート、最初はそれは、バックエンドのルーティングがあるが、ルーティングスイッチは、ページを更新する必要がありますたびに、要求を送信し、サーバーが返すデータ、ユーザ体験は良いではない、と後の前に現れましたルーティング、それはことを特徴としているブラウザで更新されません。
フロントエンドは、二つの経路、ハッシュモード、履歴モードに分割されています
履歴ルーティング原理
-
プロジェクトに初めて、解決のURLに持って、対応するルーティングをロード
-
このプロジェクトは、ルートを切り替える必要がロードされています。:あなたは、ラベルスイッチング、JSを使用してプッシュ方式が切り替えた場合、デフォルトのイベントを防止する必要性、直接操作を使用している場合
- window.history.pushState:閲覧履歴のレコードの増加
- window.history.replaceState:replaceState後のアドレスに現在のブラウザのアドレス、一定の閲覧履歴の長さの合計
- onpopstateウィンドウオブジェクトがスタックの歴史の中で、モニタの変化への方法を持っている限り、変更があったとして、それはイベントをトリガします
- ブラウザで提供される方法上記H5は更新されません
コードの実装:
main.js
import Vue from 'vue'
import App from './App.vue'
import router from './router'
Vue.config.productionTip = false
new Vue({
router: router,
render: h => h(App)
}).$mount('#app')
router.js
import Vue from 'vue'
import VueRouter from './vue-router'
import Home from './views/Home.vue'
Vue.use(VueRouter)
const routes = [
{
path: '/home',
name: 'home',
component: Home
},
{
path: '/about',
name: 'about',
component: () => import(/* webpackChunkName: "about" */ './views/About.vue')
}
]
const router = new VueRouter({
routes
})
export default router
index.js VUE-ルータフォルダ
let Vue = null;
export default class Router{
static install(_Vue){
Vue = _Vue;
Vue.mixin({
beforeCreate(){
if(this.$options.router){
//根实例挂载了router
// 路由初始化
this.$options.router.init();
}
if(this.$root.$options.router){
this.$router = this.$root.$options.router;
}
}
})
}
constructor(options){
this._options = options;
this._routeMap = {};
this._vm = new Vue({
data: {
currentPath : '/'
}
})
}
init(){
// 解析路由表
this.getRouteMap();
// 注册组件
this.initComponent();
// 解析第一次的路由
this.loadRoute();
// 监听返回的事件,重新装载组件
this.onBack();
}
getRouteMap(){
this._options.routes.forEach(route=>{
this._routeMap[route.path] = route;
})
}
initComponent(){
const self = this;
Vue.component('router-view', {
render(h){
const path = self._vm.currentPath;
const component = self._routeMap[path] && self._routeMap[path].component;
return h(component);
}
});
Vue.component('router-link', {
props: {
to: String
},
render(h){
return h('a', {
class: {
'router-link-exact-active': self._vm.currentPath === this.to
},
attrs: {
href: this.to
},
on: {
// a标签点击事件
click: (ev)=>{
// 阻止默认事件
ev.preventDefault();
// 修改地址栏
window.history.pushState({}, '', this.to);
// 装载组件
self._vm.currentPath = this.to;
}
}
}, this.$slots.default);
}
});
}
loadRoute(){
window.addEventListener('load', ()=>{
//得到路由的地址
let path = window.location.pathname;
// 加载路由对应的组件
this._vm.currentPath = path;
})
}
onBack(){
window.addEventListener('popstate', ()=>{
//得到路由的地址
let path = window.location.pathname;
// 加载路由对应的组件
this._vm.currentPath = path;
})
}
push(path){
// 修改地址栏
window.history.pushState({}, '', path);
// 加载路由对应的组件
this._vm.currentPath = path;
}
back(){
window.history.back();
}
forward(){
window.history.forward();
}
go(n){
window.history.go(n);
}
}
ハッシュルーティングの原則
アドレスバーのルーティングスイッチへの変更、onhashchange耳を傾ける必要が
JSのスイッチ・ルーティング、実際にはアドレスバーのハッシュ値を変更します
- URL以下のハッシュ値を変更し、それがサーバーにリクエストを送信しません、そのため、ページを毎回ハッシュ値の変更をリフレッシュなhashchangeイベントをトリガするので、私たちは(場所を何が起こったかのハッシュ値を知るために、このイベントを監視することができません。 .hash)
- 変更は、ページジャンプハッシュを誘発しない、ハッシュリンクは、現在のページの断片である、ページがない場合は、効果がない、対応する位置にスクロールします
コードの実装:
main.js
import Vue from 'vue'
import App from './App.vue'
import router from './router'
Vue.config.productionTip = false
new Vue({
router: router,
render: h => h(App)
}).$mount('#app')
router.js
import Vue from 'vue'
import VueRouter from './vue-router'
import Home from './views/Home.vue'
Vue.use(VueRouter)
const routes = [
{
path: '/',
name: 'home',
component: Home
},
{
path: '/about',
name: 'about',
component: () => import(/* webpackChunkName: "about" */ './views/About.vue')
}
]
const router = new VueRouter({
routes
})
export default router
index.js VUE-ルータフォルダ
let Vue = null;
export default class Router{
static install(_Vue){
Vue = _Vue;
Vue.mixin({
beforeCreate(){
if(this.$options.router){
//只有vm实例,而且是配置了router的vm实例,会进来
this.$options.router.init();
}
if(this.$root.$options.router){
this.$router = this.$root.$options.router;
}
}
});
}
constructor(options){
this._options = options;
this._routeMap = {};
this._routeEach = [];
this._vm = new Vue({
data: {
//保存当前路由所在的地址
currentPath: '/'
}
});
}
init(){
// 解析路由表
this.getRouteMap();
// 配置组件
this.initComponent();
// 加载路由
this.addEvents();
}
// 解析路由表
getRouteMap(){
this._options.routes.forEach(route=>{
this._routeMap[route.path] = route;
});
}
initComponent(){
let self = this;
Vue.component('router-view', {
render(h){
let currentPath = self._vm.currentPath;
let component = self._routeMap[currentPath].component;
return h(component);
}
});
Vue.component('router-link', {
props: {
to: String
},
render(h){
return h(
'a',
{
class: {
'router-link-exact-active': self._vm.currentPath === this.to
},
attrs: {
href: '#'+this.to
}
},
this.$slots.default
)
}
});
}
// 加载路由
addEvents(){
window.addEventListener('hashchange', this.onHashChange.bind(this));
window.addEventListener('load', this.onHashChange.bind(this));
}
getPath(){
return window.location.hash.slice(1);
}
// 处理路由
onHashChange(ev){
console.log('onHashChange函数调用了.....');
//调用路由拦截
if(this._routeEach.length > 0){
let {newURL, oldURL} = ev;
let to = {};
let from = {};
if(oldURL){
// hashChange事件
// 重新设置currentPath,那么router-view就会重新装载
to = {
path: newURL.split('#')[1]
}
from = {
path: oldURL.split('#')[1]
}
}else{
//load事件
to = {
path: window.location.hash.split('#')[1]
}
from = {
path: null
}
}
this.runEach(to, from);
}
//没有拦截
else{
let path = this.getPath();
let route = this._routeMap[path];
this._vm.currentPath = route.path;
}
}
// 切换路由
push(path){
// this._vm.currentPath = path;
window.location.hash = '#'+path;
}
// 路由拦截
beforeEach(cb){
this._routeEach.push(cb);
}
//执行路由拦截
runEach(to, from, index = 0){
console.log(index);
this._routeEach[index](to, from, ()=>{
index++;
if(index < this._routeEach.length){
this.runEach(to, from, index);
}else{
let path = this.getPath();
let route = this._routeMap[path];
this._vm.currentPath = route.path;
}
});
}
}
履歴ハッシュルーティングとの違いをルーティングします:
- ハッシュ位だけ戻って変更することができ、およびハッシュ値と元の値が異なっている必要があります
- pushStateパス、クエリパラメータとフラグメント識別子を変更することができpushStateは、複数のルートの前端に沿ってハッシュアクセス方法よりも、よりエレガントな、しかし履歴モードは、バックエンドが必要