你是否曾惊叹于React的魔力?是否曾好奇Dojo是如何运作的?是否曾对jQuery的巧妙操作感到好奇?在本教程中,我们将潜入幕后,尝试构建一个超简化的jQuery版本。
我们几乎每天都在使用JavaScript库。无论是实现算法、提供API抽象还是操作DOM,库在大多数现代网站中都执行许多功能。
在本教程中,我们将尝试从头开始构建一个这样的库(当然,这是一个简化的版本)。我们将创建一个用于DOM操作的库,类似于jQuery。是的,这很有趣,但在你兴奋之前,让我澄清几点:
- 这不会是一个功能齐全的库。我们将编写一套可靠的方法,但这并非完整的jQuery。我们将做的足够多,让你对构建库时会遇到的问题类型有很好的了解。
- 我们在这里不会追求跨所有浏览器的完全兼容性。我们今天编写的代码应该可以在Chrome、Firefox和Safari上运行,但在IE等旧版浏览器上可能无法运行。
- 我们不会涵盖我们库的每一个可能的用途。例如,我们的
prepend
方法只在你传递给它们我们的库实例时才有效;它们不适用于原始DOM节点或节点列表。
-
创建库的框架
我们将从模块本身开始。我们将使用ECMAScript模块(ESM),这是一种在Web上导入和导出代码的现代方法。
export class Dome { constructor(selector) { } }
如你所见,我们导出一个名为Dome
的类,其构造函数将接受一个参数,但它可以是多种类型。如果它是一个字符串,我们将假设它是一个CSS选择器,但我们也可以接受单个DOM节点或document.querySelectorAll
的结果来简化元素查找。如果它具有length
属性,我们将知道我们拥有一个节点列表。我们将把这些元素存储在this.elements
中,Dome
对象可以包装多个DOM元素,我们几乎需要在每种方法中循环遍历每个元素,因此这些实用程序将非常方便。
让我们从一个map
函数开始,它接受一个参数,一个回调函数。我们将循环遍历数组中的项目,收集回调函数返回的内容,Dome
实例将接收两个参数:当前元素和索引号。
我们还需要一个forEach
方法,默认情况下,我们可以简单地将调用转发到mapOne
。很容易看出这个函数的作用,但真正的问题是,为什么我们需要它?这需要一点你可能称之为“库理念”的东西。
简短的理念探讨
如果构建库只是编写代码,那将不是一项太难的工作。但在从事这个项目时,我发现更难的部分是决定某些方法应该如何工作。
很快,我们将构建一个Dome
对象,它包装了多个DOM节点($("li").text()
),你将得到一个包含所有元素文本连接在一起的单个字符串。这有用吗?我认为没有,但我不知道更好的返回值是什么。
对于这个项目,我将把多个元素的文本作为数组返回,除非数组中只有一个项目;然后我们只返回文本字符串,而不是包含单个项目的数组。我认为你最常获取单个元素的文本,所以我们对此情况进行了优化。但是,如果你正在获取多个元素的文本,我们将返回你可以使用的内容。
返回编码
因此,mapOne
将首先调用map
,然后返回数组或数组中的单个项目。如果你仍然不确定这如何有用,请继续关注:你将看到!
mapOne(callback) { const m = this.map(callback); return m.length > 1 ? m : m[0]; };
-
使用文本和HTML
接下来,让我们添加text
方法来查看我们是在设置还是获取。请注意,这只是遍历元素并设置它们的文本。如果我们正在获取,我们将返回元素的mapOne
方法:如果我们正在处理多个元素,这将返回一个数组;否则,它将只是一个字符串。
html
方法与text
方法几乎相同,只是它将使用innerHTML
。
html(html) { if (typeof html !== "undefined") { this.forEach(function (el) { el.innerHTML = html; }); return this; } else { return this.mapOne(function (el) { return el.innerHTML; }); } }
就像我说的:几乎相同。
-
操作类
接下来,我们要能够添加和删除类,所以让我们编写addClass
和removeClass
方法。
我们的addClass
方法将在每个元素上使用classList.add
方法。当传递字符串时,只添加该类,当传递数组时,我们将遍历数组并添加其中包含的所有类。
addClass(classes) { return this.forEach(function (el) { if (typeof classes !== "string") { for (const elClass of classes) { el.classList.add(elClass); } } else { el.classList.add(classes); } }); }
很简单,对吧?
现在,删除类呢?为此,你几乎要做同样的事情,只是使用classList.remove
方法。
-
使用属性
接下来,让我们添加attr
函数。这将很容易,因为它与我们的html
方法几乎相同。像这些方法一样,我们将能够同时获取和设置属性:我们将接受一个属性名称和值来设置,只接受一个属性名称来获取。
attr(attr, val) { if (typeof val !== "undefined") { return this.forEach(function (el) { el.setAttribute(attr, val); }); } else { return this.mapOne(function (el) { return el.getAttribute(attr); }); } }
如果val
已定义,我们将使用setAttribute
方法。否则,我们将使用getAttribute
方法。
-
创建元素
我们应该能够创建新元素,任何好的库都可以做到这一点。当然,这作为Dome
类的方法是没有意义的。
export function create(tagName,attrs) { }
如你所见,我们将接受两个参数:元素的名称和属性对象。大多数属性将通过我们的attr
方法应用,文本内容将通过text
方法应用于Dome
对象。以下是所有这些的实际操作:
export function create(tagName, attrs) { let el = new Dome([document.createElement(tagName)]); if (attrs) { for (let key in attrs) { if (attrs.hasOwnProperty(key)) { el.attr(key, attrs[key]); } } } return el; }
如你所见,我们创建元素并将其直接发送到新的Dome
对象中。
但是现在我们正在创建新元素,我们将希望将它们插入到DOM中,对吧?
-
附加和前置元素
接下来,我们将编写append
和prepend
方法。这些函数有点棘手,主要是因为有多种用例。以下是我们想要能够做的事情:
dome1.append(dome2); dome1.prepend(dome2);
我们可能想要附加或前置:
- 一个新元素到一个或多个现有元素
- 多个新元素到一个或多个现有元素
- 一个现有元素到一个或多个现有元素
- 多个现有元素到一个或多个现有元素
我使用“新”来表示尚未在DOM中的元素;现有元素已在DOM中。让我们现在逐步讲解:
append(els) { }
我们期望els
是一个Dome
对象。一个完整的DOM库会将其作为节点或节点列表接受,但我们不会这样做。我们必须遍历我们的每个元素,然后在其中,我们遍历我们想要附加的每个元素。
如果我们正在附加,则来自作为参数传入的外部Dome
对象的i
将只包含原始(未克隆的)节点。因此,如果我们只将单个元素附加到单个元素,则所有涉及的节点都将是它们各自的prepend
方法的一部分。
-
删除元素
为了完整起见,让我们添加一个remove
方法。这将非常简单,因为我们只需要使用removeChild
方法。为了使事情更简单,我们将使用forEach
循环反向遍历,我将使用removeChild
方法反向遍历循环,每个元素的Dome
对象仍然可以正常工作;我们可以使用任何我们想要的方法,包括将其附加或前置回DOM。不错,对吧?
-
使用事件
最后但并非最不重要的是,我们将编写一些事件处理程序函数。
查看on
方法,然后我们将讨论它:
on(evt, fn) { return this.forEach(function (el) { el.addEventListener(evt, fn, false); }); }
这很简单。我们只需遍历元素并使用addEventListener
方法。off
函数(它取消挂钩事件处理程序)几乎相同:
off(evt, fn) { return this.forEach(function (el) { el.removeEventListener(evt, fn, false); }); }
-
使用库
要使用Dome
,只需将其放入脚本并导入它。
import {Dome, create} from "./dome.js"
从那里,你可以像这样使用它:
new Dome("li") ...
确保你导入它的脚本是ES模块。
就是这样!
我希望你能尝试一下我们的小型库,甚至可以扩展它一点。正如我前面提到的,我已经把它放在GitHub上了。随意分叉它,玩耍,并发送拉取请求。
让我再次澄清一下:本教程的目的并不是建议你应该总是编写自己的库。有专门的团队在共同努力,使大型的、成熟的库尽可能好。这里的目的是让你对库内部可能发生的事情有所了解;我希望你在这里学到了一些技巧。
我强烈建议你在你的一些最喜欢的库中四处挖掘。你会发现它们并不像你想象的那么神秘,而且你可能会学到很多东西。以下是一些不错的起点:
- 我从jQuery源代码中学到的11件事(Paul Irish)
- jQuery的幕后(James Padolsey)
- React 16:深入了解我们前端UI库的API兼容重写
这篇文章已更新,其中包含Jacob Jackson的贡献。Jacob是一位网络开发者、技术作家、自由职业者和开源贡献者。
以上是构建您的第一个JavaScript库的详细内容。更多信息请关注PHP中文网其他相关文章!

Python和JavaScript的主要区别在于类型系统和应用场景。1.Python使用动态类型,适合科学计算和数据分析。2.JavaScript采用弱类型,广泛用于前端和全栈开发。两者在异步编程和性能优化上各有优势,选择时应根据项目需求决定。

选择Python还是JavaScript取决于项目类型:1)数据科学和自动化任务选择Python;2)前端和全栈开发选择JavaScript。Python因其在数据处理和自动化方面的强大库而备受青睐,而JavaScript则因其在网页交互和全栈开发中的优势而不可或缺。

Python和JavaScript各有优势,选择取决于项目需求和个人偏好。1.Python易学,语法简洁,适用于数据科学和后端开发,但执行速度较慢。2.JavaScript在前端开发中无处不在,异步编程能力强,Node.js使其适用于全栈开发,但语法可能复杂且易出错。

javascriptisnotbuiltoncorc; saninterpretedlanguagethatrunsonenginesoftenwritteninc.1)javascriptwasdesignedAsalightweight,解释edganguageforwebbrowsers.2)Enginesevolvedfromsimpleterterterpretpreterterterpretertestojitcompilerers,典型地提示。

JavaScript可用于前端和后端开发。前端通过DOM操作增强用户体验,后端通过Node.js处理服务器任务。1.前端示例:改变网页文本内容。2.后端示例:创建Node.js服务器。

选择Python还是JavaScript应基于职业发展、学习曲线和生态系统:1)职业发展:Python适合数据科学和后端开发,JavaScript适合前端和全栈开发。2)学习曲线:Python语法简洁,适合初学者;JavaScript语法灵活。3)生态系统:Python有丰富的科学计算库,JavaScript有强大的前端框架。

JavaScript框架的强大之处在于简化开发、提升用户体验和应用性能。选择框架时应考虑:1.项目规模和复杂度,2.团队经验,3.生态系统和社区支持。

引言我知道你可能会觉得奇怪,JavaScript、C 和浏览器之间到底有什么关系?它们之间看似毫无关联,但实际上,它们在现代网络开发中扮演着非常重要的角色。今天我们就来深入探讨一下这三者之间的紧密联系。通过这篇文章,你将了解到JavaScript如何在浏览器中运行,C 在浏览器引擎中的作用,以及它们如何共同推动网页的渲染和交互。JavaScript与浏览器的关系我们都知道,JavaScript是前端开发的核心语言,它直接在浏览器中运行,让网页变得生动有趣。你是否曾经想过,为什么JavaScr


热AI工具

Undresser.AI Undress
人工智能驱动的应用程序,用于创建逼真的裸体照片

AI Clothes Remover
用于从照片中去除衣服的在线人工智能工具。

Undress AI Tool
免费脱衣服图片

Clothoff.io
AI脱衣机

Video Face Swap
使用我们完全免费的人工智能换脸工具轻松在任何视频中换脸!

热门文章

热工具

Atom编辑器mac版下载
最流行的的开源编辑器

SublimeText3 Linux新版
SublimeText3 Linux最新版

mPDF
mPDF是一个PHP库,可以从UTF-8编码的HTML生成PDF文件。原作者Ian Back编写mPDF以从他的网站上“即时”输出PDF文件,并处理不同的语言。与原始脚本如HTML2FPDF相比,它的速度较慢,并且在使用Unicode字体时生成的文件较大,但支持CSS样式等,并进行了大量增强。支持几乎所有语言,包括RTL(阿拉伯语和希伯来语)和CJK(中日韩)。支持嵌套的块级元素(如P、DIV),

MinGW - 适用于 Windows 的极简 GNU
这个项目正在迁移到osdn.net/projects/mingw的过程中,你可以继续在那里关注我们。MinGW:GNU编译器集合(GCC)的本地Windows移植版本,可自由分发的导入库和用于构建本地Windows应用程序的头文件;包括对MSVC运行时的扩展,以支持C99功能。MinGW的所有软件都可以在64位Windows平台上运行。

SublimeText3 英文版
推荐:为Win版本,支持代码提示!