关于原生js:智能社原生的力量原生JavaScript开发高级课程中有一人字太真

download:智能社原生的力量——原生JavaScript开发高级课程JavaScript开发的根底和最佳实际 JavaScript是一种宽泛应用的编程语言,次要用于Web开发。它是一种解释性的语言,能够让网页交互变得更加活泼和多样化。在本文中,咱们将深入探讨JavaScript开发的基础知识和最佳实际。 基础知识 JavaScript的根本语法非常简单,但须要把握一些要害概念。首先,JavaScript是一种动静类型语言,意味着你不须要显式地申明变量的数据类型。此外,JavaScript也反对面向对象编程,能够创立自定义对象、类和办法。 变量和数据类型是JavaScript开发的另一个外围概念。JavaScript有七种根本数据类型:数字、字符串、布尔值、null、undefined、Symbol和Object。应用这些数据类型,能够创立任何复杂度的应用程序。 最佳实际 以下是一些JavaScript开发的最佳实际: 重视代码品质:编写高质量的代码是至关重要的。你应该重视代码构造、可读性和可维护性。放弃代码整洁并采纳统一的命名约定。 遵循ES6规范:ES6是JavaScript的最新规范,它引入了许多新个性和性能,包含箭头函数、模板字面量、解构赋值等。应用ES6能够使JavaScript代码更简洁、更易读。 应用模块:应用模块化办法能够帮忙你组织和治理简单的JavaScript代码。模块化办法包含CommonJS、AMD和ES6模块。 理解异步编程:JavaScript是一种单线程语言,但它反对异步编程。理解如何应用Promise、async/await和回调函数等办法能够帮忙你编写更高效的JavaScript应用程序。 测试你的代码:测试是保障代码品质的重要伎俩。应用Jest、Mocha等测试框架,能够帮忙你编写测试用例并确保代码的正确性。 总结 JavaScript是Web开发中最罕用的语言之一。理解JavaScript的基础知识和最佳实际对于编写高质量、可保护的JavaScript应用程序至关重要。遵循最佳实际能够帮忙你编写更好的代码,并进步JavaScript应用程序的性能和可靠性。

May 22, 2023 · 1 min · jiezi

回到基础:如何用原生 DOM API 生成表格

翻译:疯狂的技术宅原文:https://www.valentinog.com/bl…怎样用原生 JavaScript 生成表格需?本文告诉你答案!这是一个刷 JavaScript 经验值的好机会:在技术面试中出现的最多的一个问题就是怎样用原生 API 操作 DOM 。在下面的教程中,我们将了解如何使用 JavaScript 生成表格,而无需依赖任何库或框架。你将学到些什么在本教程中,你将学习如何:用 JavaScript 生成一个表格用本机 DOM API 来操作表要求要学习本教程,你应该对 HTML 和 JavaScript 有基本的了解。需求Eloquent JavaScript 是一本非常好的 JavaScript 书籍。这本书很简洁,也不乏味,同时有大量的练习。以下练习改编自第 14 章,它被称为“构建表格”。题目要求你用 JavaScript 构建一个 HTML 表。你的任务是依据 “mountains” 数组中的数据生成表格,将对象中的key对应到列并且每行一个对象。每个对象都是如下形式:{ name: “Monte Falco”, height: 1658, place: “Parco Foreste Casentinesi” }我们有一个名称,一个高度和一个山峰所在的位置。但 HTML 表格是什么? HTML 表格是包含表格数据的元素,以行和列的形式显示。这意味着给出以下数组:let mountains = [ { name: “Monte Falco”, height: 1658, place: “Parco Foreste Casentinesi” }, { name: “Monte Falterona”, height: 1654, place: “Parco Foreste Casentinesi” }];我们打算生成下表:<table> <thead> <tr> <th>name</th> <th>height</th> <th>place</th> </tr> </thead> <tbody> <tr> <td>Monte Falco</td> <td>1658</td> <td>Parco Foreste Casentinesi</td> </tr> <tr> <td>Monte Falterona</td> <td>1654</td> <td>Parco Foreste Casentinesi</td> </tr> </tbody></table>如你所见,该表有一个 thead(表头),其中包含一个具有三个th(表格标题)的 tr(表格行) 。然后是tbody(表体) 中包含一堆 tr(表格行)。每个表格行包含一定数量的 td元素(表格单元格)。有了这些要求,就可以开始编写 JavaScript 文件了。我们的起点可以是以下 HTML:<!DOCTYPE html><html lang=“en”><head> <meta charset=“UTF-8”> <title>Build a table</title></head><body><table><!– here goes our data! –></table></body><script src=“build-table.js”></script></html>将文件另存为 build-table.html 并继续下一部分。生成表头在与 build-table.html 相同的文件夹中创建一个名为 build-table.js 的新文件,并在文件定义数组:let mountains = [ { name: “Monte Falco”, height: 1658, place: “Parco Foreste Casentinesi” }, { name: “Monte Falterona”, height: 1654, place: “Parco Foreste Casentinesi” }, { name: “Poggio Scali”, height: 1520, place: “Parco Foreste Casentinesi” }, { name: “Pratomagno”, height: 1592, place: “Parco Foreste Casentinesi” }, { name: “Monte Amiata”, height: 1738, place: “Siena” }];第一个目标是生成表头。我们知道本机方法 createElement() 会创建传递给它的任何元素。假设我们要创建一个表头,可以用 document.createElement(‘thead’)。不过还有更好的办法吗?让我们先到 MDN 上查阅一下 element table reference 。你可以看到表格的DOM接口是 HTMLTableElement。HTMLTableElement 的有趣之处在于它公开的方法中有 createTHead()。没错!createTHead 返回与给定表关联的表头元素,更 6 的是,如果表中不存在头的话,createTHead 会帮我们创建一个。有了这些知识,接下来在我们的文件中创建一个函数,将 table 作为参数。鉴于我们的需求,可以在其中创建一个新的 thead:function generateTableHead(table) { let thead = table.createTHead();}现在找到我们的表格(记住在 build-table.html 中有一个)并将其传给我们的函数:function generateTableHead(table) { let thead = table.createTHead();}let table = document.querySelector(“table”);generateTableHead(table);如果你在浏览器中打开 build-table.html,在屏幕上还看不到任何内容,不过可以在开发者工具中看到处理的结果。填充表头的工作只做了一半,可以看到表头中填充了一堆 th。每个表头必须映射到对象描述数据组成的 key 上。信息已经存在于数组 mountains 中的第一个对象内部。可以迭代第一个对象的 key:let mountains = [ { name: “Monte Falco”, height: 1658, place: “Parco Foreste Casentinesi” }, //];然后用得到的 key 生成三个表头。但是要先在 thead 中添加一行!这时候该用 document.createElement(“TR”) 了吧?不不不。HTMLTableRowElement 提供了一个 insertRow() 方法,可以在表头上调用。让我们重构一下 generateTableHead 函数:function generateTableHead(table) { let thead = table.createTHead(); let row = thead.insertRow();}新行应包含三个 th(表头),需要手动创建,对于每个 th 元素,我们将附加一个文本节点。这个函数可以使用另一个参数来进行迭代:function generateTableHead(table, data) { let thead = table.createTHead(); let row = thead.insertRow(); for (let key of data) { let th = document.createElement(“th”); let text = document.createTextNode(key); th.appendChild(text); row.appendChild(th); }}let table = document.querySelector(“table”);let data = Object.keys(mountains[0]);generateTableHead(table, data);保存文件并刷新 build-table.html:你应该看到你的表头中被填充了 name、height 和 place。 有时用 React 和 Vue 偷懒的感觉真好,直接操作 DOM 是多么艰难和繁琐。不过我们的工作还没有完成。接下来该填表了……生成行和单元格为了填充表格可以遵循同样的方法,但这次我们需要迭代 mountains 数组中的每个对象。当进入 for…of 循环时,将为每个项目创建一个新行。要创建行,你将用到 insertRow()。但我们不能止步于此。在主循环内部,需要一个内循环,这次要用到 for… in 。内部循环迭代当前对象的每个 key,同时它:创建一个新单元格创建一个新的文本节点将文本节点附加到单元格使用 HTMLTableRowElement 的另一个方法 insertCell() 创建单元格。也就是说通过以上逻辑可以填充我们的表。打开 build-table.js 并创建一个名为 generateTable 的新函数。命名可以与我们现有的函数相同:function generateTable(table, data) { for (let element of data) { let row = table.insertRow(); for (key in element) { let cell = row.insertCell(); let text = document.createTextNode(element[key]); cell.appendChild(text); } }}可以这样调用它:generateTable(table, mountains);最后来看看完整的代码:let mountains = [ { name: “Monte Falco”, height: 1658, place: “Parco Foreste Casentinesi” }, { name: “Monte Falterona”, height: 1654, place: “Parco Foreste Casentinesi” }, { name: “Poggio Scali”, height: 1520, place: “Parco Foreste Casentinesi” }, { name: “Pratomagno”, height: 1592, place: “Parco Foreste Casentinesi” }, { name: “Monte Amiata”, height: 1738, place: “Siena” }];function generateTableHead(table, data) { let thead = table.createTHead(); let row = thead.insertRow(); for (let key of data) { let th = document.createElement(“th”); let text = document.createTextNode(key); th.appendChild(text); row.appendChild(th); }}function generateTable(table, data) { for (let element of data) { let row = table.insertRow(); for (key in element) { let cell = row.insertCell(); let text = document.createTextNode(element[key]); cell.appendChild(text); } }}let table = document.querySelector(“table”);let data = Object.keys(mountains[0]);generateTableHead(table, data);generateTable(table, mountains);你觉得它能工作吗?让我们来试试看:呃……看起来行被附加到了表头而不是表体。另外没有table body!但是如果切换函数调用顺序会怎么样呢?试试吧:// omitted for brevitylet table = document.querySelector(“table”);let data = Object.keys(mountains[0]);generateTable(table, mountains); // generate the table firstgenerateTableHead(table, data); // then the head再次刷新浏览器:好使!另外还得到了一个 tbody。为什么会这样?当你在空表上调用 insertRow() 时,这些方法会为自动你创建一个tbody(如果没有的话)。做得好!不过我们的代码可能没进行很好的组织(有太多的全局绑定),这些将会在下一篇文章中提到。到此为止,你应该能够在不依赖任何外部库的情况下操作HTML表了。恭喜!总结在本教程中,我们学到了如何用原生 JavaScript 生成表格。 HTML 表格在DOM中由 HTMLTableElement 体现。这个接口公开了很多有用的方法,其中 createTHead 用于操作表头,insertRow 用来插入行。另外 HTML 表格的行继承自 HTMLTableRowElement。这个接口有两种方法,其中最重要的是 insertCell。给定一个对象数组,可以使用 for…of 循环来迭代生成行。对于每个对象,我们可以使用 for … in 生成单元格。我们有一些带有全局绑定的代码(请参阅执行上下文和调用堆栈以获取更多信息)。在下一篇文章中,我们将看到怎样重构这些代码。jQuery正逐渐消失。 Bootstrap将在版本5中删除它。 原生DOM API 越来越好了,替换以前用 jQuery 做的事情是可行的,没有(几乎)任何额外的依赖。但即使没有 jQuery 也很容易掉进坑里。有人说你不应该在没有 $shinyNewLibrary 的情况下去操纵 DOM。实际上每个认真的 JavaScript 开发人员都应该知道原生 DOM API,以及如何使用 JavaScript 操作 DOM 。这些问题在技术面试中很容易被问到,你不想因此被拒绝吧?本教程的代码可在 Github 下载(https://github.com/valentinog…)。感谢阅读并敬请期待后续!欢迎继续阅读本专栏其它高赞文章:12个令人惊叹的CSS实验项目世界顶级公司的前端面试都问些什么CSS Flexbox 可视化手册过节很无聊?还是用 JavaScript 写一个脑力小游戏吧!从设计者的角度看 ReactCSS粘性定位是怎样工作的一步步教你用HTML5 SVG实现动画效果程序员30岁前月薪达不到30K,该何去何从7个开放式的前端面试题React 教程:快速上手指南本文首发微信公众号:jingchengyideng欢迎扫描二维码关注公众号,每天都给你推送新鲜的前端技术文章 ...

March 10, 2019 · 3 min · jiezi

移动端滚动研究

移动web滚动问题在移动端如果使用局部滚动,意思就是我们的滚动在一个固定宽高的div内触发,将该div设置成overflow:scroll/auto;来形成div内部的滚动,这时我们监听div的onscroll发现触发的时机区分android和ios两种情况,具体可以看下面表格:| 机型(内核) | body滚动 | 局部滚动 || :-: | :-: | :-: | | ios | 不能实时触发 | 不能实时触发 || android | 实时触发| 实时触发 || ios wkwebview内核 | 实时触发| 实时触发 |不能实时触发表现:只在手指触摸的屏幕上一直滑动时和滚动停止的那一刻才触发。关于模拟滚动概念正常的滚动:我们平时使用的scroll,包括上面讲的滚动都属于正常滚动,利用浏览器自身提供的滚动条来实现滚动,底层是由浏览器内核控制。模拟滚动:最典型的例子就是iscroll了,原理一般有两种:监听滚动元素的touchmove事件,当事件触发时修改元素的transform属性来实现元素的位移,让手指离开时触发touchend事件,然后采用requestanimationframe来在一个线型函数下不断的修改元素的transform来实现手指离开时的一段惯性滚动距离。监听滚动元素的touchmove事件,当事件触发时修改元素的transform属性来实现元素的位移,让手指离开时触发touchend事件,然后给元素一个css的animation,并设置好duration和function来实现手指离开时的一段惯性距离。方案比较第一种方案由于惯性滚动的时机时由js自己控制所以可以拿到滚动触发阶段的scrolltop值,并且滚动的回调函数onscroll在滚动的阶段都会触发。第二种方案相比第一种要劣势一些,区别在于手指离开时,采用的时css的animation来实现惯性滚动,所以无法直接触发惯性滚动过程中的onscroll事件,只有在animation结束时才可以借助animationend来获取到事件,当然也有一种方法可以实时获取滚动事件,也是借助于requestanimationframe来不断的去读取滚动元素的transform来拿到scrolltop同时触发onscroll回调。正常滚动和模拟滚动的性能比较模拟滚动的fps值波动较大,这样滚动起来会有明显的卡顿感觉,各位体验的时候如果滚动超过10屏之后就可以明显感觉到两着的区别。在使用模拟滚动时,浏览器在js层面会消耗更多的性能去改变dom元素的位置,在dom复杂层级深的页面更为高,所以在长列表滚动时还要使用正常滚动更好。滚动和下拉刷新方案1:借助iscroll的原理,整个页面使用模拟滚动,将下拉刷新元素放在顶部,当页面滚动到顶部下拉时,下拉刷新元素随着页面的滚动出现,当手指离开时收回,此方案实现起来较为简单直接借助iscoll即可,但是使用了模拟滚动之后在正常的列表滚动时性能上不如正常滚动。方案2:页面使用正常滚动,将下拉刷新元素放置在顶部top值为负值(正常情况下不可见),当页面处于顶部时下拉,这时监听touchmove事件,修改scrollcontent的tranlateY值,同时修改下拉刷新元素的tranlateY值,将两者同时位移来将下拉刷新元素显示出来,手指离开时(touchend)收回,这种方案满足了在正常列表滚动时使用原生的滚动节省性能,只在下拉刷新时使用模拟滚动来实现效果。方案3:方案2的改良版,唯一不同是将下拉刷新元素和scrollcontent放在一个div里,将下拉刷新元素的margintop设为负值,在下拉刷新时,只需要修改scrollcontent一个元素的tranlateY值即可实现下拉,在性能上要比方案2好。还会有一个性能上的问题就是:当页面的列表过长,dom元素过多时,在模拟滚动,下拉刷新这段时间内,页面也会有卡顿现象,这里采取了一个优化策略即:列表较长时dom数量较多时,在触发下拉刷新的时机时将页面视窗之外的dom元素隐藏或者存放在fragment里面。在刷新完成之后手指离开(touchend)时将隐藏的元素显示出来。需要注意的是,隐藏和显示视窗外的元素这个操作在下拉刷新时只会执行一次,并且只有在下拉刷新时才会执行。下面介绍如何去优化scroll事件的触发,避免scroll事件过度消耗资源:防抖(Debouncing)和节流(Throttling)scroll 事件本身会触发页面的重新渲染,同时 scroll 事件的 handler 又会被高频度的触发, 因此事件的 handler 内部不应该有复杂操作,例如 DOM 操作就不应该放在事件处理中。特别是针对此类高频度触发事件问题(例如页面 scroll ,屏幕 resize,监听用户输入等)。防抖(Debouncing)防抖技术即是可以把多个顺序地调用合并成一次,也就是在一定时间内,规定事件被触发的次数。节流(Throttling)防抖函数确实不错,但是也存在问题,譬如图片的懒加载,我希望在下滑过程中图片不断的被加载出来,而不是只有当我停止下滑时候,图片才被加载出来。又或者下滑时候的数据的 ajax 请求加载也是同理。这个时候,我们希望即使页面在不断被滚动,但是滚动 handler 也可以以一定的频率被触发(譬如 250ms 触发一次),这类场景,就要用到另一种技巧,称为节流函数(throttling)。节流函数,只允许一个函数在 X 毫秒内执行一次。与防抖相比,节流函数最主要的不同在于它保证在 X 毫秒内至少执行一次我们希望触发的事件 handler。关于防抖动与节流,我的博客文章也有提及。使用rAF(requestAnimationFrame)触发滚动事件如果页面只需要兼容高版本浏览器或应用在移动端,又或者页面需要追求高精度的效果,那么可以使用浏览器的原生方法 rAF(requestAnimationFrame)。window.requestAnimationFrame() 这个方法是用来在页面重绘之前,通知浏览器调用一个指定的函数。这个方法接受一个函数为参,该函数会在重绘前调用。rAF 常用于 web 动画的制作,用于准确控制页面的帧刷新渲染,让动画效果更加流畅,当然它的作用不仅仅局限于动画制作,我们可以利用它的特性将它视为一个定时器。(当然它不是定时器)通常来说,rAF 被调用的频率是每秒 60 次,也就是 1000/60 ,触发频率大概是 16.7ms 。(当执行复杂操作时,当它发现无法维持 60fps 的频率时,它会把频率降低到 30fps 来保持帧数的稳定。)var ticking = false; // rAF 触发锁 function onScroll(){ if(!ticking) { requestAnimationFrame(realFunc); ticking = true; }} function realFunc(){ // do something… console.log(“Success”); ticking = false;}// 滚动事件监听window.addEventListener(‘scroll’, onScroll, false);实现以16.7ms 触发一次 handler,降低了可控性,但是提升了性能和精确度。从本质上而言,我们应该尽量去精简 scroll 事件的 handler ,将一些变量的初始化、不依赖于滚动位置变化的计算等都应当在 scroll 事件外提前就绪。避免在scroll 事件中修改样式属性 / 将样式操作从 scroll 事件中剥离输入事件处理函数,比如 scroll / touch 事件的处理,都会在 requestAnimationFrame 之前被调用执行。因此,如果你在 scroll 事件的处理函数中做了修改样式属性的操作,那么这些操作会被浏览器暂存起来。然后在调用 requestAnimationFrame 的时候,如果你在一开始做了读取样式属性的操作,那么这将会导致触发浏览器的强制同步布局。滑动过程中尝试使用 pointer-events: none 禁止鼠标事件pointer-events 是一个 CSS 属性,可以有多个不同的值,大概的意思就是禁止鼠标行为,应用了该属性后,譬如鼠标点击,hover 等功能都将失效,即是元素不会成为鼠标事件的 target。pointer-events: none 可用来提高滚动时的帧频。的确,当滚动时,鼠标悬停在某些元素上,则触发其上的 hover 效果,然而这些影响通常不被用户注意,并多半导致滚动出现问题。对 body 元素应用 pointer-events: none ,禁用了包括 hover 在内的鼠标事件,从而提高滚动性能。大概的做法就是在页面滚动的时候, 给 添加上 .disable-hover 样式,那么在滚动停止之前, 所有鼠标事件都将被禁止。当滚动结束之后,再移除该属性。// css 代码.disable-hover,.disable-hover * { pointer-events: none !important;}// js 代码var body = document.body, timer;window.addEventListener(‘scroll’, function() { clearTimeout(timer); if(!body.classList.contains(‘disable-hover’)) { body.classList.add(‘disable-hover’) } timer = setTimeout(function(){ body.classList.remove(‘disable-hover’) },500);}, false);参考 移动 Web 的滚动,高性能滚动及页面渲染优化 ...

January 5, 2019 · 1 min · jiezi