Hash模式
1、hash即URL中#後面的部分。
2、如果網頁URL帶有hash,頁面會定位到id與hash一樣的元素的位置,即錨點
3、hash的改變時,頁面不會重新加載,會觸發hashchange事件,而且也會被記錄到浏覽器的曆史記錄中
4、vue-router的hash模式,主要就是通過監聽hashchange事件,根據hash值找到對應的元件進行渲染(源碼裡會先判斷浏覽器支不支援popstate事件,如果支援,則是通過監聽popstate事件,如果不支援,則監聽hashchange事件)
hash模式界面跳轉不重新整理
根據http協定所示,url中hash改變請求是不會發送到服務端的,不管你怎麼location跳轉,或者url上直接加上hash值回車,他都一樣固執,就是不和伺服器老大說。
但是我們的系統裡又引入了vue-router,其中hashchange這個事件監聽到了hash的變化,進而觸發了元件的更新,也就繪制出了相應的頁面
History模式
1、通過history.pushState修改頁面位址
2、當history改變時會觸發popstate事件,是以可以通過監聽popstate事件擷取路由位址
3、根據路由位址找到對應元件進行渲染
history模式,每次點選菜單導航會界面重新整理?
看一下正确的history模式下,首頁重新整理到顯示的整體流程:
1.将這個完整的url發到伺服器nginx
2.ngix需要配置用這個uri在指給前端index.html(因為根本沒有任何一個伺服器提供了這個url路由,如果直接通路的話就是404,是以就要指回給前端,讓前端自己去根據path來顯示)
location / {
root /usr/share/nginx/html/store;//項目存放的位址
index index.html index.htm;
try_files $uri $uri/ /index.html;//history模式下,需要配置它
}
是以try_files $uri $uri/的意思就是,比如http://test.com/example先去查找單個檔案example,如果example不存在,則去查找同名的檔案目錄/example/,如果再不存在,将進行重定向index.html(隻有最後一個參數可以引起一個内部重定向)
凡是404的路由,都會被重定向到index.html,這樣就顯示正确了
3.此時nginx将這個請求指回了前端的index.html,index.html中開始加載js,js中已有vue-router的代碼,vue-router自動觸發了popstate這個事件,在這個事件回調中,繪制了這個path下對應的頁面元件
vue-router使用
1.注冊vue-router插件
import VueRouter from 'vue-router'
// 注冊VueRouter插件
// Vue.use方法
// 1、如果傳入的是方法,則調用傳入的方法
// 2、如果傳入的是對象,則會調用插件的install靜态方法,并傳入Vue構造函數
Vue.use(VueRouter)
2.建立Router執行個體
// 建立路由表
const routes = [
{
path: '/home',
component: Home,
},
{
path: '/about',
component: About,
},
]
// 執行個體化路由對象
const router = new VueRouter({
mode: 'hash',
routes
})
3.Vue執行個體上挂載router執行個體
// 執行個體化Vue時,在執行個體上注冊router對象
new Vue({
render: h => h(App),
router
}).$mount('#app')
元件中使用
<router-view></router-view>
<router-link to="/home"><route-link>
// 通過this.$router擷取路由對象
總結,VueRouter需要做以下這些事情
1、實作install靜态方法
2、根據傳入的路由配置,生成對應的路由映射
3、給Vue執行個體挂載router執行個體
4、注冊全局元件和, router-view元件通過目前url找到對應元件進行渲染,并且url改變時,重新渲染元件,router-link則渲染為a标簽
5、通過currentUrl變量儲存目前url,并使資料變為響應式
6、監聽hashchange或popState事件,浏覽器記錄改變時重新渲染router-view元件
代碼實作
//1.實作一個插件
//2.要求必須要是一個install方法,将來會被vue調用
//3.兩個元件 router-link router-view
let Vue; //儲存Vue的構造函數,在插件中要使用
class VueRouter {
constructor(options) {
this.$options = options;
}
}
//插件:實作install方法,注冊$router
//參數一:是Vue.use調用時傳入的(參數_Vue是vue構造函數)
VueRouter.install = (_Vue) => {
Vue = _Vue;
// 1.挂載$router屬性
//this.$router.push()
//全局混入(延遲下面的邏輯到router建立完畢并且附加到選項上時才執行)
Vue.mixin({
beforeCreate() {
//注意此鈎子在每個建立執行個體的時候都會被調用
//根執行個體才有該選項
if (this.$options.router) {
Vue.prototype.$router = this.$options.router;
}
},
});
//2.實作兩個元件:router-link,router-view
//<router-link to="/">home</router-link> ==> <a href="/" target="_blank" rel="external nofollow" >home</a>
Vue.component("router-link", {});
Vue.component("router-view", {});
};
export default VueRouter;
為什麼要用混入方式寫?為了在元件建立的時候給vue執行個體的原型綁定這個router執行個體,是以咱們就可以在vue元件的地方使用this.$router
建立router-link和router-view
Vue.component("router-link", {
props: {
to: {
type: String,
required: true,
},
},
render(h) {
return h(
"a",
{
attrs: {
href: `#${this.to}`,
},
},
this.$slots.default
);
},
});
Vue.component("router-view", {
render(h) {
let component = null;
//暫時先不渲染任何内容
return h(component);
},
});
監控URL變化
定義響應式的current屬性,監聽hashchang事件
class VueRouter {
constructor(options) {
this.$options = options;
//把this.current變為響應式的資料
//将來資料發生變化,router-view的render函數能夠再次執行
let initial = window.location.hash.slice(1) || "/";
//把current變成響應式資料
Vue.util.defineReactive(this, "current", initial);
//将來資料一旦發生變化,router-view的render函數能夠重新執行
this.current = "/";
window.addEventListener("hashchange", () => {
this.current = window.location.hash.slice(1) || "/";
console.log("current", this.current);
});
}
}
動态擷取對應的元件,router-view元件
Vue.component("router-view", {
render(h) {
let component = null;
let { current, $options } = this.$router;
let routeItem = $options.routes.find((item) => item.path == current);
routeItem && (component = routeItem.component);
//擷取目前路由所對應的元件并将他渲染出來
return h(component);
},
});