奇舞学院学习笔记之JavaScript一页通
如何写好原生JavaScript
基础注意点
- JavaScript负责行为,改变状态,不是用来改变样式的。js:动态脚本语言。
- CSS负责样式
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>各司其职</title><style>body{background: white;font-size: 14px;}#user-list, #user-list1 {width: 200px;line-height: 1.5em;}#user-list > li:hover{background-color: rgba(0, 0, 0, 0.7);}#user-list > li.active{background-color: red;color: white;}#user-list1 input{display: none;}#user-list1 label{display: block;}#user-list1 > li:hover{background-color: rgba(0, 0, 0, 0.3);}#user-list1 input:checked+label{background-color: black;color: white;}</style>
</head>
<body>
<ul id="user-list"><li>赵</li><li>钱</li><li>孙</li><li>李</li>
</ul>
<ul id="user-list1"><li><input type="radio" name="items" id="item0" value="zhou"><label for="item0">zhou</label></li><li><input type="radio" name="items" id="item1" value="wu"><label for="item1">wu</label></li><li><input type="radio" name="items" id="item2" value="zheng"><label for="item2">zheng</label></li><li><input type="radio" name="items" id="item3" value="wang"><label for="item3">wang</label></li>
</ul><script>// 版本二let list = document.querySelector('#user-list');let items = list.querySelectorAll('li');list.addEventListener('click', function (e) {items.forEach(function (item) {item.className = '';});if(e.target.tagName === 'LI'){let item = e.target;item.className = 'active';console.log(item.innerHTML);}});// 版本三let list1 = document.querySelector('#user-list1');list1.addEventListener('click', function (e) {if(e.target.tagName === 'INPUT'){let checkedItem = list1.querySelector('input:checked');console.log(checkedItem.value);}});</script>
</body>
</html>
思考1:
- 写JavaScript操作DOM要注意什么?
- JavaScript与HTML、CSS的职责如何分离?
- 把复杂性放在哪一头,为什么?
思考2: API的设计?
<script>
// 版本一
// 问题:过程耦合 + Callback Hellconst traffic1 = document.getElementById('traffic1');(function reset() {traffic1.className = 'wait';setTimeout(function () {traffic1.className = 'stop';setTimeout(function () {traffic1.className = 'pass';setTimeout(reset, 2000);}, 2000)}, 2000);})();// 版本二
// 优点:着手于状态的改变
// 问题:依赖于外部变量 stateList,currentStateIndex,这两个变量应该封装起来,暴露出来。封装性不好const traffic2 = document.getElementById('traffic2');var stateList = ['wait', 'stop', 'pass'];var currentStateIndex = 0;setInterval(function () {traffic2.className = stateList[currentStateIndex];currentStateIndex = (currentStateIndex + 1) % stateList.length;}, 2000);// 版本三
// 问题:可复用性差const traffic3 = document.getElementById('traffic3');function start(traffic, stateList) {let currentStateIndex = 0;setInterval(function () {traffic3.className = stateList[currentStateIndex];currentStateIndex = (currentStateIndex+1) % stateList.length;}, 2000);}start(traffic3, ['wait','stop','pass']);// 版本四
// 过程抽象,函数式编程,抽象出 poll 方法const traffic4 = document.getElementById('traffic4');function poll(...fnList) {let stateIndex = 0;return function (...args) {let fn = fnList[stateIndex++ % fnList.length];return fn.apply(this, args);}}function setState4(state) {traffic4.className = state;}let trafficStatePoll = poll(setState.bind(null, 'wait'),setState4.bind(null, 'stop'),setState4.bind(null, 'pass'));setInterval(trafficStatePoll, 2000);// 版本五
// 优点:对等待时间抽象const traffic5 = document.getElementById('traffic5');function wait(time) {return new Promise(resolve => setTimeout(resolve, time));}function setState5(state) {traffic5.className = state;}function reset() {Promise.resolve().then(setState5.bind(null, 'wait')).then(wait.bind(null, 1000)).then(setState5.bind(null, 'stop')).then(wait.bind(null, 2000)).then(setState5.bind(null, 'pass')).then(wait.bind(null, 3000)).then(reset);}reset();// 版本六
// 形成一个协议
// 面向对象、函数式、Promise、灵活可扩展const traffic6 = document.getElementById('traffic6');function TrafficProtocol(el, reset) {this.subject = el;this.autoReset = reset;this.stateList = [];}TrafficProtocol.prototype.putState = function (fn) {this.stateList.push(fn);};TrafficProtocol.prototype.reset = function () {let subject = this.subject;this.statePromist = Promise.resolve();this.stateList.forEach((stateFn) => {this.statePromist = this.statePromist.then(()=>{return new Promise(resolve => {stateFn(subject, resolve);});});});if(this.autoReset){this.statePromist.then(this.reset.bind(this));}};TrafficProtocol.prototype.start = function () {this.reset();};var trafficE = new TrafficProtocol(traffic6, true);trafficE.putState(function (subject, next) {subject.className = 'wait';setTimeout(next, 1000);});trafficE.putState(function (subject, next) {subject.className = 'stop';setTimeout(next, 2000);});trafficE.putState(function (subject, next) {subject.className = 'pass';setTimeout(next, 3000);});trafficE.start();</script>
- 思考3: JavaScript的“效率”?
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>面试题:在一个数组中找和为10的数组对</title>
</head>
<body>
<script>// 版本一:两层循环 O(n^2)let list1 = [11,4,9,3,-1,-3,6,7,9,13];function map1(list){let ret = [], len = list.length;for(let i=0; i<len; i++){for(let j=i+1; j<len; j++){if(list[i]+list[j]===10){ret.push([list[i],list[j]])}}}return ret;}console.log(JSON.stringify(map1(list1)));// 版本二:先排序function map2() {let ret = [];list = list.sort((a,b)=>a-b);for(let i=0, j=list.length-1; i<j;){let a = list[i], b = list[j];if(a[i]+b[j]===10){ret.push([a,b]);i++;j--;}else if(a+b<10){i++;}else{j--;}}return ret;}console.log(JSON.stringify(map(list)));
</script>
</body>
</html>
- 小结
- 不应该用JS直接操作DOM
- API的设计,通用型,抽象度,可扩展性
- 程序要用合适的算法
JavaScript概览
JavaScript 简史
JavaScript 的特点
- 动态 + 弱类型
- 解释型或实时编译(JIT)型语言
- 面向对象
- 函数式特征
- 灵活和可扩展性
- 反射与元编程
- 高性能
- 单线程异步非阻塞
JavaScript 主要能做什么
- 通过DOM:改变网页文档元素和属性
- 通过BOM:操作浏览器API
- 事件机制:响应用户行为
- XHR、Fetch、WS:发送和接受数据
- Storage:保存数据和状态
- Timer、Promise:执行异步任务
- ArrayBuffer、TypedArray:处理数据
- File API:操作文件
JavaScript 系语言
谁在使用JavaScript
- 浏览器
- 服务端,如 node.js
- 硬件开发,如 树莓派
- 操作数据库,如mongoDB、CouchDB
- 写原生应用,如ReactNative
- 开发游戏,如COCOS
本博客主要讲什么
- 符合ECMA-262最新规范的JavaScript,不回避新特征
- 基本类型、原生类型、浏览器API、Node API(服务端)
- 大部分语言特性(特别是ESS及之前的版本在chrome40以上已完全支持)
- 重点讲JavaScript的独有特性及其应用场景,以实际工作常见和常用的为主。
- 重点讲函数、面向对象、过程抽象和函数式,总之能发挥JS动态特性的常见模式
- 会涉及到语言基础、运行环境(如浏览器环境、Node)
- 会涉及到部分后段、HTTP请求相关内容,这些内容对高端工程师高质量完成工作也是很有必要的
本博文不讲的内容
- 过时的不符合规范的特性,比如ES3和之前版本里被废弃和修正的东西
- 基础通用的编程语言特性,比如常见的基本if、for、while、switch语句
- 一些稍微不那么复杂、可以自学、工作中也会用到的内置类型,比如 Date
- 具体框架的使用,可以看文档
- 建议阅读 MDN文档
兼容性怎么办?
- 速查:速查JS兼容
- 方案1:shim & polyfill
- 方案2:library 实际项目里对于兼容IE8一下浏览器建议使用 jQuery
- 方案3:Bable/JSX/TypeScript
代码风格
- 代码的格式(包括缩进、大括号、分号、换行、空行、空格)
- 广义的:
- 目录结构和文件名
- 变量命名
- 文档规范
- 一起遵守规则:
- 2 spaces:两个空格
- Single quotes for strings:字符串用单引号
- No unused variables:不要有不使用的变量
- Semicolons:写分号
- Never start a line with
( [ '
- No space after keywords: if 和 括号 之间没有空格
- No space after function name:函数名和括号之间没有空格
- Always use
===
instead of==
:用三个等号判断
变量、值与类型
关于类型
关于JS类型的几点说明
- JS是 动态类型 + 弱类型 的语言
- JS的变量、属性在运行期间决定类型
- JS存在隐式类型转换
- JS有一系列识别类型的反射方法
ECMA的语言类型
typeof
- A function is a callable object
变量声明
根据规范,JS有三种变量声明的方法:
var
:声明一个变量,可选择将其初始化为一个值let
:声明一个块级作用域变量,可选择将其初始化为一个值。(ES6)const
:声明一个只读的常量.(ES5)
使用
var
的注意事项:var
不支持块级作用域var
存在变量提升(Variable hoisting)。变量提升作用域。如:var a=10;
相当于var a; a=10;
使用
let
的注意事项:- 块级作用域。出了块就是
undefined
。 - 同一作用域中不允许重复声明。
- 暂存死区(Temporal dead zone,TDZ)。在一个变量
a
声明之前使用该变量会报错ReferenceError:a is not defined
,不会有变量提升,且typeof(a)
为undefined
。 - 循环中的
let
作用域。let
有词法作用域。- 实例:
- 块级作用域。出了块就是
// 版本一// 会因变量提升而出问题var buttons = document.getElementsByTagName('button');for(var i=0; i<buttons.length; i++){buttons[i].onclick =evt => console.log('你点击了第' + i + '个按钮!')}// 版本二:利用let的块级作用域for(let i=0; i<buttons.length; i++){buttons[i].onclick =evt => console.log('你点击了第' + i + '个按钮!')}// 版本三:利用闭包的特性解决var buttons = document.querySelectorAll('button');for(var i=0; i<buttons.length; i++){(function (i) {buttons[i].onclick =evt => console.log('你点击了第' + i + '个按钮!');})(i);}
- 浏览器兼容性 。
- 使用
const
的注意事项const
声明的标识符所绑定的值不可以再次改变引用。但是还是可以修改对象里的内容,若想不允许修改可以使用Object.freeze({...})
。- ES6
const
的其他行为和let
一样
如果不声明会怎样?
- 严格模式:
use strict
。会报错ReferenceError: a is not defined
- 非严格模式:不会报错
抽象相等
- 严格相等与非严格相等
null == undefined
null !== undefined
- 非严格比较:会进行类型转换
number
里有个特殊的取值NaN
,NaN
与任何值(包括自身)都不想等
Boolean
类型
- 只有两个取值:
true
和false
。 0
、' '
、null
、undefined
被隐式地转换为false
,其他转为true
。- 建议采用严格比较,可以通过
!!
讲非boolean
值转为boolean
值。 - 布尔操作符
&&
和||
并不会转换类型(尤其注意!!) - 如:
&&
和||
的短路特性- 比较操作符总是返回
boolean
类型 Boolean
类型的运用:
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>小动画</title><style>div{width: 50px;height: 50px;background: red;border: 1px solid red;border-radius: 50%;}</style>
</head>
<body>
<div class="ball"></div>
<script>function applyAnimate(el, duration, options, easing) {var startTime = Date.now();if(typeof el === 'string'){el = document.querySelector(el);}duration = duration || 1000;options = options || {property: 'x',distance: 100};easing = easing || function(p){return p;};requestAnimationFrame(function update() {var now = Date.now();var p = (now - startTime)/duration;var ep = easing(p);if(typeof options !== 'function'){var attr = options.property, distance = options.distance;var translate = [];if(attr.indexOf('x') >= 0){translate.push('translateX(' + distance * ep + 'px)');}if(attr.indexOf('y') >= 0){translate.push('translateY(' + distance * ep + 'px)');}el.style.transform = translate.join(' ');}else{options(el, ep, p);}if(p <= 1){requestAnimationFrame(update);}});}document.querySelector('.ball').onclick = function () {applyAnimate('.ball');}
</script>
</body>
</html>
Number
类型
- 数值范围:
- 整数:-2^53 ~ 2^53
- 小数精度
Number.EPSILON
、Infinity
无穷大、Number.MAX_VALUE
、Number.MIN_VALUE
- 浮点数精度问题
- 二进制、八机制、十进制、十六进制
- +0 和 -0
String
- 引号规范。在JS中的字符串建议用单引号。
- 转义字符
- 字符串与字符
- 字符串可以拆成字符数组
var charArray = Array.from(str);
或var charArray = str.split('');
str.charCodeAt(4)
String.fromCharCode(116, 103)
- 字符串与类型转换
- -
- 常用字符串操作
- 字符串查找和替换:
str.indexOf(subStr)
- 字符串大小写:
str.toUpperCase();
,str.toLowerCase();
- 字符串连接:
str1+''+str2
- 截取子串:
str.slice(起始位置,结束位置);
str.substr(起始位置,长度);
- 逆序字符串:
str.split('').reverse.ioin('');
- 逆序字符串:
- 字符串匹配:
- 字符串查找和替换:
- 模版字符串
Object
- 对象的属性
- 属性名规则:可以是有效字符串或者任意可转换为有效字符串的类型
- 属性的访问和遍历
- 值和引用
- 值类型与引用类型
- 基本类型对应的包装类型(不带
new
的是值类型,带new
的是包装类型) - 对象的拷贝
- 类型与构造器
new
和constructor
prototype
原型链(一层层往上找某 属性)instanceOf
ES6 class
- 内置类型
Object
:根Function
:JS中最核心的Promise
:处理异步Array
:数组Date
:日期Regex
:正则表达式Error
Math
:数学ArrayBuffer
DataView
Map
:数据类型Set
:数据类型,用来去重TypedArray
:数据类型Proxy
- 对象的高级属性
- 为什么不建议修改
Object.protytype
和Array.prototype
呢?在类型(或对象)上添加方法的代价,会被所有的实例所继承下来。解决方法:Object.defineProperty
,不会被for in
检索出来,若想让其检索出来需要加enumerable:true;
。 getter
和setter
- 属性描述符
- 数据绑定视图
- 为什么不建议修改
class
(未)Symbol
(未)- ES6新特性
- 生成唯一表示
- 用作对象的key
Symbol.for
Symbol
的基本用法- 系统设置
Symbol
函数
函数声明、函数表达式
- 注意函数声明提升
- 实例:函数声明提升,变量声明提升,但是此时并未赋值
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>函数声明提升与赋值</title>
</head>
<body>
<script>console.log([typeof add, typeof sub]);function add(x, y) {return x+y;}var sub = function (x, y) {return x-y;};console.log([add(2,5), sub(2,6)]);
</script>
</body>
</html>
- 箭头函数表达式
- 实例:ES6新增:
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>箭头函数表达式</title>
</head>
<body>
<script>let double = x => x*2;let add = (x, y) => {return x + y;};console.log([double(12), add(3,7)]);
</script>
</body>
</html>
匿名函数
- 在函数表达式和回调函数中常见
- 匿名函数与
arguments.callee
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>匿名函数实现倒计时效果</title>
</head>
<body>
<script>function countDown(count, interval, callback) {if(count<=0) { return; }callback(count);setTimeout(function () {if(--count > 0){setTimeout(arguments.callee, interval);}callback(count);}, interval);}countDown(6, 1000, t => console.log('我是'+t));console.log('出发!');
</script>
</body>
</html>
函数参数
- 具名的参数,
function.length
是一个类数组的函数,但不是数组。 - 可变参数与
arguments
- ES6
rest
参数,是一个真正的数组。 - 参数默认值
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>可变参数与arguments</title>
</head>
<body>
<div style="width: 50px; height: 50px;">这里!!</div>
<p style="width: 50px; height: 50px;">这里!!</p><script>function add() {// var args = [].slice.call(arguments); 一种写法// var args = Array.prototype.slice.call(arguments); 一种写法// trueA = Array.from(FakeA) ==> 这个函数把伪数组FakeA 转换成数组 TrueA。let args = Array.from(arguments); // 一种写法return args.reduce((a,b) => a+b);}console.log(add(11,2,3,4));// javascript 函数设计中经常会让参数允许有不同的类型// el: element 给element的某个属性property赋值valuefunction setStyle(el, property, value) {if(typeof el === 'string'){el = document.querySelector(el);}if(typeof property === 'object'){for(var key in property){setStyle(el, key, property[key]);}}else{el.style[property] = value;}}console.log(setStyle.length);setStyle('div', 'background', 'red');setStyle('p', {'fontSize':'16px','backgroundColor':'blue'});// ES6:rest参数// ...args 这其实就是一个数组let add6 = (...args) => args.reduce((a,b) => a+b);console.log(add(1,2,3,4));console.log(add.length);function deepCopy(des, src) {if(!src || typeof src !== 'object'){return des;}for(var key in src){let obj = src[key];if(obj && typeof obj === 'object'){des[key] = des[key] || {};deepCopy(des[key], obj);}else{des[key] = src[key];}}return des;}function merge(des, ...objs) {return [des, ...objs].reduce((a,b) => deepCopy(a,b))}console.log('ES6 rest参数:' + JSON.stringify(merge({x:1}, {y:2}, {z:3})));</script>
</body>
</html>
作用域、闭包、this
- 重要:ES5用函数来构建作用域
- ES没有块级作用域
- IIFE:立即执行函数
什么是闭包
- 实例一
- 实例二
实例一:
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>闭包作用域</title>
</head>
<body>
<script>// 因为变量提升而导致所有时候:i=5for(var i=0; i<5; i++){setTimeout(function () {console.log(i);}, 100);}// 方法一: 闭包:立即执行函数for(var i=0; i<5; i++){(function (i) {setTimeout(function () {console.log(i);}, 500);})(i);}// 方法二: ES5 bind方法for(var i=0; i<5; i++){setTimeout((function (i) {console.log(i);}).bind(null, i), 1000);}// 方法三: ES6:块级作用域for(let i=0; i<5; i++){setTimeout(function () {console.log(i);}, 2000);}</script>
</body>
</html>
- 实例二:
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>闭包与私有数据</title>
</head>
<body>
<script>// 版本一var myClass = (function () {var privateData = 'privateData';function Class() {this.publicData = 'publicData';}Class.prototype.getData = function () {return privateData;};return Class;})();var myObj = new myClass();console.log([myObj.publicData, myObj.privateData, myObj.getData()]);// 版本二:ES6 块级作用域let Class2;{let privateD = 'privateD';Class2 = function () {this.publicD = 'publicD';};Class2.prototype.getD = function () {return privateD;};}var myO = new Class2();console.log([myO.publicD, myO.privateD, myO.getD()]);</script>
</body>
</html>
apply
、call
、bind
- JavaScript的
this
- JS的
this
是由函数求值时的调用者决定的
- JS的
apply
,call
,bind
- 通过
apply
,call
指定this
调用函数 - ES5的
bind
bind
的重要意义和高级用法
- 通过
- 实例:
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>call, apply, bind</title><style>body{transition: all 0.5s;}body.state1{background-color: red;}body.state2{background-color: lightskyblue;}</style>
</head>
<body>
<script>function add(x, y) {return x+y;}// callconsole.log(add.call(null, 1, 2));// applyconsole.log(add.apply(null, [3,4]));// bind 若将全部参数都传入,则延迟调用,会返回一个functionconsole.log(add.bind(null, 5, 6));// bind 部分调用let add1 = add.bind(null, 7);console.log(add1(8));function setBodyState(state) {document.body.className = state;}setBodyState.call(null, 'state1');setTimeout(setBodyState.bind(null, 'state2'), 1500);</script>
</body>
</html>
关于异步回调
- JS 的异步
- Timer
- 实例一
- 事件
- 获取数据API
Promise
- 其他异步模型
- 异步串行模型
through2--gulp
使用 - 异步串行模型
connect--express、koa
使用 - ES6
generators
- ES2015
async/wait
- 。。。
- 异步串行模型
- Timer
实例一:
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>用timer异步执行</title><style>#ball{display: inline-block;background-color: gray;width: 50px;height: 50px;border-radius: 50%;text-align: center;line-height: 50px;color: white;}#ball:hover{cursor: pointer;}#ball.warn{animation: 1s 7s blink linear 3 forwards normal;}@keyframes blink {0% {background: #FFFFFF;}50% {background: #f00;}100% {background: #FFFFFF;}}</style>
</head>
<body>
<div id="ball">1</div>
<script>const ball = document.getElementById('ball');ball.addEventListener('click', function () {var startTime = Date.now();var tId = setInterval(function () {var t = 10-Math.round((Date.now()-startTime)/1000);ball.innerHTML = Math.max(t, 0);if(t<=0){clearInterval(tId);}}, 1000);ball.className = 'warn';});
</script>
</body>
</html>
函数的动态构建
Function
构造器与函数模版- 过程抽象和高阶函数
- 过程抽象与函数式编程
- 过程抽象的定义
- 过程抽象与数据抽象的区别
- 过程抽象的定义
函数式编程
- 什么是函数式编程
函数式编程与前端代码有什么关系
- 函数的纯度和“提纯”
Uncurring
、Currying
&Partial Application
纯函数
- 定义:一个函数若输入参数确定则输出结果是唯一确定的,那么它就是纯函数。
- 好处:无状态、无副作用、幂等、无关时序。
- 过程抽象可以提升函数纯度
- 等价函数
- 可以实现拦截和监控
- 举例说明
- 过程抽象与函数式编程
- 函数异步化与串行执行
reduce
同步 &pipe
异步throttle
避免重复点击;debounce
避免重复点击multicast
批量操作DOM
元素阅读:
- 书:《计算机程序的构造和解释》
- JavaScript与函数式编程
- 函数式编程术语解析
- 什么是纯函数
- 函数式编程离我们还有多远
- 高阶函数对系统的“提纯”
如何封装好的函数
- 明确职责
- 限制副作用(尽量使用纯函数,限制操作DOM的函数的个数)
- 过程的优化
- 掌握抽象度
总结
- 函数的本质:封装过程,开放接口
- 理解过程抽象和函数式编程
- Tip:好的程序设计方式是面向接口编程,而不是面向实现编程
DOM & BOM
- DOM 文档树
DOM事件
- 事件流
- 默认行为
- 事件代理
DOM事件有两个阶段:
- Capture Phase:捕获阶段
- Bubbling Phase:冒泡阶段
实例一:事件流
- 实例二:组织默认行为–点击图片放大
- 实例三:事件代理
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>事件流</title><script src="../../../materials/jquery-3.1.1.js"></script><style>#outer{width: 200px;height: 200px;background-color: forestgreen;opacity: 0.7;display: flex;justify-content: center;align-items: center;}#inner{display: inline-block;width: 100px;height: 100px;background-color: #3df;opacity: 0.7;}#outer:hover, #inner:hover{opacity: 0.2;}</style>
</head>
<body>
<div id="outer"><div id="inner"></div>
</div>
<pre id="output">output:
</pre>
<script>const [outer, inner] = document.querySelectorAll('#outer', '#inner');const output = document.getElementById('output');function print(msg) {output.innerHTML += '\n' + msg;}[document.body, outer, inner].forEach(el=>{el.addEventListener('click', evt=>{let t = el.tagName, i = el.id;print(t + i + ' clicked!');}, false);})
</script>
</body>
</html>
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>点击放大图片</title><style>#fullview{position: absolute;left: 0;top: 0;width: 100%;height: 100%;background-color: rgba(0, 0, 0, 0.5);}#fullview.hide{display: none;}#fullview img{position: absolute;top: 50%;left: 50%;transform: translate(-50%, -50%);}#fullview>a{color: white;float: right;margin-right: 12px;font-size: 16px;cursor: pointer;text-decoration: none;}</style>
</head>
<body>
<div id="imgview"><a href="../../../images/pic/00.png"><img src="../../../images/pic/00.png" width="200px"></a>
</div>
<div id="fullview" class="hide"><img src="../../../images/pic/00.png" alt="">
</div>
<script>const imageView = document.getElementById('imgview');const fullView = document.getElementById('fullview');imageView.addEventListener('click', evt=>{evt.preventDefault();fullView.className = '';});fullView.addEventListener('click', evt=>{evt.target.className = 'hide';});
</script>
</body>
</html>
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>事件代理</title><style>button{font-size: 16px;}li{cursor: pointer;user-select: none;}li.selected{color: red;}</style>
</head>
<body>
<button>new</button>
<ul><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li><li>6</li>
</ul>
<script>const btn = document.querySelector('button');const list = document.querySelector('ul');const items = list.getElementsByTagName('li');btn.addEventListener('click', evt=>{let item = document.createElement('li');item.innerHTML = items.length+1;list.appendChild(item);});// 不推荐这种做法,因为无法给新增的li添加事件
// Array.from(items).forEach(item =>{// item.addEventListener('click', evt=>{// evt.target.className = evt.target.className?'':'selected';
// });
// });// 推荐做法list.addEventListener('click', evt=>{let el = evt.target;if(el.tagName === 'LI'){el.className = el.className?'':'selected';}});</script>
</body>
</html>
宽高和定位
clientWidth
、clientHeight
:内容的容器内可见宽高offsetWidth
、offsetHeight
:内容的盒子(不包括margin)宽高scrollWidth
、scrollHeight
:内容真正的宽高- 实例:
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>宽高和定位</title><style>html, body {margin: 0;padding: 0;}p {margin: 0;padding: 0;}#outer {display: inline-block;width: 200px;height: 200px;margin: 10px;background: gray;text-align: center;border: 5px solid lightseagreen;}#inner {display: inline-block;width: 100px;height: 100%;background: lightcoral;overflow: scroll;border: 5px solid lightseagreen;}</style>
</head>
<body>
<p id="atext">This is a paragraph</p>
<div id="outer"><div id="inner"><p>aaa</p><p>aaa</p><p>aaa</p><p>aaa</p><p>aaa</p><p>aaa</p><p>aaa</p><p>aaa</p><p>aaa</p><p>aaa</p><p>aaa</p><p>aaa</p><p>aaa</p><p>aaa</p><p>aaa</p><p>aaa</p><p>aaa</p></div>
</div>
<script>setTimeout(function(){// 无法获取继承的值const p = document.getElementById('atext');console.log('width' + 'height' +JSON.stringify([p.style.width, p.style.height]));// 通过getComputedStyleconst styleP = window.getComputedStyle(p);console.log('width' + 'height' + JSON.stringify([styleP.width, styleP.height]));console.log('clientWidth ' + 'clientHeight ' + JSON.stringify([p.clientWidth, p.clientHeight]));console.log('offsetWidth ' + 'offsetHeight ' + JSON.stringify([p.offsetWidth, p.offsetHeight]));console.log('scrollWidth ' + 'scrollHeight ' + JSON.stringify([p.scrollWidth, p.scrollHeight]));console.log('---------');console.log('clientWidth ' + 'clientHeight ' + JSON.stringify([outer.clientWidth, outer.clientHeight]));console.log('offsetWidth ' + 'offsetHeight ' + JSON.stringify([outer.offsetWidth, outer.offsetHeight]));console.log('scrollWidth ' + 'scrollHeight ' + JSON.stringify([outer.scrollWidth, outer.scrollHeight]));console.log('---------');console.log('clientWidth ' + 'clientHeight ' + JSON.stringify([inner.clientWidth, inner.clientHeight]));console.log('offsetWidth ' + 'offsetHeight ' + JSON.stringify([inner.offsetWidth, inner.offsetHeight]));console.log('scrollWidth ' + 'scrollHeight ' + JSON.stringify([inner.scrollWidth, inner.scrollHeight]));}, 100);</script>
</body>
</html>
- UI组件设计
- 结构设计
- API设计
- 控制流设计
- 实例:图片轮播
- 图片轮播
- -
动画基础(上)
动画基础(下)
服务器与HTTP基础
常用设计模式和组件开发
浅谈前端工程化
奇舞学院学习笔记之JavaScript一页通相关推荐
- 奇舞学院学习笔记之CSS一页通
CSS概念与简单选择器 版本 CSS Level 1 CSS Level 2(CSS2.1规范) CSS Level 3 Color Module Level 3 Selectors Level 3 ...
- 尚硅谷谷粒学院学习笔记(防坑点的总结部分勘误)
谷粒学院学习笔记 部分勘误 数据库设计规约 模块说明 环境搭建 创建一个Spring Boot 的父工程,版本使用:2.2.1.RELEASE 父工程pom.xml里面添加 在pom.xml中添加依赖 ...
- 【百度前端学院学习笔记】Day6 浮动/BFC
[百度前端学院学习笔记]Day6 浮动/BFC 一.什么是浮动? 二.普通流 / 浮动 / 绝对定位 三.BFC/Flow Root 3.1 什么是BFC? 3.2 BFC 的特性 3.2.1 特性一 ...
- 【百度前端学院学习笔记】Day9 圣杯布局和双飞翼布局
[百度前端学院学习笔记]Day9 圣杯布局和双飞翼布局 圣杯布局(古老而费解的方法) 双飞翼布局(圣杯的改进) 参考资料: In search of the Holy Grail - A list a ...
- GEE(Google Earth Engine) 最基础代码学习笔记二 —— JavaScript 语言
GEE(Google Earth Engine) 学习笔记二 Javascript 语言 1. 注释 print('Hello World!'); 如果要注释,则在代码前面加//,比如: // pri ...
- Windows保护模式学习笔记(八)—— 页目录表基址/页表基址
Windows保护模式学习笔记(八)-- 页目录表基址/页表基址 要点回顾 一.页目录表基址 实验:拆分线性地址C0300000,并查看其对应的物理页 第一步:打开一个进程,获得它的Cr3 第二步:查 ...
- 奇舞学院JavaScript视频-如何写好原生js
月影JavaScript视频学习笔记 第零课 Q1: 列表渲染的不同版本 优劣 版本1(初级前端) let list = document.querySelector('#user-list'); l ...
- 前端学习笔记之 JavaScript WebAPIs(整理)
目录 篇一 一.鼠标事件 二.获取元素的属性值 三.设置元素的属性值 四.移除属性 五.H5自定义属性 1. 设置自定义属性 2. 获取自定义属性 六.节点操作 1.两种方法的区别 2.节点概述 3 ...
- 【前端学习笔记】JavaScript + jQuery + Vue.js + Element-UI
前端学习笔记 JavaScript jQuery Vue.js Element-UI Java 后端部分的笔记:Java 后端笔记 JavaScript 基础语法(数据类型.字符串.数组.对象.Map ...
最新文章
- 【干货】裸金属服务Ironic项目介绍
- git中Please enter a commit message to explain why this merge is necessary.
- 京东AI一把手周伯文被曝离职创业,曾任技术委员会主席,毕业于中科大少年班...
- C# 入门经典 第三版 下载。
- 7.7-9 chage、chpasswd、su
- 蓝桥杯 平面切分(欧拉定理)
- 组态王怎么做超级曲线_鸭肉怎么做?大叔教你红烧鸭块,香气扑鼻,简单易做,超级好吃...
- Android 为应用添加默认加载页
- java 发送带basic认证的http post请求实例代码_图解HTTP学习笔记(八)—确认访问用户身份的认证...
- 输入控件控制输入限制
- 一起谈.NET技术,Microsoft NLayerApp案例理论与实践 - 多层架构与应用系统设计原则...
- SAP ABAP开发从入门到精通——第15章 面向对象ALV
- linux修改无线网卡hwaddr,在Linux下改无线网卡的mac的地址
- java version什么意思_输入java -version命令后提示结果如下,是什么意思??哪位能看懂,在线等。。。。...
- 重磅:Mobileye官宣推迟IPO,营收增速放缓、市场竞争加剧
- 0x5085170C (ucrtbased.dll)处(位于 Project1.exe 中)引发的异常: 0xC0000005: 读取位置 0x0000001A 时发生访问冲突。
- RabbitMQ - 4种Exchange类型
- Markdown设置字体大小、颜色、类型、加粗
- Spring - bean
- Linux ps命令详解,Linux查看进程
热门文章
- [note] 拉-曼-Raman spectra
- android 适配最佳方案,android适配方案
- Intellij Idea 快捷键设置大全
- C++学习记录之STL函数
- MySQL的50条经典语句(更新中...
- 旭凤锦覓虐心 恋只愿共赴鸿蒙,《香蜜》原著锦觅和旭凤的“虐恋情深”:细想,他们的爱情,不美...
- 查看Linux操作系统版本及内核版本
- H.264裸流文件中获取每一帧数据
- PXE+VMware主机模式+KickStart脚本 自动安装ESXi 并试用WireShark抓包分析其中的协议TFTP,DHCP
- 滴滴杜欢:大型微服务框架设计实践