• 如何构建一个简单的前端框架


    先让我来解释一下什么是前端框架。所谓的前端框架,就是一种能够让我们避免去写常规的HTML和JavaScript代码

    <p id="cool-para">p>
    <script>
      const coolPara = 'Test';
      const el = document.getElementById('cool-para');
      el.innerText = coolPara;
    script>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    而是让我们能够编写出像这样简约的HTML和JavaScript代码(Vue):

    
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    或者是下面这个(react)

    export default function Para() {
      const coolPara = 'Lorem ipsum';
      return 

    { coolPara }

    ; }
    • 1
    • 2
    • 3
    • 4

    这样一个框架的优点是显而易见的。记住诸如document、innerText和getElementById等单词或短语是很困难的。当然看玩笑的,这个不是主要的原因。

    特点

    Reactivity ✨

    第一个主要原因是,在第二个和第三个例子中, 我们可以只设置或更新变量的值,标记(即元素)就会更新,而无需显式设置其 .coolPara``

    ``innerText

    这称为反应性,UI 与这样的数据相关联 仅更改数据即可更新 UI 的方式。

    Composability ✨

    第二个主要原因是能够定义组件和 重用它,而不必在每次我们需要使用它时重新定义它。这 称为可组合性

    常规HTML + JavaScript默认没有这个。所以 以下代码不会执行应有的操作:

    
    <component name="cool-para">
      <p>
        <content />
      p>
    component>
    
    
    <cool-para>Lorem ipsum.cool-para>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    反应性和可组合性是Vue、React等常见前端框架给我们的两个主要优势。

    这些抽象不是免费提供的,我们必须预先加载一堆框架特定的概念,处理它们在以难以解释的神奇方式工作时出现的缺陷,更不用说,还有一大堆容易出错的依赖项。

    但是,事实证明,使用现代Web API来实现这两点并不难。而且,对于大多数用例,我们可能实际上并不需要使用通常的框架以及它们的复杂性的混乱。

    介绍

    Reactivity

    解释反应性的简单语句是,当数据更新时,自动更新 UI

    第一部分是知道数据何时更新。这 不幸的是,这不是普通对象可以做的事情。我们不能 只需附加一个调用以侦听数据的侦听器 更新事件。ondataupdate

    幸运的是,JavaScript 正好允许我们做到这一点, 它被称为代理

    Proxy对象

    Proxy允许我们从常规对象创建代理对象

    const user = { name: 'Lin' };
    const proxy = new Proxy(user, {});
    
    • 1
    • 2

    然后,此代理对象可以侦听对数据的更改。

    在上面的例子中,我们有一个代理对象,但它并不是真的 当知道已经改变时,做任何事情。name

    为此,我们需要一个处理程序,它是一个对象,它告诉代理对象在数据更新时要做什么。

    
    const handler = {
      set(user, value, property) {
        console.log(`${property} is being updated`);
        return Reflect.set(user, value, property);
      },
    };
    
    //用handler创建一个代理
    const user = { name: 'Lin' };
    const proxy = new Proxy(user, handler);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    现在,每当我们使用该对象进行更新时,我们都会收到一条消息,说.name``proxy``"name is being updated"

    下面来看这样写的好处:

    • 代理方法具有通用性,并且可以重用处理器
    • 在代理对象上设置的任何值都可以递归地转换为代理
    • 现在这个神奇的对象可以无论嵌套多深都能对数据更新作出反应。

    除此之外,您还可[处理其他几个访问事件,例如读取、更新、删除属性等。

    实现

    更新用户界面

    如果您还记得,反应性的第二部分是自动更新 UI。为此,我们需要获取要更新的相应 UI 元素。但在此之前,我们 需要首先根据需要标记 UI 元素。

    为此,我们将使用 data-attributes,该功能允许我们在元素上设置任意值:

    <div>
     
      <h1 data-mark="name">h1>
    div>
    
    • 1
    • 2
    • 3
    • 4

    data-attributes的优点在于,我们现在可以使用以下方法找到所有合适的元素:

    document.querySelectorAll('[data-mark="name"]');
    
    • 1

    现在我们只需设置所有适当元素innerText

    const handler = {
      set(user, value, property) {
        const query = `[data-mark="${property}"]`;
        const elements = document.querySelectorAll(query);
    
        for (const el of elements) {
          el.innerText = value;
        }
    
        return Reflect.set(user, value, property);
      },
    };
     
    const user = new Proxy({ name: 'Lin' }, handler);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    就是这样,这就是反应性的关键!

    由于我们的一般性质,对于设置的任何属性,所有适当的 UI 元素都将更新。handler``user

    这就是 JavaScript 功能的强大之处,具有 零依赖性和一些聪明,它可以给我们这些神奇的反应对象。Proxy

    现在进入第二个主要问题

    可组合性

    事实证明,浏览器已经有专门用于此的整个功能 叫Web组件

    很少使用它,因为它使用起来有点痛苦。

    对于可组合性,我们首先需要定义组件。

    标记用于包含标记,即 不由浏览器呈现。例如,您可以添加以下内容 HTML 中的标记: