1、兩欄布局
要求:垂直兩欄,左邊固定右邊自適應(yīng)。
<!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>
<style>
.outer {
height: 100px;
margin-bottom: 10px;
}
.left {
background: tomato;
height: 100px;
}
.right {
background: gold;
height: 100px;
}
/* 浮動(dòng) */
.outer1 .left {
width: 200px;
float: left;
}
.outer1 .right {
width: auto;
margin-left: 200px;
}
/* flex */
.outer2 {
display: flex;
}
.outer2 .left {
flex-grow: 0;
flex-shrink: 0;
flex-basis: 200px;
}
.outer2 .right {
flex: auto; /* 1 1 auto */
}
/* position */
.outer3 {
position: relative;
}
.outer3 .left {
position: absolute;
width: 200px;
}
.outer3 .right {
margin-left: 200px;
}
/* position again */
.outer4 {
position: relative;
}
.outer4 .left {
width: 200px;
}
.outer4 .right {
position: absolute;
top: 0;
left: 200px;
right: 0;
}
</style>
</head>
<!-- 左右兩欄,左邊固定,右邊自適應(yīng) -->
<body>
<p class="outer outer1">
<p class="left">1-left</p>
<p class="right">1-right</p>
</p>
<p class="outer outer2">
<p class="left">2-left</p>
<p class="right">2-right</p>
</p>
<p class="outer outer3">
<p class="left">3-left</p>
<p class="right">3-right</p>
</p>
<p class="outer outer4">
<p class="left">4-left</p>
<p class="right">4-right</p>
</p>
</body>
</html>
2、三欄布局
要求:垂直三欄布局,左右兩欄寬度固定,中間自適應(yīng)
<!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>
<style>
.outer, .left, .middle, .right {
height: 100px;
margin-bottom: 5px;
}
.left {
background: tomato;
}
.middle {
background: lightgreen;
}
.right {
background: gold;
}
/* 左右分別設(shè)置絕對(duì)定位 中間設(shè)置外邊距 */
.outer1 {
position: relative;
}
.outer1 .left {
position: absolute;
width: 100px;
}
.outer1 .middle {
margin: 0 200px 0 100px;
}
.outer1 .right {
position: absolute;
width: 200px;
top: 0;
right: 0;
}
/* flex 布局 */
.outer2 {
display: flex;
}
.outer2 .left {
flex: 0 0 100px;
}
.outer2 .middle {
flex: auto;
}
.outer2 .right {
flex: 0 0 200px;
}
/* 浮動(dòng)布局 但是 html 中 middle要放到最后 */
.outer3 .left {
float: left;
width: 100px;
}
.outer3 .right {
float: right;
width: 200px;
}
.outer3 .middle {
margin: 0 200px 0 100px;
}
</style>
</head>
<!-- 三欄布局 左右固定 中間自適應(yīng) -->
<body>
<p class="outer outer1">
<p class="left">1-left</p>
<p class="middle">1-middle</p>
<p class="right">1-right</p>
</p>
<p class="outer outer2">
<p class="left">2-left</p>
<p class="middle">2-middle</p>
<p class="right">2-right</p>
</p>
<p class="outer outer3">
<p class="left">3-left</p>
<p class="right">3-right</p>
<p class="middle">3-middle</p>
</p>
</body>
</html>
3、圣杯布局 和 雙飛翼布局
和三欄布局要求相同,不過(guò)中間列要寫(xiě)在前面保證優(yōu)先渲染。
<!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>
<style>
.outer, .left, .middle, .right {
height: 100px;
margin-bottom: 5px;
}
.left {
background: tomato;
}
.middle {
background: lightgreen;
}
.right {
background: gold;
}
/* 圣杯布局 通過(guò)浮動(dòng)和負(fù)邊距實(shí)現(xiàn) */
.outer1 {
padding: 0 200px 0 100px;
}
.outer1 .middle {
width: 100%;
float: left;
}
.outer1 .left {
width: 100px;
float: left;
margin-left: -100%;
position: relative;
left: -100px;
}
.outer1 .right {
width: 200px;
float: left;
margin-left: -200px;
position: relative;
left: 200px;
}
/* 雙飛翼布局 */
.outer2 .middle-wrapper {
width: 100%;
float: left;
}
.outer2 .middle {
margin: 0 200px 0 100px;
}
.outer2 .left {
width: 100px;
float: left;
margin-left: -100%;
}
.outer2 .right {
width: 200px;
float: left;
margin-left: -200px;
}
</style>
</head>
<!-- 三欄布局 左右固定 中間自適應(yīng) -->
<body>
<!-- 圣杯布局 middle 最先 -->
<p class="outer outer1">
<p class="middle">圣杯-middle</p>
<p class="left">圣杯-left</p>
<p class="right">圣杯-right</p>
</p>
<!-- 雙飛翼布局 middle 最先 多一層 p -->
<p class="outer outer2">
<p class="middle-wrapper">
<p class="middle">雙飛翼布局-middle</p>
</p>
<p class="left">雙飛翼布局-left</p>
<p class="right">雙飛翼布局-right</p>
</p>
</body>
</html>
4、三角形
實(shí)現(xiàn)一個(gè)三角形
常見(jiàn)題目,通過(guò) border 實(shí)現(xiàn)
<!DOCTYPE html>
<html>
<head>
<title>三角形</title>
<style type="text/css">
.box1, .box2, .box3, .box4 {
height: 0px;
width: 0px;
float: left;
border-style: solid;
margin: 10px;
}
.box1 { /* 等腰直角 */
border-width: 100px;
border-color: tomato transparent transparent transparent;
}
.box2 { /* 等邊 */
border-width: 100px 173px;
border-color: transparent tomato transparent transparent;
}
.box3 { /* 等腰 */
border-width: 100px 80px;
border-color: transparent transparent tomato transparent;
}
.box4 { /* 其他 */
border-width: 100px 90px 80px 70px;
border-color: transparent transparent transparent tomato;
}
</style>
</head>
<body>
<p class="box1"></p>
<p class="box2"></p>
<p class="box3"></p>
<p class="box4"></p>
</body>
</html>
5、正方形
使用 css 實(shí)現(xiàn)一個(gè)寬高自適應(yīng)的正方形
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title></title>
<style>
/* 都是像對(duì)于屏幕寬度的比例 */
.square1 {
width: 10%;
height: 10vw;
background: red;
}
/* margin/padding 百分比是相對(duì)父元素 width 的 */
.square2 {
width: 20%;
height: 0;
padding-top: 20%;
background: orange;
}
/* 通過(guò)子元素 margin */
.square3 {
width: 30%;
overflow: hidden; /* 觸發(fā) BFC */
background: yellow;
}
.square3::after {
content: '';
display: block;
margin-top: 100%; /* 高度相對(duì)于 square3 的 width */
}
</style>
</head>
<!-- 畫(huà)一個(gè)正方形 -->
<body>
<p class="square1"></p>
<p class="square2"></p>
<p class="square3"></p>
</body>
</html>
6、扇形
實(shí)現(xiàn)一個(gè) 1/4 圓、任意弧度的扇形
有多種實(shí)現(xiàn)方法,這里選幾種簡(jiǎn)單方法(我看得懂的)實(shí)現(xiàn)
<!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>
<style>
/* 通過(guò) border 和 border-radius 實(shí)現(xiàn) 1/4 圓 */
.sector1 {
height: 0;
width: 0;
border: 100px solid;
border-radius: 50%;
border-color: turquoise tomato tan thistle;
}
/* 類似三角形的做法加上父元素 overflow: hidden; 也可以實(shí)現(xiàn)任意弧度圓 */
.sector2 {
height: 100px;
width: 200px;
border-radius: 100px 100px 0 0;
overflow: hidden;
}
.sector2::after {
content: '';
display: block;
height: 0;
width: 0;
border-style: solid;
border-width: 100px 58px 0;
border-color: tomato transparent;
transform: translate(42px,0);
}
/* 通過(guò)子元素 rotateZ 和父元素 overflow: hidden 實(shí)現(xiàn)任意弧度扇形(此處是60°) */
.sector3 {
height: 100px;
width: 100px;
border-top-right-radius: 100px;
overflow: hidden;
/* background: gold; */
}
.sector3::after {
content: '';
display: block;
height: 100px;
width: 100px;
background: tomato;
transform: rotateZ(-30deg);
transform-origin: left bottom;
}
/* 通過(guò) skewY 實(shí)現(xiàn)一個(gè)60°的扇形 */
.sector4 {
height: 100px;
width: 100px;
border-top-right-radius: 100px;
overflow: hidden;
}
.sector4::after {
content: '';
display: block;
height: 100px;
width: 100px;
background: tomato;
transform: skewY(-30deg);
transform-origin: left bottom;
}
/* 通過(guò)漸變?cè)O(shè)置60°扇形 */
.sector5 {
height: 200px;
width: 200px;
background: tomato;
border-radius: 50%;
background-image: linear-gradient(150deg, transparent 50%, #fff 50%),
linear-gradient(90deg, #fff 50%, transparent 50%);
}
</style>
</head>
<body>
<p style="display: flex; justify-content: space-around;">
<p class="sector1"></p>
<p class="sector2"></p>
<p class="sector3"></p>
<p class="sector4"></p>
<p class="sector5"></p>
</p>
</body>
</html>
7、水平垂直居中
實(shí)現(xiàn)子元素的水平垂直居中
<!DOCTYPE html>
<html>
<head>
<title>水平垂直居中</title>
<style type="text/css">
.outer {
height: 200px;
width: 200px;
background: tomato;
margin: 10px;
float: left;
position: relative;
}
.inner {
height: 100px;
width: 100px;
background: black;
}
/*
* 通過(guò) position 和 margin 居中
* 缺點(diǎn):需要知道 inner 的長(zhǎng)寬
*/
.inner1 {
position: absolute;
top: 50%;
left: 50%;
margin-top: -50px;
margin-left: -50px;
}
/*
* 通過(guò) position 和 margin 居中 (2
*/
.inner2 {
position: absolute;
top: 0;
right: 0;
bottom: 0;
left: 0;
margin: auto;
}
/*
* 通過(guò) flex 進(jìn)行居中
*/
.outer3 {
display: flex;
justify-content: center;
align-items: center;
}
/**
* 通過(guò) position 和 transform 居中
*/
.inner4 {
top: 50%;
left: 50%;
transform: translate(-50%,-50%);
position: absolute;
}
</style>
</head>
<body>
<p class="outer outer1">
<p class="inner inner1"></p>
</p>
<p class="outer outer2">
<p class="inner inner2"></p>
</p>
<p class="outer outer3">
<p class="inner inner3"></p>
</p>
<p class="outer outer4">
<p class="inner inner4"></p>
</p>
</body>
</html>
8、清除浮動(dòng)
要求:清除浮動(dòng)
可以通過(guò) clear:both 或 BFC 實(shí)現(xiàn)
<!DOCTYPE html>
<html>
<head>
<title>清除浮動(dòng)</title>
<style type="text/css">
.outer {
width: 200px;
background: tomato;
margin: 10px;
position: relative;
}
.inner {
height: 100px;
width: 100px;
background: pink;
margin: 10px;
float: left;
}
/* 偽元素 */
.outer1::after {
content: '';
display: block;
clear: both;
}
/* 創(chuàng)建 BFC */
.outer2 {
overflow: hidden;
}
</style>
</head>
<body>
<p class="outer outer1">
<p class="inner"></p>
</p>
<p class="outer outer2">
<p class="inner"></p>
</p>
</body>
</html>
9、彈出框
使用 CSS 寫(xiě)一個(gè)彈出框效果
<!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>
<style>
.bg {
height: 666px;
width: 100%;
font-size: 60px;
text-align: center;
}
.dialog {
z-index: 999;
position: fixed;
top: 0;
right: 0;
bottom: 0;
left: 0;
background: rgba(0, 0, 0, 0.5);
}
.dialog .content {
min-height: 300px;
width: 600px;
background: #fff;
border-radius: 5px;
border: 1px solid #ebeef5;
box-shadow: 0 2px 12px 0 rgba(0,0,0,.1);
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
}
</style>
</head>
<body>
<p class="bg">
頁(yè)面內(nèi)容
</p>
<p class="dialog">
<p class="content">
彈出框
</p>
</p>
</body>
</html>
10、導(dǎo)航欄
要求:一個(gè) p 內(nèi)部放很多水平 p ,并可以橫向滾動(dòng)。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=p, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
<style>
body,html {
margin: 0;
padding: 0;
}
/* flex 實(shí)現(xiàn) */
/* .nav {
display: flex;
height: 30px;
border: 1px solid #000;
padding: 3px;
overflow-x: auto;
}
.nav::-webkit-scrollbar {
display: none;
}
.item {
flex: 0 0 200px;
height: 30px;
margin-right: 5px;
background: gray;
} */
/* inline-block 和 white-space: nowrap; 實(shí)現(xiàn) */
.nav {
height: 30px;
padding: 3px;
border: 1px solid #000;
overflow-x: auto;
white-space: nowrap;
}
.nav::-webkit-scrollbar {
display: none;
}
.item {
display: inline-block;
width: 200px;
height: 30px;
margin-right: 5px;
background: gray;
}
</style>
</head>
<!-- 水平滾動(dòng)導(dǎo)航欄 -->
<body>
<p class="nav">
<p class="item">item1</p>
<p class="item">item2</p>
<p class="item">item3</p>
<p class="item">item4</p>
<p class="item">item5</p>
<p class="item">item6</p>
<p class="item">item7</p>
<p class="item">item8</p>
<p class="item">item9</p>
</p>
</body>
</html>
CSS 部分完,總結(jié),F(xiàn)lex 無(wú)敵。
1、手寫(xiě) bind、call 和 apply
Function.prototype.bind = function(context, ...bindArgs) {
// func 為調(diào)用 bind 的原函數(shù)
const func = this;
context = context || window;
if (typeof func !== 'function') {
throw new TypeError('Bind must be called on a function');
}
// bind 返回一個(gè)綁定 this 的函數(shù)
return function(...callArgs) {
let args = bindArgs.concat(callArgs);
if (this instanceof func) {
// 意味著是通過(guò) new 調(diào)用的 而 new 的優(yōu)先級(jí)高于 bind
return new func(...args);
}
return func.call(context, ...args);
}
}
// 通過(guò)隱式綁定實(shí)現(xiàn)
Function.prototype.call = function(context, ...args) {
context = context || window;
context.func = this;
if (typeof context.func !== 'function') {
throw new TypeError('call must be called on a function');
}
let res = context.func(...args);
delete context.func;
return res;
}
Function.prototype.apply = function(context, args) {
context = context || window;
context.func = this;
if (typeof context.func !== 'function') {
throw new TypeError('apply must be called on a function');
}
let res = context.func(...args);
delete context.func;
return res;
}
2、實(shí)現(xiàn)一個(gè)繼承
// 參考 You Dont Know JavaScript 上卷
// 基類
function Base() {
}
// 派生類
function Derived() {
Base.call(this);
}
// 將派生類的原型的原型鏈掛在基類的原型上
Object.setPrototypeOf(Derived.prototype, Base.prototype);
3、實(shí)現(xiàn)一個(gè) new
// 手動(dòng)實(shí)現(xiàn)一個(gè) new 關(guān)鍵字的功能的函數(shù) _new(fun, args) --> new fun(args)
function _new(fun, ...args) {
if (typeof fun !== 'function') {
return new Error('參數(shù)必須是一個(gè)函數(shù)');
}
let obj = Object.create(fun.prototype);
let res = fun.call(obj, ...args);
if (res !== null && (typeof res === 'object' || typeof res === 'function')) {
return res;
}
return obj;
}
4、實(shí)現(xiàn)一個(gè) instanceof
// a instanceof b
function _instanceof(a, b) {
while (a) {
if (a.__proto__ === b.prototype) return true;
a = a.__proto__;
}
return false;
}
5、手寫(xiě) jsonp 的實(shí)現(xiàn)
// foo 函數(shù)將會(huì)被調(diào)用 傳入后臺(tái)返回的數(shù)據(jù)
function foo(data) {
console.log('通過(guò)jsonp獲取后臺(tái)數(shù)據(jù):', data);
document.getElementById('data').innerHTML = data;
}
/**
* 通過(guò)手動(dòng)創(chuàng)建一個(gè) script 標(biāo)簽發(fā)送一個(gè) get 請(qǐng)求
* 并利用瀏覽器對(duì) <script> 不進(jìn)行跨域限制的特性繞過(guò)跨域問(wèn)題
*/
(function jsonp() {
let head = document.getElementsByTagName('head')[0]; // 獲取head元素 把js放里面
let js = document.createElement('script');
js.src = 'http://domain:port/testJSONP?a=1&b=2&callback=foo'; // 設(shè)置請(qǐng)求地址
head.appendChild(js); // 這一步會(huì)發(fā)送請(qǐng)求
})();
// 后臺(tái)代碼
// 因?yàn)槭峭ㄟ^(guò) script 標(biāo)簽調(diào)用的 后臺(tái)返回的相當(dāng)于一個(gè) js 文件
// 根據(jù)前端傳入的 callback 的函數(shù)名直接調(diào)用該函數(shù)
// 返回的是 'foo(3)'
function testJSONP(callback, a, b) {
return `${callback}(${a + b})`;
}
6、ajax 的實(shí)現(xiàn)
// Asynchronous Javascript And XML
function ajax(options) {
// 選項(xiàng)
var method = options.method || 'GET',
params = options.params,
data = options.data,
url = options.url + (params ? '?' + Object.keys(params).map(key => key + '=' + params[key]).join('&') : ''),
async = options.async === false ? false : true,
success = options.success,
headers = options.headers;
var request;
if (window.XMLHttpRequest) {
request = new XMLHttpRequest();
} else {
request = new ActiveXObject('Microsoft.XMLHTTP');
}
request.onreadystatechange = function() {
/**
readyState:
0: 請(qǐng)求未初始化
1: 服務(wù)器連接已建立
2: 請(qǐng)求已接收
3: 請(qǐng)求處理中
4: 請(qǐng)求已完成,且響應(yīng)已就緒
status: HTTP 狀態(tài)碼
**/
if (request.readyState === 4 && request.status === 200) {
success && success(request.responseText);
}
}
request.open(method, url, async);
if (headers) {
Object.keys(headers).forEach(key => request.setRequestHeader(key, headers[key]));
}
method === 'GET' ? request.send() : request.send(data);
}
// e.g.
ajax({
method: 'GET',
url: '...',
success: function(res) {
console.log('success', res);
},
async: true,
params: {
p: 'test',
t: 666
},
headers: {
'Content-Type': 'application/json'
}
})
7、reduce 的實(shí)現(xiàn)
function reduce(arr, callback, initial) {
let i = 0;
let acc = initial === undefined ? arr[i++] : initial;
for (; i < arr.length; i++) {
acc = callback(acc, arr[i], i, arr);
}
return acc;
}
8、實(shí)現(xiàn) generator 的自動(dòng)執(zhí)行器
要求是 yield 后面只能是 Promise 或 Thunk 函數(shù),詳見(jiàn) es6.ruanyifeng.com/#docs/gener…
function run(gen) {
let g = gen();
function next(data) {
let result = g.next(data);
if (result.done) return result.value;
if (result.value instanceof Promise) {
result.value.then(data => next(data));
} else {
result.value(next);
}
}
return next();
}
// ======== e.g. ==========
function func(data, cb) {
console.log(data);
cb();
}
function *gen() {
let a = yield Promise.resolve(1);
console.log(a);
let b = yield Promise.resolve(2);
console.log(b);
yield func.bind(null, a + b);
}
run(gen);
/**
output:
1
2
3
**/
9、節(jié)流
/**
* 節(jié)流函數(shù) 限制函數(shù)在指定時(shí)間段只能被調(diào)用一次
* 用法 比如防止用戶連續(xù)執(zhí)行一個(gè)耗時(shí)操作 對(duì)操作按鈕點(diǎn)擊函數(shù)進(jìn)行節(jié)流處理
*/
function throttle(func, wait) {
let timer = null;
return function(...args) {
if (!timer) {
func(...args);
timer = setTimeout(() => {
timer = null;
}, wait);
}
}
}
10、防抖
/**
* 函數(shù)調(diào)用后不會(huì)被立即執(zhí)行 之后連續(xù) wait 時(shí)間段沒(méi)有調(diào)用才會(huì)執(zhí)行
* 用法 如處理用戶輸入
*/
function debounce(func, wait) {
let timer = null;
return function(...args) {
if (timer) clearTimeout(timer); // 如果在定時(shí)器未執(zhí)行期間又被調(diào)用 該定時(shí)器將被清除 并重新等待 wait 秒
timer = setTimeout(() => {
func(...args);
}, wait);
}
}
11、手寫(xiě) Promise
簡(jiǎn)單實(shí)現(xiàn),基本功能都有了。
const PENDING = 1;
const FULFILLED = 2;
const REJECTED = 3;
function MyPromise(executor) {
let self = this;
this.resolveQueue = [];
this.rejectQueue = [];
this.state = PENDING;
this.val = undefined;
function resolve(val) {
if (self.state === PENDING) {
setTimeout(() => {
self.state = FULFILLED;
self.val = val;
self.resolveQueue.forEach(cb => cb(val));
});
}
}
function reject(err) {
if (self.state === PENDING) {
setTimeout(() => {
self.state = REJECTED;
self.val = err;
self.rejectQueue.forEach(cb => cb(err));
});
}
}
try {
// 回調(diào)是異步執(zhí)行 函數(shù)是同步執(zhí)行
executor(resolve, reject);
} catch(err) {
reject(err);
}
}
MyPromise.prototype.then = function(onResolve, onReject) {
let self = this;
// 不傳值的話默認(rèn)是一個(gè)返回原值的函數(shù)
onResolve = typeof onResolve === 'function' ? onResolve : (v => v);
onReject = typeof onReject === 'function' ? onReject : (e => { throw e });
if (self.state === FULFILLED) {
return new MyPromise(function(resolve, reject) {
setTimeout(() => {
try {
let x = onResolve(self.val);
if (x instanceof MyPromise) {
x.then(resolve);
} else {
resolve(x);
}
} catch(e) {
reject(e);
}
});
});
}
if (self.state === REJECTED) {
return new MyPromise(function(resolve, reject) {
setTimeout(() => {
try {
let x = onReject(self.val);
if (x instanceof MyPromise) {
x.then(resolve);
} else {
resolve(x);
}
} catch(e) {
reject(e);
}
});
});
}
if (self.state === PENDING) {
return new MyPromise(function(resolve, reject) {
self.resolveQueue.push((val) => {
try {
let x = onResolve(val);
if (x instanceof MyPromise) {
x.then(resolve);
} else {
resolve(x);
}
} catch(e) {
reject(e);
}
});
self.rejectQueue.push((val) => {
try {
let x = onReject(val);
if (x instanceof MyPromise) {
x.then(resolve);
} else {
resolve(x);
}
} catch(e) {
reject(e);
}
});
});
}
}
MyPromise.prototype.catch = function(onReject) {
return this.then(null, onReject);
}
MyPromise.all = function(promises) {
return new MyPromise(function(resolve, reject) {
let cnt = 0;
let result = [];
for (let i = 0; i < promises.length; i++) {
promises[i].then(res => {
result[i] = res;
if (++cnt === promises.length) resolve(result);
}, err => {
reject(err);
})
}
});
}
MyPromise.race = function(promises) {
return new MyPromise(function(resolve, reject) {
for (let i = 0; i < promises.length; i++) {
promises[i].then(resolve, reject);
}
});
}
MyPromise.resolve = function(val) {
return new MyPromise(function(resolve, reject) {
resolve(val);
});
}
MyPromise.reject = function(err) {
return new MyPromise(function(resolve, reject) {
reject(err);
})
}
12、實(shí)現(xiàn)一個(gè)路由 - Hash
實(shí)現(xiàn)原理就是監(jiān)聽(tīng) url 的哈希值變化了
<!DOCTYPE html>
<html>
<head>
<title>hash 路由</title>
</head>
<body>
<header>
<a href="#home">首頁(yè)</a>
<a href="#center">個(gè)人中心頁(yè)</a>
<a href="#help">幫助頁(yè)</a>
</header>
<p id="content"></p>
<script>
window.addEventListener('hashchange', (e) => {
let content = document.getElementById('content');
content.innerText = location.hash;
})
</script>
</body>
</html>
13、路由實(shí)現(xiàn) - history
<!DOCTYPE html>
<html>
<head>
<title>history 路由</title>
</head>
<body>
<header>
<a onclick="changeRoute(this)" data-path="home">首頁(yè)</a>
<a onclick="changeRoute(this)" data-path="center">個(gè)人中心頁(yè)</a>
<a onclick="changeRoute(this)" data-path="help">幫助頁(yè)</a>
</header>
<p id="content"></p>
<script>
function changeRoute(route) {
let path = route.dataset.path;
/**
* window.history.pushState(state, title, url)
* state:一個(gè)與添加的記錄相關(guān)聯(lián)的狀態(tài)對(duì)象,主要用于popstate事件。該事件觸發(fā)時(shí),該對(duì)象會(huì)傳入回調(diào)函數(shù)。
* 也就是說(shuō),瀏覽器會(huì)將這個(gè)對(duì)象序列化以后保留在本地,重新載入這個(gè)頁(yè)面的時(shí)候,可以拿到這個(gè)對(duì)象。
* 如果不需要這個(gè)對(duì)象,此處可以填 null。
* title:新頁(yè)面的標(biāo)題。但是,現(xiàn)在所有瀏覽器都忽視這個(gè)參數(shù),所以這里可以填空字符串。
* url:新的網(wǎng)址,必須與當(dāng)前頁(yè)面處在同一個(gè)域。瀏覽器的地址欄將顯示這個(gè)網(wǎng)址。
*/
changePage(path);
history.pushState({ content: path }, null, path);
}
/**
* 調(diào)用 history.pushState() 或者 history.replaceState() 不會(huì)觸發(fā) popstate 事件。
* 點(diǎn)擊后退、前進(jìn)按鈕、或者在 js 中調(diào)用 history.back()、history.forward()、history.go() 方法會(huì)觸發(fā)
*/
window.addEventListener('popstate', (e) => {
let content = e.state && e.state.content;
changePage(content);
});
function changePage(pageContent) {
let content = document.getElementById('content');
content.innerText = pageContent;
}
</script>
</body>
</html>