[深刻01] 執行上下文
[深刻02] 原型鏈
[深刻03] 繼承
[深刻04] 事件循環
[深刻05] 柯里化 偏函數 函數記憶
[深刻06] 隱式轉換 和 運算符
[深刻07] 瀏覽器緩存機制(http緩存機制)
[深刻08] 前端安全
[深刻09] 深淺拷貝
[深刻10] Debounce Throttle
[深刻11] 前端路由
[深刻12] 前端模塊化
[深刻13] 觀察者模式 發佈訂閱模式 雙向數據綁定
[深刻14] canvas
[深刻15] webSocket
[深刻16] webpack
[深刻17] http 和 https
[深刻18] CSS-interview
[react] Hooksjavascript
[部署01] Nginx
[部署02] Docker 部署vue項目
[部署03] gitlab-CIcss
[源碼-webpack01-前置知識] AST抽象語法樹
[源碼-webpack02-前置知識] Tapable
[源碼-webpack03] 手寫webpack - compiler簡單編譯流程html
(Universal Resource Identifier
Uniform Resource Locator
分別標識惟一資源和標識惟一地址很麻煩,因此用URL也充當RUI的角色,即標記惟一資源還標記該資源的惟一地址
http://www.baidu.com:80/stu/index.html?name=xxx&age=25#teacher
前端
http://
,https://
www.baicu.com
:80
/開始 ?以前的部分
, 本例中是:/stu/index.html
?開頭到結尾,或者?開頭到#以前
,本例是:?name=xxx&age=25
#開頭到結尾
,本例是:teacher
window.addEventListener('load', ....)
DOM完整解析過程:
1. 解析html
2. 解析css - 包括當html中的樣式和外部引入的樣式
3. 解析並運行腳本 - 報錯本html中的腳本和外部引入的腳本
4. DOM構建完成 ---------------------------------------------------- DOM加載完成,觸發 DOMContentLoaded
5. 加載圖片,視頻等其餘資源
6. 頁面加載完畢 --------------------------------------------------- 頁面加載完成,觸發 load
複製代碼
String.prototype.slice()
特例:
''.slice(1) ----------- 返回 '' 空字符串
案例:
window.location.hash
// 由於:當地址欄的url中的hash不存在時,window.location.hash返回的是空字符串,這種狀況以下
// 因此:window.location.hash.slice(1) => 返回空字符串
複製代碼
window.location 對象
屬性:
pathname: 返回url的path部分,/開始 ?以前 或者 /開始到結果,若是沒有query和hash
origin:protocal + hostname + port 三者之和,至關於協議,域名,端口
protocal:協議 http:// https://
hostnme: 主機名
port:端口號
host:主機 (hostname + port)
search:查詢字符串 (?開頭到#以前,或者?開頭到結尾)
hash:片斷字符串 (哈希值,#開頭到結尾)
複製代碼
<a href="#anchor1">錨點1</a>
<a href="#anchor2">錨點2</a>
<div id="anchor1">錨點1的位置</div>
<div id="anchor2">錨點2的位置</div>
說明:
- 點擊a2,頁面會跳轉到div2的位置
- 而且頁面的hash部分也會改變,即 url 中以 #開頭的字符串會改變
- anchor:是錨的意思
- 注意:a標籤的name屬性已經廢棄,用id代替 (由於有的教程使用name屬性實現的)
複製代碼
<body>
<a href="#anchor1">錨點1</a>
<a href="#anchor2">錨點2</a>
<script>
window.addEventListener('hashchange', function() {
console.log('111111111')
}, false)
</script>
</body>
說明:
- 點擊a標籤,url中的hash改變,hash改變,hashchange事件觸發,則監聽函數就會執行,輸出111111
複製代碼
hash-router
原理:
(1) hash改變,地址欄url的hash字符串改變,觸發hashchange事件
(2) 在hashchange事件的回調函數中更新視圖
代碼:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
</head>
<body>
<a href="#/home">home</a>
<a href="#/other">other</a>
<div id="content">內容部分</div>
<script>
const routes = [{
path: '/home',
component: '<h1>home頁面</h1>'
}, {
path: '/other',
component: '<h1>other頁面</h1>'
}]
class Router {
constructor(routes) { // 構造函數
this.route = {} // 路由映射
this.createRouteMap(routes) // 建立路由映射
this.init() // 初始化
}
createRouteMap = (routes) => {
routes.forEach(item => {
this.route[item.path] = () => {
document.getElementById('content').innerHTML = item.component
// 函數體的做用:將id是content的div中的內容換成 componet
}
// 循環配置
// key是path
// value包裝成一個更新html內容的函數,在 load 和 hahschange 中調用
})
}
init = () => {
window.addEventListener('load', this.updateView, false) // 頁面加載完成時觸發,注意區分DOMContentLoaded
window.addEventListener('hashchange', this.updateView, false)
}
updateView = () => {
const hash = window.location.hash.slice(1) || '/home'; // 初次加載home頁面
// load事件觸發時,window.location.hash => 返回 '' 空字符串
// ''.slice(1) => 返回''
if (this.route[hash]) this.route[hash]()
// 存在,則執行函數
}
}
new Router(routes)
</script>
</body>
</html>
注意:該html須要用 Live Server 啓動,vscode插件
複製代碼
back()
, forward()
, go()
,pushState()
,replaceState()
window.history.pushState({}, null, url)
history-router
原理:
(1) 封裝一個方法,在pushState()和replaceState()改變url後調用,在該方法中獲取最新的window.location.path,更相信頁面
(2) 經過 go() back() forward() 瀏覽器前進後退等觸發 popstate 事件
代碼:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
</head>
<body>
<a href="javascript:void(0)" data-href="/home">home</a> // html中的自定義屬性
<a href="javascript:void(0)" data-href="/other">other</a>
<div id="content">content的內容</div>
<script>
const routes = [{
path: '/home',
component: '<h1>home頁面</h1>'
}, {
path: '/other',
component: '<h1>other頁面</h1>'
}]
class Router {
constructor(routes) {
this.route = {} // key-value鍵值對,key是path,value是更新視圖的函數
this.createRouteMap(routes) // 建立路由映射
this.bindEvent() // 綁定a標籤的點擊事件
this.init() // 綁定load和popstate事件
}
createRouteMap = (routes) => {
routes.forEach(item => {
this.route[item.path] = () => {
document.getElementById('content').innerHTML = item.component
}
})
}
bindEvent = () => {
const a = document.getElementsByTagName('a')
Array.prototype.forEach.call(a, item => { // 第二個參數,是forEach須要傳入的回調函數
item.addEventListener('click', () => {
const path = item.getAttribute('data-href') // 獲取data-herf屬性
this.pushStateFn(path)
// 執行History.pushState()方法
// 這裏因爲是箭頭函數,this指向父級所在的上下文環境,即 bindEvent 所在的上下文環境,即Router
}, false)
})
}
pushStateFn = (url) => {
window.history.pushState({}, null, url) // 改變url後,調用更新視圖的函數updateView
this.updateView() // 更新視圖
}
init = () => {
window.addEventListener('load', this.updateView, false) // 頁面加載完成時觸發
window.addEventListener('popstate', this.updateView, false) // 瀏覽器前進後退,History.go() back() forward()時觸發
}
updateView = () => {
const path = window.location.pathname || '/'; // 獲取url的path部分
if(this.route[path]) this.route[path]() // path在route中存在,就執行對象的函數,key-value鍵值對
}
}
new Router(routes)
</script>
</body>
</html>
複製代碼
手動實現一個vue-router(hash版)
vue相關前置知識
- <router-link to="#/home">home</router-link> // 點擊會跳轉到 '#/home' 地址
- <router-view></router-view> // 路由將顯示的DOM位置
// 定義一個名爲 button-counter 的新組件
Vue.component('button-counter', {
data: function () {
return {
count: 0
}
},
template: '<button v-on:click="count++">You clicked me {{ count }} times.</button>'
})
- 由於組件是可複用的 Vue 實例,因此它們與 new Vue 接收相同的選項
- 例如 data、computed、watch、methods 以及生命週期鉤子等。
---------------
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
<!-- 引入 Vue 經過CDN引入 -->
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
</head>
<body>
<div id="app">
<!-- 注意 router-link組件具備 to 屬性 -->
<router-link to="#/home">home</router-link>
<router-link to="#/other">other</router-link>
<router-view></router-view>
</div>
<script>
// 建立兩個vue組件
const Home = {template: '<h1>home頁面</h1>'}
const Other = {template: '<h1>other頁面</h1>'}
// 建立vue路由數組
const routes = [{
path: '/home',
component: Home
}, {
path: '/other',
component: Other
}]
class VueRouter {
constructor(Vue, option) {
// 參數:
// Vue:Vue構造函數,經過cdn引入的
// option: 配置對象,包含routes路由數組屬性
this.$options = option
this.routeMap = {} // 路由映射,是這樣的結構 { path: component }
this.createRouteMap(this.$options) // 建立路由映射
this.app = new Vue({
data: {
currentHash: '#/'
}
})
// this.app.currentHash => 能夠訪問到currentHash的值 '#/'
// 舉例
// var data = {name: 'woow_wu7'}
// var vm = new Vue({
// data: data
// })
// vm.name === data.name => true
this.init() // 初始化監聽函數
this.initComponent(Vue) // 初始化Vue種的各類組件
}
createRouteMap = (option) => {
// 注意:option 是傳入VueRoute的第二個參數,即 {routes: routes}
// 因此:options是一個對象
option.routes.forEach(item => {
this.routeMap[item.path] = item.component
// this.routeMap是這樣一個對象:{path: component}
})
}
init = () => {
window.addEventListener('load', this.onHashChange, false)
// 頁面加載完成觸發,注意區別 DOMContentLoaded
// load:頁面加載完成時觸發,包括 DOM加載完成,圖片,視頻等全部資源加載完成
// DOMContentLoaded:DOM加載完成時觸發
window.addEventListener('hashchange', this.onHashChange, false)
// 監聽 hashchange 事件
// 觸發hashchange的條件:hash改變時候
}
onHashChange = () => {
this.app.currentHash = window.location.hash.slice(1) || '/'
// (1)
// 當 hahs沒有改變時,load事件觸發時
// window.location.hash = '' => window.location.hash.slice(1) = ''
// 因此:此種狀況:this.app.currentHash = '/'
// (2)
// hash改變時,window.location.hash有值,是 '#/...' 這樣的字符串
}
initComponent = (Vue) => {
// router-link組件
// props to屬性
// template 本質上會被處理成a標籤,href屬性是傳入的 to 屬性,內容是 slot 插入的內容
Vue.component('router-link', {
props: {
to: {
type: String,
value: ''
}
},
template: '<a :href="to"><slot/></a>'
})
Vue.component('router-view', {
render: (h) => {
const component = this.routeMap[this.app.currentHash] // 拿到最新hash對應的組件
return h(component)
// h(component) 至關於 createElement(component)
// render: function(createElement) { return createElement(App); }
}
})
}
}
new VueRouter(Vue, {
routes
})
new Vue({
el: '#app'
})
</script>
</body>
</html>
複製代碼
URI和URL:www.luyuqiang.com/uri-url-urn…
URI和URL的區別舉例(很形象)juejin.im/post/5cd4e4…
URL的組成(優秀)www.jianshu.com/p/406d19dfa…
DOMContentLoaded和load的區別:www.jianshu.com/p/1a8a7e698…
window.location對象:wangdoc.com/javascript/…
vue-router模擬實現 juejin.im/post/5b35dc…
hash history 路由 模擬實現 juejin.im/post/5b3301…
vue-router源碼記錄 juejin.im/post/5cf9f7…
VueRouter源碼分析 juejin.im/post/5cb2c1…vue