搜索
首页web前端js教程构建您的第一个JavaScript库

Build Your First JavaScript Library

你是否曾惊叹于React的魔力?是否曾好奇Dojo是如何运作的?是否曾对jQuery的巧妙操作感到好奇?在本教程中,我们将潜入幕后,尝试构建一个超简化的jQuery版本。

我们几乎每天都在使用JavaScript库。无论是实现算法、提供API抽象还是操作DOM,库在大多数现代网站中都执行许多功能。

在本教程中,我们将尝试从头开始构建一个这样的库(当然,这是一个简化的版本)。我们将创建一个用于DOM操作的库,类似于jQuery。是的,这很有趣,但在你兴奋之前,让我澄清几点:

  • 这不会是一个功能齐全的库。我们将编写一套可靠的方法,但这并非完整的jQuery。我们将做的足够多,让你对构建库时会遇到的问题类型有很好的了解。
  • 我们在这里不会追求跨所有浏览器的完全兼容性。我们今天编写的代码应该可以在Chrome、Firefox和Safari上运行,但在IE等旧版浏览器上可能无法运行。
  • 我们不会涵盖我们库的每一个可能的用途。例如,我们的prepend方法只在你传递给它们我们的库实例时才有效;它们不适用于原始DOM节点或节点列表。

  1. 创建库的框架

我们将从模块本身开始。我们将使用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];
};
  1. 使用文本和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;
        });
    }
}

就像我说的:几乎相同。


  1. 操作类

接下来,我们要能够添加和删除类,所以让我们编写addClassremoveClass方法。

我们的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方法。

  1. 使用属性

接下来,让我们添加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方法。

  1. 创建元素

我们应该能够创建新元素,任何好的库都可以做到这一点。当然,这作为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中,对吧?

  1. 附加和前置元素

接下来,我们将编写appendprepend方法。这些函数有点棘手,主要是因为有多种用例。以下是我们想要能够做的事情:

dome1.append(dome2);
dome1.prepend(dome2);

我们可能想要附加或前置:

  • 一个新元素到一个或多个现有元素
  • 多个新元素到一个或多个现有元素
  • 一个现有元素到一个或多个现有元素
  • 多个现有元素到一个或多个现有元素

我使用“新”来表示尚未在DOM中的元素;现有元素已在DOM中。让我们现在逐步讲解:

append(els) {

}

我们期望els是一个Dome对象。一个完整的DOM库会将其作为节点或节点列表接受,但我们不会这样做。我们必须遍历我们的每个元素,然后在其中,我们遍历我们想要附加的每个元素。

如果我们正在附加,则来自作为参数传入的外部Dome对象的i将只包含原始(未克隆的)节点。因此,如果我们只将单个元素附加到单个元素,则所有涉及的节点都将是它们各自的prepend方法的一部分。

  1. 删除元素

为了完整起见,让我们添加一个remove方法。这将非常简单,因为我们只需要使用removeChild方法。为了使事情更简单,我们将使用forEach循环反向遍历,我将使用removeChild方法反向遍历循环,每个元素的Dome对象仍然可以正常工作;我们可以使用任何我们想要的方法,包括将其附加或前置回DOM。不错,对吧?

  1. 使用事件

最后但并非最不重要的是,我们将编写一些事件处理程序函数。

查看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);
    });
}

  1. 使用库

要使用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中文网其他相关文章!

声明
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn
Python vs. JavaScript:开发人员的比较分析Python vs. JavaScript:开发人员的比较分析May 09, 2025 am 12:22 AM

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

Python vs. JavaScript:选择合适的工具Python vs. JavaScript:选择合适的工具May 08, 2025 am 12:10 AM

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

Python和JavaScript:了解每个的优势Python和JavaScript:了解每个的优势May 06, 2025 am 12:15 AM

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

JavaScript的核心:它是在C还是C上构建的?JavaScript的核心:它是在C还是C上构建的?May 05, 2025 am 12:07 AM

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

JavaScript应用程序:从前端到后端JavaScript应用程序:从前端到后端May 04, 2025 am 12:12 AM

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

Python vs. JavaScript:您应该学到哪种语言?Python vs. JavaScript:您应该学到哪种语言?May 03, 2025 am 12:10 AM

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

JavaScript框架:为现代网络开发提供动力JavaScript框架:为现代网络开发提供动力May 02, 2025 am 12:04 AM

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

JavaScript,C和浏览器之间的关系JavaScript,C和浏览器之间的关系May 01, 2025 am 12:06 AM

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

See all articles

热AI工具

Undresser.AI Undress

Undresser.AI Undress

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

AI Clothes Remover

AI Clothes Remover

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

Undress AI Tool

Undress AI Tool

免费脱衣服图片

Clothoff.io

Clothoff.io

AI脱衣机

Video Face Swap

Video Face Swap

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

热工具

Atom编辑器mac版下载

Atom编辑器mac版下载

最流行的的开源编辑器

SublimeText3 Linux新版

SublimeText3 Linux新版

SublimeText3 Linux最新版

mPDF

mPDF

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

MinGW - 适用于 Windows 的极简 GNU

MinGW - 适用于 Windows 的极简 GNU

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

SublimeText3 英文版

SublimeText3 英文版

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