0120-浏览器事件

Javascript和HTML的交互都是通过事件来实现的,而事件的产生与执行则是遵循着传统软件工程领域中的观察者模式,其能够做到页面行为和页面展示的解耦合。 本节内容会从事件流谈起,然后逐一介绍几种注册事件的方式以及他们其中的一些细节,最后还会提到关于**事件委托(代理)**的概念。 事件流 事件流描述了页面接受事件的顺序。因为一个事件的触发可能会影响好几处地方,这很容易理解,比如在页面上嵌套着写了几个div元素,同时在最里层的div元素上进行事件触发,那这不仅仅是最内层的div对事件进行响应,任意一层的嵌套的div都会对事件进行相应处理。(其实通过上述的观察者模式也可以推断出其合理性,因为一个对象可以由多个观察者进行观察) 所以多个监听事件的元素响应顺序需要进行统一,因为一些历史原因,事件的响应顺序有两种模式:冒泡和捕获。 事件冒泡 顾名思义,事件的冒泡就如水底下的气泡一下,从内到外,同理,事件冒泡规定的事件流顺序也是从内而外,事件会从最深层的节点开始触发,然后向外传播到document(文档)。 代码如下所示。 <html> <body> <div id="ddd"> click me </div> </body> </html> 此时我如果对id=ddd的div元素进行click事件触发,那么该事件会以如下顺序发生: div body html document 现代的浏览器的事件会一直冒泡到window对象。 事件捕获 事件捕获则和事件冒泡相反,事件的响应顺序是从外到内的,还是以上一个例子为例,那么对应click事件讲会以如下顺序发生: document html body div DOM事件流 DOM2 Events规范里规定里事件流为分三个部分:事件捕获,到达目标和事件冒泡。 需要注意的是,div元素(即直接触发元素)是不会响应捕获事件的,因为通常认为直接触发事件是冒泡阶段发生的,所以它也是冒泡阶段第一个发生的事件。 但现在大多数支持DOM事件流的浏览器都实现了一个小小的拓展,即在捕获阶段在事件目标上触发事件。最终结果表现为有两个机会来处理事件。 事件处理程序 事件意味着用户或浏览器执行的某种动作,而为响应事件而调用的函数被称为事件处理程序(事件监听器)。 HTML事件处理程序 HTML事件处理程序是以HTML属性的形式来进行指定的。该属性的值必须是能够执行的javascript代码。 比如下面这个例子,就是按钮在被点击时执行一段代码。 <button onclick="console.log('click')"> click me </button> 当然也可以以函数的形式来进行响应事件定义。 <script> function click(event){ console.log('click') } </script> <button onclick="click(event)"> click me </button> 可以看到,除了把函数单独拎出来以外,还多了一个event对象,这个是一个特殊的局部变量,它定义了事件触发的一些属性以及被触发元素的一些属性。 除此之外,HTML事件处理程序中的this就是DOM元素本身,所以可以直接使用this对象去获取对应元素上的属性。 <input type="button" value="Click Me" onclick="console.log(this.value)"> 这里还有个比较有趣的地方,获取元素属性时可以直接省略掉this,直接使用value,即下面写法也能达到同样的效果。 <input type="button" value="Click Me" onclick="console.log(value)"> 因为这个包装函数在创建时其作用域链被with操作符给延长了,所以document和元素自身的成员都可以被当成局部变量来使用。 function() { with(document) { with(this) { // 属性值 } } } 但最好不要这样做,因为不仅仅会显得很诡异,而且在后期调试时也会造成误解。 HTML事件处理程序一个比较大的问题是:它把HTML和Javascript在代码上进行了强耦合(在逻辑上依然是分开的),如果我们需要更改响应程序,那么两处都需要进行修改。...

January 20, 2022 · 2 min · 260 words · Runtus

DOM扩展

虽然原生DOM API已经能做许多事情了,但是仍然不断有标准或专有的扩展出现,以支持更多的功能,由于各个浏览器对DOM扩展的支持是专有的,为了统一这些专有的DOM API,W3C开始着手将这些专有扩展转变为标准规范。 Selectors API Selectors APIs 是浏览器原生支持的CSS查询API,由于是原生支持,解析和遍历DOM树可以通过底层编译语言实现,相比其他Javascript库(比如jQuery),性能有数量级的提升。 Selectors API Level 1 主要是两个API:querySelector() 和 querySelectorAll() querySelector() 该方法接受CSS选择符参数,返回匹配到的第一个后代元素,如果没有匹配元素则返回null。 // 匹配 class 为 list 的第一个DOM元素 document.querySelector('.list') // 匹配 id 为 myDiv 的第一个DOM元素 document.querySelector('#myDiv') // 匹配 class=header DOM元素子元素中 id为someDiv的元素 const header = querySelector('.header'); header.querySelector('#someDiv') 如果直接在document上使用querySelector方法,会从文档元素开始搜索(前两个例子);在Element上使用querySelector方法,则只会在该元素的后代中查询(第三个例子)。 querySelectorAll() 该方法和querySelector类似,接受CSS选择符参数,只不过它会返回匹配的所有节点。即返回的是一个NodeList的静态实例。 ⚠️注意:无论是querySelector还是querySelectorAll返回的都是DOM元素的静态快照,即和之前提到的getElementById获取的动态实例不同,更改静态快照是不会影响DOM元素在页面上的渲染。 matches() matches方法接受一个css选择符参数,用于判断是否存在对应css选择符的DOM元素,如果存在返回true,否则返回false。 if(document.body.matches("body.header")){ // true } CSS类扩展 HTML5增加了一些特性以方便使用CSS类。 getElementsByClassName() 该方法接受一个参数,包含一个或多个类名的字符串,返回类名中包含对应类的元素的NodeList。 // 返回 class 包含 username 和 current 的类 document.getElementsByClassName('username current') classList属性 classList属性提供了快速操作DOM元素类名的方法,如果是之前,对一个含有多个class的DOM元素进行类名操作会很麻烦,基本操作都是把其类字符串解析成数组,然后一个一个进行匹配操作,最后再合并为一个新的类字符串重新赋值回去。 // 要删除"user"类 let targetClass = "user"; // 把类名拆成数组 let classNames = div....

December 26, 2021 · 1 min · 114 words · Runtus

1224-浏览器缓存

浏览器缓存是性能优化中最直接,高效的优化方式,它可以显著减少因为网络传输而带来的损耗。 对于数据请求来说,大致可以分为 请求 -> 处理 -> 响应这三个步骤,而浏览器缓存则主要在第一步和第三步做手脚,即请求发出时寻找合适的缓存,拿到新的响应数据时做新的缓存。 缓存带给我们最直观的感受就是,每次加载页面,第二次之后加载总是比第一次加载的更快,这就是缓存的功劳,下面讲从缓存位置和缓存策略两个方面介绍浏览器相关缓存。 缓存位置 浏览器的缓存位置大概可以分为四种: Service Worker Memory Cache Disk Cache Push Cache(HTTP 2) 他们有各自的优先级,当发出请求时,浏览器会依次去寻找缓存,如果都没有命中,才会发出请求。 Service Worker Service Worker是浏览器背后的独立线程,可以用来实现缓存功能,但是需要注意,如果要使用Service Worker,传输协议必须是HTTPS。 Service Worker实现缓存大致三个步骤。 注册Service Worker。 监听install事件,并对需要的文件进行缓存。 拦截HTTPS请求,并根据请求内容去命中缓存,如果命中,则直接使用缓存,否则请求数据。 下面是一串实例代码(源代码来自前端面试之道) // index.js if (navigator.serviceWorker) { navigator.serviceWorker .register('sw.js') .then(function(registration) { console.log('service worker 注册成功') }) .catch(function(err) { console.log('servcie worker 注册失败') }) } // sw.js // 监听install事件,缓存文件 self.addEventListener('install', e => { e.waitUntil( caches.open('my-cache').then(function(cache) { return cache.addAll(['./index.html', './index.js']) }) ) }) // 拦截请求,并根据请求去命中响应数据 self....

December 24, 2021 · 1 min · 144 words · Runtus

初入数据可视化

视图编码(可视化编码) = 标记 + 视觉通道 可视化设计的三部曲 可展示数据的筛选 -> 可视化编码映射(视图编码) -> 视图与交互设计 数据可视化设计的注意事项 在对数据可视化之前,要选择合适的标记和视觉通道,选择合适的视觉通道编码能够更加清晰,直观地展现出数据的特点,同时能够使用户更加容易地分析数据特征。 不同的视觉通道编码信息会产生不同的效果,这种效果也被称为表现力和有效性。 表现力和有效性决定着数据可视化的最终效果。 在表现力排序中,无论是定量型视觉通道还是定性型视觉通道,空间位置都具有最大表现力。 决定表现力的四个维度: 精准性 可辨认性 可分离性 -> 不同的视觉通道编码之间互相干扰的程度 视觉突出 -> 人依靠本能,在很快的时间内快速感应到图形中的异常点。此维度在发现异常数据的可视化分析中至关重要。 提升表现力的方法: 聚焦:通过恰当的技术手段就将可视化结果中的最重要的部分重点突出。 均衡:空间布局要合理,将重要的元素位于中心区域,其余元素均衡分布。 简单:元素尽量简单,避免画面过于复杂。 隐喻:尽量用人们所熟悉的某样事物去表达信息,从而使得可视化内容更加直观、易懂。 数据按照它们之间的特征,可以大致分为以下的三类: 数值型数据,分类型数据,有序性数据

October 17, 2021 · 1 min · 32 words · Runtus