JavaScript 是一门基于对象
和事件驱动
的弱类型
脚本语言
机器语言
汇编语言
高级语言
脚本语言
动态语言
相较于编译语言
,不需要编译器
,它需要的是解释器
编译器面向的是计算机
解释器面向的是某个特定的软件或者计算机某一个部分
HTML 结构
CSS 美化
JavaScript 行为
浏览器内核
渲染引擎
JS引擎越来越独立,内核就倾向于只指渲染引擎
JS 引擎
解析和执行 javascript 来实现网页的动态效果
组成
ECMAScript
ECMA262 标准
JS语法和基本对象
JS-Web-API W3C 标准
DOM
文档对象模型
BOM
浏览器对象模型
事件绑定
Ajax
存储
引用方式 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 <a onclick ="alert('Hello World!')" id ="fuck" href ="javascript:void(0);" > Hello World! </a > <script type ="text/javascript" > const elem = document .getElementById ('fuck' ) elem.onclick = function ( ) {} elem.addEventListener ('click' , function ( ) {}, false ) elem.addEventListener ('keyup' , function ( ) {}, false ) </script > <script src ="main.js" type ="text/javascript" > </script >
变量命名
不允许数字开头
不允许使用关键字和保留字
使用字母,数字,下划线(_),美元符($)任意组合而成
属性操作
常用属性
id
className
value
style
width
height
color
fontSize
background
cssText
…
innerText
innerHTML
href
src
tagName
classList
add()
remove()
contains()
toggle()
href 值和 src 值获取到的是绝对路径
style 是行间属性
cssText 会替换掉当前所有的行间属性
class 是保留字,改成 className
tagName 获取到的是大写字母
属性中不允许出现-
,font-size 改成 fontSize
数据类型
基本类型 string number boolean null undefined symbol
复杂类型 object
传址
引用类型
浅拷贝
Array.prototype.slice
Object.assign()
...
展开运算符
深拷贝
储存在内存堆
中 树形结构
typeof 运算符 function object string number boolean undefined symbol bigint
typeof
只能检测出普通变量类型, 除function
外, 都是object
了
typeof + instanceof
1 2 3 4 5 6 7 8 9 10 typeof 'abc' typeof 123 typeof true typeof {} typeof [] typeof null typeof undefined typeof console .log typeof Symbol () typeof 1n
强制数据类型转换
String()
数字类型 返回对应的字符串数字
布尔值 返回字符串 true/false
null 返回字符串 null
undefined 返回字符串 undefined
数组 [1, 2, , 3, [4, [5]], { a: ‘b’ }]
‘1,2,,3,4,5,[object Object]’
函数 把整个函数变成字符串返回
对象 调用对象的 toString 方法 ‘[object Object]’
Number()
Boolean()
👈👈
运算符 数学运算符 +加、-减、*乘、/除、%取模、++递增、--递减、+正号、-负号
加性操作符
+
加法
当左右两侧的操作数,任何一侧为字符串,另一侧非字符串的类型则会转为字符串,进行字符串的拼接
当左右两侧都为 Number 类型的情况下,按照如下规则返回结果:
左右两侧均为数值,执行常规的加法计算
如果有一个操作数是 NaN,则结果返回 NaN
如果操作数是 Boolean、null、undefined,则会(根据对应的规则 Number())转为数字类型,再进行计算
4 + [1, 2, 3] 👉 ‘41,2,3’
-
减法
乘性操作符
一元操作符 只能操作一个值的操作符叫做一元操作符
+
一元加运算符
如果操作数是 Number 类型的时候,正号
放在数值前面,对其完全没有任何影响
如果操作数是 String、Boolean、null、undefined,则会(根据对应的规则 Number())转为数字类型
-
一元减运算符
递增、递减运算符
浮点数精度问题 1 2 console .log (0.1 + 0.2 ) console .log ((0.1 * 10 + 0.2 * 10 ) / 10 )
赋值运算符 =等号、+=加等、-=减等、*=乘等、/=除等、%=模等
比较运算符 关系操作符 <小于、>大于、<=小于等于、>= 大于等于
相等操作符 ==相等、!=不等、===全等、!==全不等
=== 全等比较
数据类型
值
== 隐式类型转换
如果两边都是 String 类型,比较Unicode
编码
如果两边都是 Number 类型,比较数值是否相同
null == undefined
如果有一侧是 NaN,则结果得到 false
NaN 不等于任何类型的数值,包括自己本身NaN != NaN
如果一侧是 String、Boolean、null、undefined、Object,则会(根据对应的规则 Number())转为数字类型,再进行比较
何时使用 == 何时使用 ===
1 2 3 4 5 6 7 if (obj.a == null ) { 其它情况使用尽量都使用 === }
逻辑运算符 短路
非 作用在一个条件上,所以也是一元运算符
的成员之一,表示对该操作数进行取反操作,会对该数据进行隐式类型转换
为布尔值
如果操作数是非空字符串
,返回 !true
如果操作数是字符串0
,返回 !true
如果操作数是数字0
,返回 !false
如果操作数是 NaN,返回 !false
如果操作数是 null 或 undefined,返回 !false
如果操作数是 Object 类型,返回 !true
所有对象均为 true,包括 空数组 []、空对象 {}
[] == false
!!a
等同于Boolean(a)
流程控制 顺序结构 if 分支 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 if () {} else if () { } else { } switch (表达式/变量) { case value1 : break case value2 : break default : break } switch (true ) { case score >= 90 && score <= 100 : console .log ('优秀' ) break case score >= 60 && score < 90 : console .log ('良好' ) break case score < 60 && score >= 0 : console .log ('不及格' ) break default : console .log ('whoops!' ) break }
for 循环 1 2 3 4 5 6 7 8 9 10 11 12 for (let i = 0 ; index <= 9 ; i++) {} while () {} do {} while ()
break
终止当前循环,包括 break 后面的代码也会被停止执行,并且跳出该循环
continue
终止当前循环,包括 break 后面的代码也会被停止执行,并进入下次循环
万物皆“对象”
内置函数
String Number Boolean Symbol Array Object Function Date RegExp Error
内置对象
Math JSON
String 字符串 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 charAt (i) charCodeAt (i) String .fromCharCode (25105 , 29233 , 20320 ) indexOf (searchValue[, fromIndex]) lastIndexOf () function indexOf (str, searchValue, fromIndex = 0 ) { let i = fromIndex < 0 ? 0 : fromIndex, index = -1 for (; i < str.length ; i++) { if (str.charAt (i) === searchValue) { index = i break } } return index } slice (start[, end]) substr (start[, length]) substring (start[, end]) split (separator[, limit]) trim ()includes (searchValue[, fromIndex])'abc' .startsWith ('a' ) 'abc' .endsWith ('c' ) toLowerCase () toUpperCase () 'a' .repeat (3 ) 'a' .concat ('b' , 'c' )
Number 数字 1 2 3 let number = 123 number.toFixed (2 )
Array 数组 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 Array .from () Array .of ('a' , 'b' , 'c' ) Array .isArray () push () pop () unshift () shift () slice (start[, end]) splice (start[, num, item1, item2, ...]) join (separator = ',' ) reverse () concat (arr1, arr2, ...) indexOf (searchValue[, fromIndex])lastIndexOf ()includes (searchValue[, fromIndex])sort ((a, b ) => { return a - b return b - a return Math .random () - 0.5 }) ['B' , 'a' , 'C' , 'c' , 'b' , 'A' ].sort ((a, b ) => { a = a.toLowerCase () b = b.toLowerCase () if (a >= b) { return 1 } else { return -1 } }) forEach (function (item, index, arr ) {}, bindThis)filter (function (item, index, arr ) {}, bindThis)map (function (item, index, arr ) {}, bindThis)flatMap (function (item, index, arr ) {}, bindThis)reduce (function (total, item, index, arr ) { return total + item }, initialValue) some (function (item, index, arr ) {}, bindThis)every (function (item, index, arr ) {}, bindThis)find (function (item, index, arr ) {}, bindThis)findIndex (function (item, index, arr ) {}, bindThis)flat (depth)
Object 对象 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 keys ()values ()delete obj.key Object .create ()Object .assign ()Object .freeze ()Object .isFrozen ()Object .is (+0 , -0 ) Object .is (NaN , NaN ) new Set ([...document .querySelectorAll ('*' )].map (item => item.tagName )).size [...document .querySelectorAll ('*' )].map (item => item.tagName ).reduce ((res, item ) => { res[item] = (res[item] || 0 ) + 1 return res }, {}) Object .entries ( [...document .querySelectorAll ('*' )].map (item => item.tagName ).reduce ((res, item ) => { res[item] = (res[item] || 0 ) + 1 return res }, {}) ).sort ((a, b ) => b[1 ] - a[1 ]).slice (0 , 3 )
Date 日期时间 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 typeof Date () let date = new Date () let year = date.getFullYear ()let month = date.getMonth () + 1 let day = date.getDate ()let week = date.getDay ()let hour = date.getHours ()let minute = date.getMinutes ()let second = date.getSeconds ()let milliSecond = date.getMilliseconds ()let currentMilliSecond = date.getTime () new Date (1000 ) new Date (-1000 ) new Date ('2023-01-02 00:02:01:999' ) new Date (2023 , 00 , 02 , 00 , 01 , 61 , 999 )
Math 数学 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 Math .PI Math .min ()Math .max ()Math .ceil () Math .floor () Math .round () Math .abs () Math .random ()Math .floor (Math .random () * (m - n + 1 ) + n) Math .ceil (Math .random () * (m - n) + n) Math .round (Math .random () * (m - n) + n) let random = Math .random ()random = random + '0000000000' random = random.slice (0 , 10 )
JSON 1 2 JSON .parse ()JSON .stringify ()
全局属性
全局函数
encodeURI() 👈
不会对 ASCII 字母、数字、-_.!~*'()
、;,/?:@&=+$#
编码
decodeURI()
encodeURIComponent()
不会对 ASCII 字母、数字、-_.!~*'()
编码 会对;,/?:@&=+$#
这些用于分隔 URI 组件的 ASCII 标点符号编码
decodeURIComponent()
非转义字符
ASCII字母(a-zA-Z)
十进制数字(0-9)
uri标记符 -_.!~*’
括号 ()
保留字符
特殊字符
其他
总结:
encodeURI 只对 4.其它
编码
encodeURIComponent 除了非转义字符(保留字符、特殊字符、其它)
escape()废弃
编码普通字符串
unescape()废弃
解码普通字符串
isFinite()
isNaN()
eval()
requestAnimationFrame 动画帧
requestAnimationFrame 会把每一帧中的所有 DOM 操作集中起来, 在一次重排重绘
中就完成, 与计算机系统重绘频率保持一致
屏幕画面的渲染帧频一般是60Hz/s
, 相当于每秒重绘60次
在隐藏或不可见的元素
中, requestAnimationFrame 将不会进行重排重绘
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 function moveScroll (target = 0 ) { cancelAnimationFrame (window .scrollTimer ) window .scrollTimer = requestAnimationFrame (move) function move ( ) { let nowScroll = window .scrollY if (Math .abs (target - nowScroll) < 2 ) { window .scrollTo (0 , target) } else { let speed = (target - nowScroll) / 20 window .scrollTo (0 , nowScroll + speed) window .scrollTimer = requestAnimationFrame (move) } } } if (!window .requestAnimationFrame ) { let lastTime = 0 window .requestAnimationFrame = function (callback ) { const now = new Date ().getTime () const nextTime = Math .max (lastTime + 16.7 , now) return window .setTimeout (function ( ) { lastTime = nextTime callback () }, nextTime - now) } } if (!window .cancelAnimationFrame ) { window .cancelAnimationFrame = clearTimeout }
DOM 文档对象模型
针对HTML文档的一个应用程序编程接口
是 JS 和 HTML 的桥梁
DOM 关系
childNodes 子节点
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 elem.childNodes .forEach (item => { console .log (item.nodeType , item.nodeName ) }) class Node {}class Document extends Node {}class DocumentFragment extends Node {}class CharacterData extends Node {}class Text extends CharacterData {}class Comment extends CharacterData {}class Element extends Node {}class HTMLElement extends Element {}class HTMLDivElement extends HTMLElement {}class HTMLInputElement extends HTMLElement {}
firstChild 第 0 个子节点
firstElementChild
第 0 个子元素
lastChild 最后一个子节点
nextSibling 下一个兄弟节点
nextElementSibling
下一个兄弟元素
previousSibling 上一个兄弟节点
previousElementSibling
上一个兄弟元素
parentNode 父节点
节点操作 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 let frag = document .createDocumentFragment ()let osList = ['mac' , 'win' , 'linux' ]for (let i = 0 , len = osList.length ; i < len; i++) { let li = document .createElement ('li' ) let liText = document .createTextNode (osList[i]) li.appendChild (liText) frag.appendChild (li) } ul.appendChild (frag) document .getElementById ('id' )document .getElementsByName ('name' )document .getElementsByClassName ('class' )document .getElementsByTagName ('div' )document .querySelector ('selector' )document .querySelectorAll ('selector' )document .createElement ('div' )document .createTextNode ('文本' )parentEl.appendChild (node) parentEl.insertBefore (node, existNode) parentEl.replaceChild (node, oldNode) parentEl.removeChild (node) node.remove () node.cloneNode (!false )
属性操作 1 2 3 4 5 6 7 8 9 elem.attributes elem.getAttribute ('class' ) elem.setAttribute ('class' , 'className' ) elem.removeAttribute ('class' ) elem.hasAttribute ('class' ) elem.dataset .key = 'value'
属性property
(各种数据类型) 特性attribute
(字符串)
公认的 特性attribute 会映射到 属性property 属性是node节点
, 特性会显示到html结构
上
elem.className
elem.getAttribute(‘class’)
elem.getAttributeNode(‘class’).nodeValue
1 2 3 4 5 6 7 8 9 let className = oDiv.getAttributeNode ('class' ).nodeValue let attr = oDiv.getAttributeNode ('class' )if (!attr) { attr = document .createAttribute ('class' ) oDiv.setAttributeNode (attr) } attr.nodeValue = 'className'
长度宽度 强制渲染 触发回流
offset client scroll 相关属性
width height
getComputedStyle()
getBoundingClientRect()
offset
client
clientWidthwidth+padding 不含滚动条
clientHeightheight+padding 不含滚动条
clientTop 上边框宽度
clientLeft 左边框宽度
scrollWidth无滚动条 则和 client 一样
scrollHeight
scrollTop 上下滚动距离
scrollLeft 左右滚动距离
scrollIntoView
getBoundingClientRect()
left 元素左侧距离可视区左侧距离
top 元素顶部距离可视区顶部距离
right 元素右侧距离可视区左侧距离
bottom 元素底部距离可视区顶部距离
widthwidth+padding+border
heightwidth+padding+border
兼容性问题: IE 会多出 2px
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 function getPageOffset (elem ) { let elRect = elem.getBoundingClientRect () let scrollL = window .scrollX let scrollT = window .scrollY return { left : scrollL + elRect.left , top : scrollT + elRect.top } } function rectCollisionDetect (elem, elem2 ) { let elRect = elem.getBoundingClientRect () let el2Rect = ele2.getBoundingClientRect () if ( elRect.right < el2Rect.left || el2Rect.right < elRect.left || elRect.bottom < el2Rect.top || el2Rect.bottom < elRect.top ) { console .log ("矩形碰撞检测: 没有碰撞" ) } } function circleCollisionDetect (elem, elem2 ) { let elRect = elem.getBoundingClientRect () let elCenter = { x : elRect.left + elRect.width / 2 , y : elRect.top + elRect.width / 2 } let el2Rect = ele2.getBoundingClientRect () let el2Center = { x : el2Rect.left + el2Rect.width / 2 , y : el2Rect.top + el2Rect.width / 2 } let dis = (elCenter.x - el2Center.x ) * (elCenter.x - el2Center.x ) + (elCenter.y - el2Center.y ) * (elCenter.y - el2Center.y ) dis = Math .sqrt (dis) return dis <= elRect.width / 2 + el2Rect.width / 2 }
NodeList Node 静态集合
但并不都是静态的
childNodes动态
querySelectorAll静态
可以使用 forEach
HTMLCollection Element 动态集合
children
getElementsByName getElementsByTagName getElementsByClassName
没有 forEach 方法, 使用 for 循环
for 和 forEach 哪个更快? for 更快
for 直接在当前函数中执行,forEach 每次都要新创建一个函数
函数有单独的作用域和上下文,所以耗时更久
开发中不仅要考虑性能,还要考虑代码的可读性,forEach 可读性更好
tBodies rows cells tHead tFoot
BOM 浏览器对象模型 window 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 window .innerWidth `包含滚动条` window .innerHeight document .documentElement .clientHeight `不含滚动条` document .documentElement .offsetHeight document .documentElement .scrollHeight document .body scrollX / pageXOffset scrollY / pageYOffset scrollTo (x, y )document .documentElement .scrollTop document .documentElement .offsetLeft document .documentElement .clientTop let clientHeight = document .documentElement .clientHeight let offsetHeight = document .body .offsetHeight let scrollTop = document .documentElement .scrollTop let distance = 100 if ((clientHeight + scrollTop) >= (offsetHeight - distance)) { loadMore () }
screen 屏幕信息 1 2 3 window .screen .width window .screen .height
location 地址栏信息 1 2 3 4 5 window .location document .location window .onhashchange = () => {}
history 历史记录
state
pushState(state, title[, url])
replaceState
navigator 浏览器信息
事件绑定 elem.onclick = fn
elem.onclick = null
事件绑定
添加多个事件会被后面覆盖事件监听
可以添加多个事件处理函数
事件监听 elem.addEventListener(type, listener[, options|useCapture])
elem.removeEventListener(type, listener[, options|useCapture])
可选参数
options<Object>
capture<Boolean>
once<Boolean>
passive<Boolean>
表示永远不会调用 preventDefault; 如果 listener 仍然调用, 客户端将会忽略它并抛出一个控制台警告
useCapture<Boolean> 默认 false 冒泡
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 class BindEvent { constructor (elem ) { this .elem = elem } addEventListener (type, handler ) { const elem = this .elem if (elem.addEventListener ) { elem.addEventListener (type, handler, false ) } else if (elem.attachEvent ) { elem.attachEvent (`on${type} ` , (e ) => { e = BindEvent .fixEvent (e) handler.call (elem, e) }) } else { elem[`on${type} ` ] = () => { const e = BindEvent .fixEvent (window .event ) handler.call (elem, e) } } } removeEventListener (type, handler ) { const elem = this .elem if (removeEventListener) { elem.removeEventListener (type, handler, false ) } else if (attachEvent) { elem.detachEvent (`on${type} ` , handler) } else { elem[`on${type} ` ] = null } } static stopPropagation (e ) { if (e.stopPropagation ) { e.stopPropagation () } else { e.cancelBubble = true } } static stopImmediatePropagation (e ) { if (e.stopImmediatePropagation ) { e.stopImmediatePropagation () } } static preventDefault (e ) { if (e.preventDefault ) { e.preventDefault () } else { e.returnValue = true } } static fixEvent (e ) { e.target = e.target || e.srcElement e.currentTarget e.preventDefault = e.preventDefault || function ( ) { e.returnValue = false } e.stopPropagation = e.stopPropagation || function ( ) { e.cancelBubble = true } e.charCode = typeof e.charCode === 'number' ? e.charCode : e.keyCode return e } }
事件流 DOM2级事件流
事件捕获capture(先父后子👎) -> 处于目标target -> 事件冒泡bubbling(先子后父👍)
自定义事件 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 const longTap = new Event ('longTap' , { bubbles : true , cancelable : false }) let timer = 0 elem.addEventListener ('mousedown' , () => { clearTimeout (timer) timer = setTimeout (() => { elem.dispatchEvent (longTap) }, 750 ) }) elem.addEventListener ('mouseup' , () => { clearTimeout (timer) }) document .addEventListener ('longTap' , (e ) => { if (e.target === elem) { console .log ('自定义事件' ) } }, false )
鼠标事件 1 2 3 4 5 6 7 8 elem.addEventListener ('mousedown' , (e ) => { document .addEventListener ('mousemove' , moveFn) document .addEventListener ('mouseup' , () => { document .removeEventListener ('mousemove' , moveFn) }, { once : true }) e.preventDefault () })
mouseenter mouseleave👍
mouseover mouseout👎
键盘事件 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 elem.addEventListener ('keydown' , (e ) => { if (e.keyCode === 13 && e.ctrlKey ) { } }) let lastCode = '' elem.addEventListener ('keydown' , (e ) => { if ((e.keyCode === 38 && lastCode === 40 ) || (e.keyCode === 40 && lastCode === 38 )) { } else { lastCode = e.keyCode } }) elem.addEventListener ('keyup' , () => { lastCode = '' })
移动端事件 touch 事件 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 document .addEventListener ('touchstart' , (e ) => { e.preventDefault () }) document .addEventListener ('touchmove' , (e ) => { e.preventDefault () })
点击穿透 在移动端中,当触发一个事件时,JS 会记录当前触发的坐标,300ms
之后,在该坐标查找元素,如果元素有鼠标事件 ,就把该鼠标事件执行了鼠标事件的执行在移动端会有 300ms 左右的延迟
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 <style > #box { position : absolute; left : 0 ; top : 0 ; width : 100px ; height : 100px ; background : rgba (255 , 0 , 0 , .3 ); } </style > <a href ="https://www.5207.fun/" > 点击穿透</a > <div id ="box" > </div > <script > { let box = document .querySelector ('#box' ) box.addEventListener ('touchend' , (e ) => { box.style .display = 'none' }) document .addEventListener ('touchend' , (e ) => { e.preventDefault () }, { passive : false }) } </script >
原因:双击缩放(double tap to zoom)网页
1 2 3 4 window .addEventListener ('load' , function ( ) { FastClick .attach ( document .body ) }, false )
1 2 <meta name ="viewport" content ="width=device-width" />
touchEvent
touches 屏幕中的手指列表
targetTouches 元素上的手指列表
changedTouches
触发事件的手指列表
1 2 3 elem.addEventListener ('touchmove' , (e ) => { console .log (e.touches .length ) })
禁止缩放 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 document .documentElement .addEventListener ( 'touchstart' , function (event ) { if (event.touches .length > 1 ) { event.preventDefault () } }, false ) document .addEventListener ('gesturestart' , function (event ) { event.preventDefault () }, false ) var lastTouchEnd = 0 document .documentElement .addEventListener ( 'touchend' , function (event ) { var now = Date .now () if (now - lastTouchEnd <= 300 ) { event.preventDefault () } lastTouchEnd = now }, false )
orientation 横竖屏切换 1 2 3 4 5 6 7 8 9 10 11 12 window .addEventListener ('orientationchange' , () => { switch (orientation) { case 0 : case 180 : console .log ('竖屏' ) break ; case -90 : case 90 : console .log ('横屏' ) break ; } })
devicemotion 加速度 1 2 3 4 5 6 7 8 9 10 window .addEventListener ('devicemotion' , (e ) => { const acceleration = e.acceleration const accelerationIncludingGravity = e.accelerationIncludingGravity console .log (accelerationIncludingGravity.x - acceleration.x ) })
手机摇一摇 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 const MAX_RANGE = 60 const MIN_RANGE = 5 let lastX = 0 let lastY = 0 let lastZ = 0 let isShake = false window .addEventListener ('devicemotion' , throttle ((e ) => { let motion = e.acceleration let x = motion.x let y = motion.y let z = motion.z let range = Math .abs (x - lastX) + Math .abs (y - lastY) + Math .abs (z - lastZ) if (range >= MAX_RANGE ) { isShake = true } if (range <= MIN_RANGE && isShake) { isShake = false } lastX = x lastY = y lastZ = z }))
deviceorientation 倾斜角度
元素拖拽
draggable
设置元素为可拖放
给默认可拖拽的元素(选中的文本、链接、图像)设置 draggable 为 false, 可以阻止拖拽
firefox浏览器
如果拖放的元素没有设置拖放内容 dataTransfer.setData() 还是不能拖放
dataTransfer.setData() 设置拖拽时传递的信息
dataTransfer.getData() 获取拖拽时传递的信息
相关事件
ondragstart 拖动开始时触发
ondrag 拖动过程中触发
ondragend 拖动结束时触发
---------------------------------
ondragenter 拖动元素进入放置目标时触发
ondragleave 拖动元素从放置目标中移出时触发
ondragover 元素或文本选择在放置目标中移动时触发
ondrop 在有效放置目标上放置元素或文本选择时触发
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 let box1 = document .querySelector ('#box1' )let box2 = document .querySelector ('#box2' )let img = new Image () img.src = 'https://www.5207.fun/img/loading.gif' box1.ondragstart = function (e ) { e.dataTransfer .setData ('text/plain' , '#box1' ) e.dataTransfer .setDragImage (img, 100 , 100 ) console .log ('dragstart' ) } box2.ondragover = function (e ) { e.preventDefault () console .log (e.dataTransfer .dropEffect ) e.dataTransfer .dropEffect = 'move' console .log ('dragover' ) } box2.ondrop = function (e ) { e.preventDefault () e.stopPropagation () let id = e.dataTransfer .getData ('text/plain' ) let el = document .querySelector (id) this .appendChild (el) }
系统文件拖放 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 document .body .ondragover = function (e ) { e.preventDefault () } document .body .ondrop = function (e ) { e.preventDefault () e.stopPropagation () console .log (e.dataTransfer .files ) let file = e.dataTransfer .files [0 ] let fr = new FileReader () fr.onload = function ( ) { let img = new Image () img.src = this .result document .body .appendChild (img) } fr.readAsDataURL (file) }
系统文件读取 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 document .body .ondragover = function (e ) { e.preventDefault () } document .body .ondrop = function (e ) { e.preventDefault () e.stopPropagation () [...e.dataTransfer .items ].forEach (item => { console .log (item.kind ) let entry = item.webkitGetAsEntry () getFiles (entry) }) } function getFiles (entry ) { console .log (entry) if (entry.isFile ) { entry.file (file => { console .log (file) }, error => { console .error (error) }) } if (entry.isDirectory ) { let dirReader = entry.createReader () dirReader.readEntries (entries => { entries.forEach (entry => { getFiles (entry) }) }) } }
严格模式 代码(或一个函数)开始行插入'use strict'
开启严格模式
一般情况下,开发环境用 ES 或者 Typescript,打包出的 js 代码使用严格模式
全局变量必须声明
禁止使用 with
创建 eval 作用域
正常模式下,JS 只有两种变量作用域:全局作用域 + 函数作用域。严格模式下,JS 增加了 eval 作用域
禁止 this 指向全局作用域
函数参数不能重名
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 'use strict' function fn ( ) { 'use strict' } n = 10 let obj = { x : 10 }with (obj) { console .log (x) } var x = 10 eval ('var x = 20; console.log(x)' )console .log (x)function fn ( ) { console .log ('this' , this ) } fn ()function fn (x, x, y ) { }