[深刻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