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

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

<p id="cool-para"></p>
<script>const coolPara = 'Test';const el = document.getElementById('cool-para');el.innerText = coolPara;
</script>

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

<script setup>const coolPara = 'Test';
</script>
<template><p>{{ coolPara }}</p>
</template>

或者是下面这个(react)

export default function Para() {const coolPara = 'Lorem ipsum';return <p>{ coolPara }</p>;
}

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

特点

Reactivity ✨

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

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

Composability ✨

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

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

<!-- Defining the component -->
<component name="cool-para"><p><content /></p>
</component><!-- Using the component -->
<cool-para>Lorem ipsum.</cool-para>

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

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

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

介绍

Reactivity

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

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

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

Proxy对象

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

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

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

在上面的例子中,我们有一个代理对象,但它并不是真的 当知道已经改变时,做任何事情。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);

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

下面来看这样写的好处:

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

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

实现

更新用户界面

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

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

<div><h1 data-mark="name"></h1>
</div>

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

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

现在我们只需设置所有适当元素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);

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

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

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

现在进入第二个主要问题

可组合性

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

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

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

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

<template><h1>Will not render!</h1>
</template>

并且它不会被渲染。您可以将它们视为不可见的容器 为您的组件。

下一个构建块是 定义组件内容的放置位置。这 使组件能够与不同的内容重用,即它变得可组合<slot>

例如,下面是一个将其文本着色为红色的 h1 元素。

<template><h1 style="color: red"><slot /></h1>
</template>

在我们开始使用我们的组件之前——比如上面的红色 h1,我们需要 注册它们。

在注册红色 h1 组件之前,我们需要一个名称来注册它 由。我们可以为此使用该属性:name

<template name="red-h1"><h1 style="color: red"><slot /></h1>
</template>

现在,使用一些JavaScript,我们可以获取组件及其名称:

const template = document.getElementsByTagName('template')[0];
const componentName = template.getAttribute('name');

最后使用 customElements.define注册它:

customElements.define(componentName,class extends HTMLElement {constructor() {super();const component = template.content.children[0].cloneNode(true);this.attachShadow({ mode: 'open' }).appendChild(component);}}
);

下面我们把这两个放到一起

总结

快速回顾一下,我们做了两件事:

  1. 我们创建了一个反应式数据结构,即代理对象,在设置值时可以更新我们标记的任何元素。
  2. 我们定义了一个自定义组件,该组件将呈现它的 内容为红色 H1。red-h1

现在我们可以将它们放在一起:

```html

并让自定义组件呈现我们的数据并在我们时更新 UI 更改数据。当然,通常的前端框架不只是这样做,它们有 专门的语法,例如 Vue 中的[模板语法](https://vuejs.org/guide/essentials/template-syntax.html)和 React 中的 [JSX](https://react.dev/learn/writing-markup-with-jsx),这使得编写复杂的前端相对更简洁 否则会是这样。由于这种专门的语法不是常规的JavaScript或HTML,因此它不是 可由浏览器解析,因此它们都需要专门的工具来编译 在浏览器之前,它们可以简化为常规的JavaScript,HTML和CSS。 了解他们。即使没有专门的语法,你也可以做很多通常的事情 前端框架以类似的简洁性完成,只需使用 和 即可。`Proxy``WebComponents`这里的代码过度简化,并将其转换为框架 你必须充实它。在开发此功能时,我计划维护两个硬约束:1. 没有依赖关系。
2. 在可以使用之前没有构建步骤。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/77453.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

TensorFlow 02(张量)

一、张量 张量Tensor 张量是一个多维数组。与NumPy ndarray对象类似&#xff0c;tf.Tensor对象也具有数据类型和形状。如下图所示: 此外&#xff0c;tf.Tensors可以保留在GPU中。TensorFlow提供了丰富的操作库 (tf.add&#xff0c;tf.matmul,tf.linalg.inv等)&#xff0c;它们…

文字点选验证码识别(下)-训练一个孪生神经网络模型

声明 本文以教学为基准、本文提供的可操作性不得用于任何商业用途和违法违规场景。 本人对任何原因在使用本人中提供的代码和策略时可能对用户自己或他人造成的任何形式的损失和伤害不承担责任。 如有侵权,请联系我进行删除。 文章中没有代码,只有过程思路,请大家谨慎订阅。…

HarmonyOS Codelab 优秀样例——溪村小镇(ArkTS)

一、介绍 溪村小镇是一款展示溪流背坡村园区风貌的应用&#xff0c;包括园区内的导航功能&#xff0c;小火车行车状态查看&#xff0c;以及各区域的风景展览介绍&#xff0c;主要用于展示HarmonyOS的ArkUI能力和动画效果。具体包括如下功能&#xff1a; 打开应用时进入启动页&a…

哪种IP更适合你的数据抓取需求?

程序员大佬们好&#xff01;今天我要和大家分享一个关于数据抓取的话题&#xff0c;那就是Socks5爬虫ip和动态IP之间的比较。在进行数据抓取时&#xff0c;选择适合自己需求的工具和技术是非常重要的。Socks5爬虫ip和动态IP都是常见的网络工具&#xff0c;它们在数据抓取方面都…

Spring Boot 中的参数验证和自定义响应处理,使用 @Valid 注解

&#x1f60a; 作者&#xff1a; 一恍过去 &#x1f496; 主页&#xff1a; https://blog.csdn.net/zhuocailing3390 &#x1f38a; 社区&#xff1a; Java技术栈交流 &#x1f389; 主题&#xff1a; Spring Boot 中的参数验证和自定义响应处理&#xff0c;使用 Valid 注解…

【sgCreateAPI】自定义小工具:敏捷开发→自动化生成API接口脚本(接口代码生成工具)

<template><div :class"$options.name"><div class"sg-head">接口代码生成工具</div><div class"sg-container"><div class"sg-start "><div style"margin-bottom: 10px;">接口地…

如何进行函数的递归调用?

函数的递归调用是一种强大而常见的编程技巧&#xff0c;它允许函数在自身内部调用自己。递归在解决问题的分而治之策略中非常有用&#xff0c;可以将大问题分解为更小的、相同或类似的子问题&#xff0c;然后通过逐步解决这些子问题来解决原始问题。在本文中&#xff0c;我将详…

信息化发展39

IT 服务管理 1 、IT 服务管理是通过主动管理和流程的持续改进来确保IT 服务交付有效且高效的一组活动。 2 、IT 服务管理由若干不同的活动组成&#xff1a; 服务台、事件管理、问题管理、变更管理、配置管理、发布管理、服务级别管理、财务管理、容量管理、服务连续性管理和可…

做期权卖方一般会怎么选择合约?

我们知道期权有多种获利方式&#xff0c;其中靠时间能赚钱的是做期权卖方策略&#xff0c;虽然赚得慢&#xff0c;但可以稳稳地收入权利金&#xff0c;适合某些稳健风格的投资者&#xff0c;胜率对比买方也是高了很多&#xff0c;那么做期权卖方一般会怎么选择合约&#xff1f;…

Unity——JSON的读取

一、读取JSON 在实际中&#xff0c;读取JSON比保存JSON重要得多。因为存档、发送数据包往往可以采用其他序列化方法&#xff0c;但游戏的配置文件使用JSON格式比较常见。游戏的配置数据不属于动态数据&#xff0c;属于游戏资源&#xff0c;但很适合用JSON表示。 下面以一个简…

Mybatis---第二篇

系列文章目录 文章目录 系列文章目录一、#{}和${}的区别是什么?二、简述 Mybatis 的插件运行原理,如何编写一个插件一、#{}和${}的区别是什么? #{}是预编译处理、是占位符, KaTeX parse error: Expected EOF, got # at position 27: …接符。 Mybatis 在处理#̲{}时,会将…

Linux之Socket函数(详细篇)

本篇是基于Linux man手册的一些总结 socket作用&#xff1a; create an endpoint for communication 函数结构 c #include <sys/types.h> /* See NOTES */ #include <sys/socket.h> int socket(int domain, int type, int protocol); 描述 socket() …

LeetCode(力扣)45. 跳跃游戏 IIPython

LeetCode45. 跳跃游戏 II 题目链接代码 题目链接 https://leetcode.cn/problems/jump-game-ii/description/ 代码 class Solution:def jump(self, nums: List[int]) -> int:if len(nums) 1:return 0curdis 0nextdis 0step 0for i in range(len(nums)):nextdis max(…

华为云耀云服务器HECS安装Docker

先去购买服务器&#xff0c;这里就不多说了 1、进入自己买的服务器&#xff0c; 找到切换系统 2、选择centOs镜像 安装docker 卸载旧版本 较旧的 Docker 版本称为 docker 或 docker-engine 。如果已安装这些程序&#xff0c;请卸载它们以及相关的依赖项。 yum remove docker…

职业规划就问它!海量知识与智慧,AIGC助你冲破择业迷茫

数字化时代的兴起改变了我们的日常生活和职业工作方式。科技迅猛的发展&#xff0c;尤其是人工智能的崛起&#xff0c;将我们引入了一个崭新的智能化时代。在这个时代中&#xff0c;AI被认为是从"数字时代"向"数智时代"转变的关键元素&#xff0c;引领着这…

蛇形填数 rust解法

蛇形填数。 在nn方阵里填入1&#xff0c;2&#xff0c;…&#xff0c;nn&#xff0c;要求填成蛇形。例如&#xff0c;n&#xff1d;4时方阵为&#xff1a; 10 11 12 1 9 16 13 2 8 15 14 3 7 6 5 4 解法如下&#xff1a; use std::io;fn main() {let mut buf String::new();…

2023年Gartner新技术与AI成熟度曲线

1. Gartner 将生成式 AI 置于 2023 年新技术成熟度曲线的顶峰&#xff0c;新兴人工智能将对商业和社会产生深远影响 根据 Gartner, Inc. 2023 年新兴技术成熟度曲线&#xff0c;生成式人工智能 (AI) 处于成熟度曲线期望的顶峰&#xff0c;预计将在两到五年内实现转型效益。生成…

htaccess绕过上传实验

实验目的 利用上传htaccess文件解析漏洞绕过验证进行上传PHP脚本木马 实验工具 火狐&#xff1a;Mozilla Firefox&#xff0c;中文俗称“火狐”&#xff08;正式缩写为Fx或fx&#xff0c;非正式缩写为FF&#xff09;&#xff0c;是一个自由及开放源代码网页浏览器&#xff0…

Linux OpenGauss 数据库远程连接

目录 前言 1. Linux 安装 openGauss 2. Linux 安装cpolar 3. 创建openGauss主节点端口号公网地址 4. 远程连接openGauss 5. 固定连接TCP公网地址 6. 固定地址连接测试 前言 openGauss是一款开源关系型数据库管理系统&#xff0c;采用木兰宽松许可证v2发行。openGauss内…

【vue】下拉、上拉刷新

我这里就把主要的下拉刷新的写一下&#xff0c;上拉是一样的道理&#xff0c;就不写了 <div class"talk_top" ref"listWrapper" id"listWrapper"><div class"loadingpic" v-loading"loading"></div><d…