>[success] # 分清前端路由的 history 和 hash 路由
1. 兩種方式均為客戶端路由的實現方式:當路徑法發生變化,不會向服務器發送請求,使用js監視路徑的變化 根據不同的地址渲染不同的內容,如果需要服務器端的內容會發送Ajax請求來獲取
1.1. Hash模式url中帶#號 #號后邊內容為路由地址 url帶井號或者問號
1.2. History 模式正常url模式
2. 原理區別:
2.1. `Hash`模式是基于錨點,以及`onhashchange`事件。通過錨點值作為路由地址,路由變化后 觸發`onhashchange`事件
2.2. `History` 模式是基于HTML5中的`History API` 有兼容問題 `history.pushState()` IE10以后才支持 `history.replaceState()` 不會向服務器發送請求,僅改變瀏覽器地址欄中的地址,并且將地址記錄到歷史記錄中,api 如下
* `replaceState`:替換原來的路徑
* `pushState`:使用新的路徑;
* `popState`:路徑的回退;
* `go`:向前或向后改變路徑;
* `forward`:向前改變路徑;
* `back`:向后改變路徑;
3. 雖然`History` 模式不會向后臺發送請求,但是注意一點,用戶如果刷新頁面或者重新請求該地址 會像后臺服務器發起請求,此時沒有對應連接對應的頁面會產生查找不到頁面,如果使用history模式 需要`后臺配合 `
4. 總結:
4.1. `Hash 模式`: URL中#后面的內容作為路徑地址,僅改變# 后面的內容則不會向服 務器請求這個地址,但會記錄到訪問歷史中,監聽hashchange事件,url改變會觸發該事件 ,根據當前路由地址找到對應組件重新渲染
4.2. `History 模式 `:通過`history.pushState()`方法改變地址欄,僅改變地址欄并將其記錄到訪問歷史中,并不會跳轉到指定路徑即不會向服務器發送請求 監聽 `popstate` 事件,可以記錄改變后的地址,調用`pushState和replaceState`時不會觸發該事件,后退或前進歷史頁面時才會觸發 根據當前路由地址找到對應組件重新渲染
>[danger] ##### history簡單案例
~~~html
<!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>
<div id="app">
<a href="/home" class="router">home</a>
<a href="/index" class="router">about</a>
<div class="content">Default</div>
</div>
</head>
<body>
<script>
class VueRouter {
constructor(options, identifier) {
this.options = options
// 注冊路由列表
this.routerMap = {}
this.identifier = identifier
this.initRouterMap()
this.initEvent()
this.clickHandler()
}
initRouterMap() {
const contentEl = document.querySelector('.content')
for (let key in this.options) {
this.routerMap[key] = () =>
(contentEl.innerHTML = this.options[key])
}
}
// 當點擊 a 標簽時候 取消默認跳轉行為
// 將前端路由儲存 并且渲染對應路由對應節點
clickHandler() {
const els = document.getElementsByClassName(this.identifier)
;[...els].forEach((el) => {
el.addEventListener('click', (e) => {
// 阻止默認事件
e.preventDefault()
const href = el.getAttribute('href')
history.pushState({}, '', href)
this.routerMap[href]()
})
})
}
initEvent() {
// 當觸發如用戶點擊瀏覽器的回退按鈕(或者在Javascript代碼中調用history.back()或者history.forward()方法 觸發
window.addEventListener('popstate', () => {
this.routerMap[location.pathname]()
})
}
}
const urlMap = {
'/home': `<p>home</p>`,
'/index': `<p>index<p>`,
}
const vueRouter = new VueRouter(urlMap, 'router')
</script>
</body>
</html>
~~~
>[danger] ##### 使用 hash 模式
~~~
<!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>
<div id="app">
<a href="#/home">home</a>
<a href="#/about">about</a>
<div class="content">Default</div>
</div>
<script>
const contentEl = document.querySelector('.content');
window.addEventListener("hashchange", () => {
switch(location.hash) {
case "#/home":
contentEl.innerHTML = "Home";
break;
case "#/about":
contentEl.innerHTML = "About";
break;
default:
contentEl.innerHTML = "Default";
}
})
</script>
</body>
</html>
~~~
>[danger] ##### 簡單看vuerouter 使用
1. 知道上面原理后,先了解以下vueRouter 使用這里版本`4.x`
* 根據上面案例首先創建一個 路由映射 形成路由和組件關系
* 可以選擇具體使用`hash `形式 還是 `history `形式
* 通過一個容器可以將我們映射的內容展示出來
~~~
import { createRouter, createWebHistory } from "vue-router";
import HomeView from "../views/HomeView.vue";
// map 形成路由和組件的關系
const routes = [
{
path: "/",
name: "home",
component: HomeView,
},
{
path: "/about",
name: "about",
component: () =>
import(/* webpackChunkName: "about" */ "../views/AboutView.vue"),
},
];
// 創建了路由對象
const router = createRouter({
history: createWebHistory(process.env.BASE_URL), // hash 和 history 選擇
routes,
});
export default router;
~~~
* 使用時候容器
~~~html
<template>
<nav>
<router-link to="/">Home</router-link> |
<router-link to="/about">About</router-link>
</nav>
<!-- 使用時候容器 -->
<router-view />
</template>
~~~
- 官網給的工具
- 聲明vue2 和 vue3
- 指令速覽
- Mustache -- 語法
- v-once -- 只渲染一次
- v-text -- 插入文本
- v-html -- 渲染html
- v-pre -- 顯示原始的Mustache標簽
- v-cloak -- 遮蓋
- v-memo(新)-- 緩存指定值
- v-if/v-show -- 條件渲染
- v-for -- 循環
- v-bind -- 知識
- v-bind -- 修飾符
- v-on -- 點擊事件
- v-model -- 雙向綁定
- 其他基礎知識速覽
- 快速使用
- 常識知識點
- key -- 作用 (后續要更新)
- computed -- 計算屬性
- watch -- 偵聽
- 防抖和節流
- vue3 -- 生命周期
- vue-cli 和 vite 項目搭建方法
- vite -- 導入動態圖片
- 組件
- 單文件組件 -- SFC
- 組件通信 -- porp
- 組件通信 -- $emit
- 組件通信 -- Provide / Inject
- 組件通信 -- 全局事件總線mitt庫
- 插槽 -- slot
- 整體使用案例
- 動態組件 -- is
- keep-alive
- 分包 -- 異步組價
- mixin -- 混入
- v-model-- 組件
- 使用計算屬性
- v-model -- 自定義修飾符
- Suspense -- 實驗屬性
- Teleport -- 指定掛載
- 組件實例 -- $ 屬性
- Option API VS Composition API
- Setup -- 組合API 入口
- api -- reactive
- api -- ref
- 使用ref 和 reactive 場景
- api -- toRefs 和 toRef
- api -- readonly
- 判斷性 -- API
- 功能性 -- API
- api -- computed
- api -- $ref 使用
- api -- 生命周期
- Provide 和 Inject
- watch
- watchEffect
- watch vs. watchEffect
- 簡單使用composition Api
- 響應性語法糖
- css -- 功能
- 修改css -- :deep() 和 var
- Vue3.2 -- 語法
- ts -- vscode 配置
- attrs/emit/props/expose/slots -- 使用
- props -- defineProps
- props -- defineProps Ts
- emit -- defineEmits
- emit -- defineEmits Ts
- $ref -- defineExpose
- slots/attrs -- useSlots() 和 useAttrs()
- 自定義指令
- Vue -- 插件
- Vue2.x 和 Vue3.x 不同點
- $children -- 移除
- v-for 和 ref
- attribute 強制行為
- 按鍵修飾符
- v-if 和 v-for 優先級
- 組件使用 v-model -- 非兼容
- 組件
- h -- 函數
- jsx -- 編寫
- Vue -- Router
- 了解路由和vue搭配
- vueRouter -- 簡單實現
- 安裝即使用
- 路由懶加載
- router-view
- router-link
- 路由匹配規則
- 404 頁面配置
- 路由嵌套
- 路由組件傳參
- 路由重定向和別名
- 路由跳轉方法
- 命名路由
- 命名視圖
- Composition API
- 路由守衛
- 路由元信息
- 路由其他方法 -- 添加/刪除/獲取
- 服務器配置映射
- 其他
- Vuex -- 狀態管理
- Option Api -- VUEX
- composition API -- VUEX
- module -- VUEX
- 刷新后vuex 數據同步
- 小技巧
- Pinia -- 狀態管理
- 開始使用
- pinia -- state
- pinia -- getter
- pinia -- action
- pinia -- 插件 ??
- Vue 源碼解讀
- 開發感悟
- 練手項目