CSS 部分
两栏布局
要求:垂直两栏,左边固定右边自适应。
查看代码
<!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; } /* 浮动 */ .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> <!-- 左右两栏,左边固定,右边自适应 --> <body> <div class="outer outer1"> <div class="left">1-left</div> <div class="right">1-right</div> </div> <div class="outer outer2"> <div class="left">2-left</div> <div class="right">2-right</div> </div> <div class="outer outer3"> <div class="left">3-left</div> <div class="right">3-right</div> </div> <div class="outer outer4"> <div class="left">4-left</div> <div class="right">4-right</div> </div> </body> </html>
三栏布局
要求:垂直三栏布局,左右两栏宽度固定,中间自适应
查看代码
<!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; } /* 左右分别设置绝对定位 中间设置外边距 */ .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; } /* 浮动布局 但是 html 中 middle要放到最后 */ .outer3 .left { float: left; width: 100px; } .outer3 .right { float: right; width: 200px; } .outer3 .middle { margin: 0 200px 0 100px; } </style> </head> <!-- 三栏布局 左右固定 中间自适应 --> <body> <div class="outer outer1"> <div class="left">1-left</div> <div class="middle">1-middle</div> <div class="right">1-right</div> </div> <div class="outer outer2"> <div class="left">2-left</div> <div class="middle">2-middle</div> <div class="right">2-right</div> </div> <div class="outer outer3"> <div class="left">3-left</div> <div class="right">3-right</div> <div class="middle">3-middle</div> </div> </body> </html>
圣杯布局 和 双飞翼布局
和三栏布局要求相同,不过中间列要写在前面保证优先渲染。
查看代码
<!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; } /* 圣杯布局 通过浮动和负边距实现 */ .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> <!-- 三栏布局 左右固定 中间自适应 --> <body> <!-- 圣杯布局 middle 最先 --> <div class="outer outer1"> <div class="middle">圣杯-middle</div> <div class="left">圣杯-left</div> <div class="right">圣杯-right</div> </div> <!-- 双飞翼布局 middle 最先 多一层 div --> <div class="outer outer2"> <div class="middle-wrapper"> <div class="middle">双飞翼布局-middle</div> </div> <div class="left">双飞翼布局-left</div> <div class="right">双飞翼布局-right</div> </div> </body> </html>
三角形
实现一个三角形
常见题目,通过 border
实现
查看代码
<!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> <div class="box1"></div> <div class="box2"></div> <div class="box3"></div> <div class="box4"></div> </body> </html>
正方形
使用 css 实现一个宽高自适应的正方形
查看代码
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title></title> <style> /* 都是像对于屏幕宽度的比例 */ .square1 { width: 10%; height: 10vw; background: red; } /* margin/padding 百分比是相对父元素 width 的 */ .square2 { width: 20%; height: 0; padding-top: 20%; background: orange; } /* 通过子元素 margin */ .square3 { width: 30%; overflow: hidden; /* 触发 BFC */ background: yellow; } .square3::after { content: ‘‘; display: block; margin-top: 100%; /* 高度相对于 square3 的 width */ } </style> </head> <!-- 画一个正方形 --> <body> <div class="square1"></div> <div class="square2"></div> <div class="square3"></div> </body> </html> 复制代码
扇形
实现一个 1/4 圆、任意弧度的扇形
有多种实现方法,这里选几种简单方法(我看得懂的)实现。
查看代码
<!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> /* 通过 border 和 border-radius 实现 1/4 圆 */ .sector1 { height: 0; width: 0; border: 100px solid; border-radius: 50%; border-color: turquoise tomato tan thistle; } /* 类似三角形的做法加上父元素 overflow: hidden; 也可以实现任意弧度圆 */ .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); } /* 通过子元素 rotateZ 和父元素 overflow: hidden 实现任意弧度扇形(此处是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; } /* 通过 skewY 实现一个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; } /* 通过渐变设置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> <div style="display: flex; justify-content: space-around;"> <div class="sector1"></div> <div class="sector2"></div> <div class="sector3"></div> <div class="sector4"></div> <div class="sector5"></div> </div> </body> </html>
水平垂直居中
实现子元素的水平垂直居中
查看代码
<!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; } /* * 通过 position 和 margin 居中 * 缺点:需要知道 inner 的长宽 */ .inner1 { position: absolute; top: 50%; left: 50%; margin-top: -50px; margin-left: -50px; } /* * 通过 position 和 margin 居中 (2 */ .inner2 { position: absolute; top: 0; right: 0; bottom: 0; left: 0; margin: auto; } /* * 通过 flex 进行居中 */ .outer3 { display: flex; justify-content: center; align-items: center; } /** * 通过 position 和 transform 居中 */ .inner4 { top: 50%; left: 50%; transform: translate(-50%,-50%); position: absolute; } </style> </head> <body> <div class="outer outer1"> <div class="inner inner1"></div> </div> <div class="outer outer2"> <div class="inner inner2"></div> </div> <div class="outer outer3"> <div class="inner inner3"></div> </div> <div class="outer outer4"> <div class="inner inner4"></div> </div> </body> </html>
清除浮动
要求:清除浮动
可以通过 clear:both
或 BFC 实现
查看代码
<!DOCTYPE html> <html> <head> <title>清除浮动</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; } /* 创建 BFC */ .outer2 { overflow: hidden; } </style> </head> <body> <div class="outer outer1"> <div class="inner"></div> </div> <div class="outer outer2"> <div class="inner"></div> </div> </body> </html>
弹出框
使用 CSS 写一个弹出框效果
查看代码
<!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> <div class="bg"> 页面内容 </div> <div class="dialog"> <div class="content"> 弹出框 </div> </div> </body> </html>
导航栏
要求:一个
div
内部放很多水平div
,并可以横向滚动。
查看代码
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=div, initial-scale=1.0"> <meta http-equiv="X-UA-Compatible" content="ie=edge"> <title>Document</title> <style> body,html { margin: 0; padding: 0; } /* flex 实现 */ /* .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; 实现 */ .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> <!-- 水平滚动导航栏 --> <body> <div class="nav"> <div class="item">item1</div> <div class="item">item2</div> <div class="item">item3</div> <div class="item">item4</div> <div class="item">item5</div> <div class="item">item6</div> <div class="item">item7</div> <div class="item">item8</div> <div class="item">item9</div> </div> </body> </html>
CSS 部分完,总结,Flex 无敌。
JavaScript 部分
手写 bind、call 和 apply
Function.prototype.bind = function(context, ...bindArgs) { // func 为调用 bind 的原函数 const func = this; context = context || window; if (typeof func !== ‘function‘) { throw new TypeError(‘Bind must be called on a function‘); } // bind 返回一个绑定 this 的函数 return function(...callArgs) { let args = bindArgs.concat(callArgs); if (this instanceof func) { // 意味着是通过 new 调用的 而 new 的优先级高于 bind return new func(...args); } return func.call(context, ...args); } } // 通过隐式绑定实现 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; }
实现一个继承
// 参考 You Dont Know JavaScript 上卷 // 基类 function Base() { } // 派生类 function Derived() { Base.call(this); } // 将派生类的原型的原型链挂在基类的原型上 Object.setPrototypeOf(Derived.prototype, Base.prototype);
实现一个 new
// 手动实现一个 new 关键字的功能的函数 _new(fun, args) --> new fun(args)
function _new(fun, ...args) { if (typeof fun !== ‘function‘) { return new Error(‘参数必须是一个函数‘); } 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; }
实现一个 instanceof
// a instanceof b function _instanceof(a, b) { while (a) { if (a.__proto__ === b.prototype) return true; a = a.__proto__; } return false; }
手写 jsonp 的实现
// foo 函数将会被调用 传入后台返回的数据 function foo(data) { console.log(‘通过jsonp获取后台数据:‘, data); document.getElementById(‘data‘).innerHTML = data; } /** * 通过手动创建一个 script 标签发送一个 get 请求 * 并利用浏览器对 <script> 不进行跨域限制的特性绕过跨域问题 */ (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‘; // 设置请求地址 head.appendChild(js); // 这一步会发送请求 })(); // 后台代码 // 因为是通过 script 标签调用的 后台返回的相当于一个 js 文件 // 根据前端传入的 callback 的函数名直接调用该函数 // 返回的是 ‘foo(3)‘ function testJSONP(callback, a, b) { return `${callback}(${a + b})`; }
ajax 的实现
感觉这个有点无聊了……
查看代码
// Asynchronous Javascript And XML function ajax(options) { // 选项 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.onstatechange = function() { /** readyState: 0: 请求未初始化 1: 服务器连接已建立 2: 请求已接收 3: 请求处理中 4: 请求已完成,且响应已就绪 status: HTTP 状态码 **/ 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(request.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‘ } })
reduce 的实现
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; }
实现 generator 的自动执行器
要求是 yield
后面只能是 Promise
或 Thunk
函数,详见 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 **/
节流
老生常谈了,感觉没必要写太复杂
/** * 节流函数 限制函数在指定时间段只能被调用一次 * 用法 比如防止用户连续执行一个耗时操作 对操作按钮点击函数进行节流处理 */ function throttle(func, wait) { let timer = null; return function(...args) { if (!timer) { func(...args); timer = setTimeout(() => { timer = null; }, wait); } } }
防抖
/** * 函数调用后不会被立即执行 之后连续 wait 时间段没有调用才会执行 * 用法 如处理用户输入 */ function debounce(func, wait) { let timer = null; return function(...args) { if (timer) clearTimeout(timer); // 如果在定时器未执行期间又被调用 该定时器将被清除 并重新等待 wait 秒 timer = setTimeout(() => { func(...args); }, wait); } }
手写 Promise
简单实现,基本功能都有了。
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 { // 回调是异步执行 函数是同步执行 executor(resolve, reject); } catch(err) { reject(err); } } MyPromise.prototype.then = function(onResolve, onReject) { let self = this; // 不传值的话默认是一个返回原值的函数 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); }) }
实现一个路由 - Hash
实现原理就是监听 url 的哈希值变化了
<!DOCTYPE html> <html> <head> <title>hash 路由</title> </head> <body> <header> <a href="#home">首页</a> <a href="#center">个人中心页</a> <a href="#help">帮助页</a> </header> <section id="content"></section> <script> window.addEventListener(‘hashchange‘, (e) => { let content = document.getElementById(‘content‘); content.innerText = location.hash; }) </script> </body> </html>
路由实现 - history
<!DOCTYPE html> <html> <head> <title>history 路由</title> </head> <body> <header> <a onclick="changeRoute(this)" data-path="home">首页</a> <a onclick="changeRoute(this)" data-path="center">个人中心页</a> <a onclick="changeRoute(this)" data-path="help">帮助页</a> </header> <section id="content"></section> <script> function changeRoute(route) { let path = route.dataset.path; /** * window.history.pushState(state, title, url) * state:一个与添加的记录相关联的状态对象,主要用于popstate事件。该事件触发时,该对象会传入回调函数。 * 也就是说,浏览器会将这个对象序列化以后保留在本地,重新载入这个页面的时候,可以拿到这个对象。 * 如果不需要这个对象,此处可以填 null。 * title:新页面的标题。但是,现在所有浏览器都忽视这个参数,所以这里可以填空字符串。 * url:新的网址,必须与当前页面处在同一个域。浏览器的地址栏将显示这个网址。 */ changePage(path); history.pushState({ content: path }, null, path); } /** * 调用 history.pushState() 或者 history.replaceState() 不会触发 popstate 事件。 * 点击后退、前进按钮、或者在 js 中调用 history.back()、history.forward()、history.go() 方法会触发 */ 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>
还有一些稍复杂的可以写,有时间再补。
作者:我不吃饼干呀
链接:https://juejin.im/post/5c9edb066fb9a05e267026dc
来源:掘金
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
原文地址:https://www.cnblogs.com/Antwan-Dmy/p/10714433.html
时间: 2024-10-02 20:25:37