挑战21天手写前端框架 day3 让页面运行起来

简介: 挑战21天手写前端框架 day3 让页面运行起来

image.png



阅读本文需要 3 分钟,编写本文耗时 3 小时,因为不知道该从哪个角度切入会更加合适,所以涂涂改改。纠结半天,最终确定下来今天的内容。


之前看 phodal 的低代码相关的文章,里面有一句话大概说的是,项目的复杂度就像力一样,只会发生转移而不会凭空消失。


我觉得这句话在好多地方都是适用的,比如我们要手写一个前端框架的目的就是将手写原生web项目的复杂度转移到框架中。


所以要手写前端框架,我们可以回归到前端开发的最初的起点,回想一下你学习前端开发的第一个 demo。


比如我们写一个简单的 Hello World:

<!DOCTYPE html>
<html lang="en">
<body>
    <div id="malita">
        <span>loading...</span>
    </div>
    <script>
        const root = document.getElementById('malita');
        root.innerHTML = '<span>Hello Malita!</span>';
        root.addEventListener('click', (event) => {
            event.target.innerHTML = '<span>Hi!</span>';
        })
    </script>
</body>
</html>
复制代码


有点前端基础的同学应该一眼就能看出上面的代码逻辑,就是在页面上显示 ‘Hello Malita!’,然后用户点击之后变成了 ‘Hi!’。

上面的需求虽然非常的简单,甚至没有前端基础的同学多看几眼也能看懂,但是如果使用现代前端框架中常常被提及的 MVC 架构去分析的话。


Hello Malita!Hi! 是数据,存放在 Model 层;  是视图存放在 View 层; 点击事件和数值变化是控制层存放在 Controller


将上面的代码拆解之后,得到以下的代码段,夸张点说,这就是 React 和 Vue 的核心源码,这可不是不买会员就可以观看的内容哦。 (我吹的,我不会Vue)

<script>
        function Model() {
            this.text = 'Hello Malita!';
            this.setText = text => this.text = text;
        }
        function View(controller) {
            const self = this;
            self.root = document.getElementById('malita');
            self.root.addEventListener('click', controller.onClick)
            this.render = () => {
                const text = controller.getModel().text;
                self.root.innerHTML = `<span>${text}</span>`;
            }
        }
        function Controller(model) {
            const self = this;
            self.model = model;
            this.onClick = (event) => {
                self.model.setText('Hi!');
                // 数据驱动页面,页面应该根据 model 更改响应 render
                const text = controller.getModel().text;
                event.target.innerHTML = `<span>${text}</span>`;
            }
            this.getModel = () => {
                return self.model;
            }
        }
        const model = new Model();
        const controller = new Controller(model);
        const view = new View(controller);
        view.render();
    </script>
复制代码


递进一步的我们来看下使用 React 如何实现上面的功能。

为了便于后续的开发,(其实是我懒得复制 cdn 链接)我们在当前项目的根目录下,安装 react 和 react-dom

npm i react react-dom
复制代码


然后在 demo 中引入

<script src="../../node_modules/react/umd/react.development.js"></script>
    <script src="../../node_modules/react-dom/umd/react-dom.development.js"></script>
复制代码


然后使用 React 的原始用法来实现上述的功能

<body>
    <div id="malita">
        <span>loading...</span>
    </div>
    <script>
        const Hello = () => {
            const [text, setText] = React.useState('Hello Malita!');
            return React.createElement("span", {
                onClick: () => {
                    setText('Hi!');
                }
            }, text);
        };
        const root = ReactDOM.createRoot(document.getElementById('malita'));
        root.render(React.createElement(Hello));
    </script>
</body>
复制代码


如果你没有 React 基础,那这个用例和上面的哪些用例可以比对着,仔细看看。

使用 createElement 的语法进行 React 开发,最大的问题就是当有层级嵌套时,会变得非常的复杂。可读性极差。

比如简单的

<div><p>Hello<span>Malita!</span></p></div>
复制代码


需要编写以下代码:

React.createElement("div", null, React.createElement("p", null, "Hello", React.createElement("span", null, "Malita!")));

就相当于你在写 html 的时候,都不使用 html 的标签,而是全部使用 js 方法 document.createElement(tagName) 来编写整个页面。


所以为了更加便于书写和阅读,充分利用 html 和 js 的优势,我们进行 React 开发一般都会使用 jsx 语法。

依旧是上面的需求,我们引入 jsx,代码变得更直观了:

<body>
    <div id="malita">
        <span>loading...</span>
    </div>
    <script>
        const Hello = () => { 
            const [text, setText] = React.useState('Hello Malita!'); 
            return (<span onClick={()=> {
                setText('Hi!')
            }}> {text} </span>);
        }; 
        const root = ReactDOM.createRoot(document.getElementById('malita')); 
        root.render(React.createElement(Hello));
    </script>
</body>
复制代码


但是写完发现,浏览器是无法识别 jsx 语法的,所以我们要引入 babel 来将我们的 jsx 语法转换成 React 的原始语法。

其实 babel 的实现原理非常简单,就是通过将代码转换成抽象语法书 (AST),再转换成目标语法,记下来,这是面试题。


在项目中安装 babel-standalone

npm i babel-standalone
复制代码


然后在项目中引入,并且修改 script 的 type 为 text/babel

<head>
+ <script src="../../node_modules//babel-standalone/babel.min.js"></script>
</head>
<body>
    <div id="malita">
        <span>loading...</span>
    </div>
-    <script>
+    <script type="text/babel">
    </script>
</body>
复制代码


我测试的时候使用的是谷歌浏览器 V100 ,所以里面用到的 ES6 的一些语法,它都可以识别,后续我们也会使用 babel 将我们的 es6 代码转换成 es5。


到此我们就完成了让页面运行起来的所有尝试。


值得注意的是,这不是一个 React 的零基础入门教程,文章的用意在于讲清楚前端框架的部分运行原理和工作内容,你可以把这当作一篇需求文档来对待,因为我们会在后续的内容中,用更加科学合理的方式来实现它。


在这一个系列中,我会尽量讲明“为什么使用XXX”,它解了什么问题。

感谢阅读,如果你有其他的疑问,或者对这个系列书写的角度和切入点有其他的看法和建议的话,欢迎在评论区和我互动。


源码归档

目录
相关文章
|
11天前
|
前端开发 数据安全/隐私保护
.自定义认证前端页面
.自定义认证前端页面
6 1
.自定义认证前端页面
|
4月前
|
开发框架 前端开发 JavaScript
循序渐进VUE+Element 前端应用开发(5)--- 表格列表页面的查询,列表展示和字段转义处理
循序渐进VUE+Element 前端应用开发(5)--- 表格列表页面的查询,列表展示和字段转义处理
|
12天前
|
缓存 前端开发 JavaScript
前端开发的必修课:如何让你的网页在弱网环境下依然流畅运行?
【10月更文挑战第30天】随着移动互联网的普及,弱网环境下的网页性能优化变得尤为重要。本文详细介绍了如何通过了解网络状况、优化资源加载、减少HTTP请求、调整弱网参数和代码优化等方法,提升网页在弱网环境下的加载速度和流畅性,从而改善用户体验。
91 4
|
6天前
|
前端开发 安全 JavaScript
在阿里云快速启动Appsmith搭建前端页面
本文介绍了Appsmith的基本信息,并通过阿里云计算巢完成了Appsmith的快速部署,使用者不需要自己下载代码,不需要自己安装复杂的依赖,不需要了解底层技术,只需要在控制台图形界面点击几下鼠标就可以快速部署并启动Appsmith,非技术同学也能轻松搞定。
|
10天前
|
机器学习/深度学习 自然语言处理 前端开发
前端神经网络入门:Brain.js - 详细介绍和对比不同的实现 - CNN、RNN、DNN、FFNN -无需准备环境打开浏览器即可测试运行-支持WebGPU加速
本文介绍了如何使用 JavaScript 神经网络库 **Brain.js** 实现不同类型的神经网络,包括前馈神经网络(FFNN)、深度神经网络(DNN)和循环神经网络(RNN)。通过简单的示例和代码,帮助前端开发者快速入门并理解神经网络的基本概念。文章还对比了各类神经网络的特点和适用场景,并简要介绍了卷积神经网络(CNN)的替代方案。
|
29天前
|
前端开发 JavaScript
回顾前端页面发送ajax请求方式
回顾前端页面发送ajax请求方式
36 18
|
30天前
|
存储 弹性计算 算法
前端大模型应用笔记(四):如何在资源受限例如1核和1G内存的端侧或ECS上运行一个合适的向量存储库及如何优化
本文探讨了在资源受限的嵌入式设备(如1核处理器和1GB内存)上实现高效向量存储和检索的方法,旨在支持端侧大模型应用。文章分析了Annoy、HNSWLib、NMSLib、FLANN、VP-Trees和Lshbox等向量存储库的特点与适用场景,推荐Annoy作为多数情况下的首选方案,并提出了数据预处理、索引优化、查询优化等策略以提升性能。通过这些方法,即使在资源受限的环境中也能实现高效的向量检索。
|
2月前
|
前端开发 JavaScript API
前端JS读取文件内容并展示到页面上
前端JavaScript使用FileReader API读取文件内容,支持文本类型文件。在文件读取成功后,可以通过onload事件处理函数获取文件内容,然后展示到页面上。
79 2
前端JS读取文件内容并展示到页面上
|
1月前
|
前端开发 数据安全/隐私保护
angular前端基本页面验证
angular前端基本页面验证
29 1
|
1月前
|
前端开发
搭建个人博客--1、前端页面
搭建个人博客--1、前端页面
20 1