Loading [MathJax]/jax/input/TeX/config.js
前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >使用虚拟dom和JavaScript构建完全响应式的UI框架

使用虚拟dom和JavaScript构建完全响应式的UI框架

作者头像
疯狂的技术宅
发布于 2019-03-28 02:35:24
发布于 2019-03-28 02:35:24
1.4K00
代码可运行
举报
文章被收录于专栏:京程一灯京程一灯
运行总次数:0
代码可运行

最近我热衷于响应式编程,特别是在Mobx生态系统。我非常喜欢这个框架背后的思想:以透明的方式实现响应式。所以我问我自己…

在JavaScript中怎样才能创建一个完全 响应式(透明)的UI框架呢?

不要担心,至少现在你不会在npm仓库中看到另外一个JavaScript框架,但是我认为这个一个很好的架构练习。我们将对这个问题一分为二来看,第一个是帮助我们把状态渲染到dom上的UI库,第二个是管理响应式状态的库。是的,我们将创建一个粗糙版本的React和MobX技术栈。:)


UI框架

高度抽象的UI框架应该只是我们应用程序中状态的纯函数。下面是用数学的方法表达这个概念…

如果我们只想要一个高性能的渲染 而不是像React那样完整的库。我们可以使用虚拟dom算法的纯实现,就像你可以在@MatthewEsch的github仓库(https://github.com/Matt-Esch/virtual-dom)中找到的这个一样。我们可以通过一个数组渲染出一个简单的列表:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
import { create, h } from 'virtual-dom';

const render = (state) => {
    const children = state.list.map(t => h('li',{},[t]));
    return h('ul', {}, children);
};

const INITIAL_STATE = {
    list:['first','second']
};

let tree =_render(INITIAL_STATE);
let rootNode = create(tree);

document.body.appendChild(rootNode);

如你所见,这个虚拟dom的实现使用了HyperScript 格式来定义HTML元素。当list(数组)发生改变,我们需要添加如下代码来更新我们的dom:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
const updateDom = (state) => {
    const newTree = render(state);
    const patches = diff(tree, newTree);

    tree = newTree;
    rootNode = patch(rootNode, patches);
};

这样我们就使用了纯函数来创建和更新我们的DOM树。换句话说,框架的UI部分已经完成了。接下来我们来谈谈状态管理部分。


响应式状态管理库

状态管理库需要实现响应式,但是“响应式”是什么意思呢?在我看来,定义一个响应式应用程序的最简单的方法是(观察者)…

显而易见,在这里我过分简化了这个概念,但是在最终的响应式编程中所有的一切都是可观察的。我这里的目的是创建一个对框架使用者同样透明的响应式状态管理库。就像MobX应用程序中发生的那样,当我改变model就会重新渲染。因此我想通过下面的代码给list添加一个新的元素:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
state.list = […state.list,’Another Element’];

在JavaScript中,我知道的实现这个目标的最快方法是使用EcmaScript 2015 Proxies. MDN文档是这么定义代理的:

Proxy 对象用来为基础操作(例如:属性查找、赋值、枚举、方法调用等)定义用户自定义行为。

在使用代理对象之前,考虑到并不是所有的浏览器都支持他。你可以使用Babel的一个插件(https://www.npmjs.com/package/babel-plugin-proxy)或者由谷歌Chrome团队创建的一个腻子补丁(https://github.com/GoogleChrome/proxy-polyfill)

哎,又是 IE…

仅仅使用Proxy的构造函数就可以创建一个Proxy对象。在接下里的栗子里我们将创建一个简单的'Loggable'对象工厂函数,它可以在控制台输出目标对象的每一次属性查找或者赋值过程。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
export default (target) => {
    const loggingHandler = {
        get: function (target,name) {
            const value = target[name];
            console.log(getting ${name}: ${value});
            return value;
        },
        set: function (target,name,value) {
            console.log(setting ${name}: ${value});
            target[name] = value;
            return true;
        }
    };

    return new Proxy(target,loggingHandler);
};

然后我们可以通过很简单的方式创建一个"loggable"对象:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
const INITIAL_STATE = {
    startValue:0
};

const state = loggable(INITIAL_STATE);

const value = state.startValue; //prints 'getting startValue: 0'

state.startValue = 1; //prints 'setting startValue: 1'

我们仅仅需要一个目标对象和监听回调就可以用相同的技术来创建一个通用的观察者。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
export default ({target,listener}) => {
    let observable;

    const set = (target,name,value) => {
        target[name] = value;
        listener(observable);
        return true;
    };

    const get = (target,name) => {
        return Object.freeze(target[name]);
    };

    const handler = {
        set,
        get 
    };

    observable = new Proxy(target,handler);

    return observable;
};

现在我们拥有了我们框架的所有部分,我们只需要组合它们即可。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
import { patch, create, diff } from 'virtual-dom';
import { render } from './view';
import loggable from './loggable';
import observable from './observable';

const _updateDom_ = (state) => {
    const newTree = render(state);
    const patches = diff(tree, newTree);

    tree = newTree;
    rootNode = patch(rootNode, patches);
};

const INITIAL_STATE = {
    //The state of your application
};

const state = observable({
    target:loggable(INITIAL_STATE),
    listener:_updateDom
});

let tree = _render_(state);
let rootNode = create(tree);

document.body.appendChild(rootNode);

就是这样!我们只是使用render函数来渲染我们的初始DOM,当'state'的变量的值发生改变,dom就会自动更新。你可以在Github(https://francesco-strazzullo.github.io/js-proxies-ui-framework/)上找到一个用这种方式构建的待完成列表的栗子。源代码也在我的GitHub(https://github.com/francesco-strazzullo/js-proxies-ui-framework)账户上。


总结

很明显这不是一个真正的框架,但我认为这个对你自己造轮子而言有非常大的帮助。为了最大限度的降低技术债,在某些场合下我们应该考虑不是使用框架,而是从头开始。这也是我非常喜欢JavaScript生态系统的一个原因。众所周知现在每个星期都会踊跃出一个闪亮的新框架,这不应该成为一种学习疲劳,而是一个学习用新的方式编写和组织代码的大好机会。

来源:http://www.zcfy.cc/article/create-a-fully-reactive-ui-framework-with-javascript-proxies-and-virtual-dom-2520.html

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2017-08-18,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 京程一灯 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
白话虚拟dom
又到了发文章的时候了,今天和大家一起来讨论下虚拟dom,为什么要讨论这个玩意呢,因为现在最流行的两个前端框架都用到了虚拟dom。
挥刀北上
2019/07/19
8050
白话虚拟dom
虚拟DOM及其实现
一篇介绍从各个角度介绍数据变化和UI变化的文章,解析了主流的库是怎么工作的:http://teropa.info/blog/2015/03/02/change-and-its-detection-in-javascript-frameworks.html 分析了过去和现在的JS框架是怎么处理前端数据和页面更新的。
河马嘴不大
2022/12/24
3360
虚拟DOM及其实现
虚拟 DOM 到底是什么?(长文建议收藏)
虚拟 DOM (Virtual DOM )这个概念相信大家都不陌生,从 React 到 Vue ,虚拟 DOM 为这两个框架都带来了跨平台的能力(React-Native 和 Weex)。因为很多人是在学习 React 的过程中接触到的虚拟 DOM ,所以为先入为主,认为虚拟 DOM 和 JSX 密不可分。其实不然,虚拟 DOM 和 JSX 固然契合,但 JSX 只是虚拟 DOM 的充分不必要条件,Vue 即使使用模版,也能把虚拟 DOM 玩得风生水起,同时也有很多人通过 babel 在 Vue 中使用 JSX。
桃翁
2019/07/08
4.2K0
虚拟 DOM 到底是什么?(长文建议收藏)
响应式、模版克隆、Proxy 代理。。。JavaScript 框架工作原理你还了解多少?
我的日常工作是开发 JavaScript 框架 (LWC)。虽然我已经在这个框架上工作了近三年,但我仍然觉得自己是个门外汉。当我阅读大型框架领域的最新动态时,我常常会被自己不知道的事情压得喘不过气来。
unkown
2023/12/11
2310
响应式、模版克隆、Proxy 代理。。。JavaScript 框架工作原理你还了解多少?
Vue 3 响应式基础
reactive 相当于 Vue 2.x 中的 Vue.observable() API ,为避免与 RxJS 中的 observables 混淆因此对其重命名。该 API 返回一个响应式的对象状态。该响应式转换是“深度转换”——它会影响嵌套对象传递的所有 property。
公众号---人生代码
2020/11/11
6890
浅谈前端响应式设计(二)
上一篇文章提到了几种响应式的方案,以及它们的缺点。本文将介绍 Observable以及它的一个实现,以及它在处理响应式时相对于上篇博客中的方案的巨大优势(推荐两篇博客对比阅读)。
有赞coder
2020/08/25
1.1K0
从Lisp到Vue、React再到 Qwit:响应式编程的发展历程
我的旅程始于 Macromedia Flex,后来被 Adobe 收购。Flex 是基于 Flash 上的 ActionScript 的一个框架。ActionScript 与 JavaScript 非常相似,但它具有注解功能,允许编译器为订阅包装字段。我不记得确切的语法了,也在网上找不到太多信息,但它看起来是这样的:
前端小智@大迁世界
2023/04/08
1.8K0
从Lisp到Vue、React再到 Qwit:响应式编程的发展历程
React性能测量和分析
上一篇文章讲了 React 性能优化的一些方向和手段,这篇文章再补充说一下如何进行性能测量和分析, 介绍 React 性能分析的一些工具和方法.
_sx_
2019/08/07
2.4K0
React性能测量和分析
简单实现一个Virtual DOM
前言 之前写过一篇文章为什么使用v-for时必须添加唯一的key?[1],但是解释的不是很深刻,其实真正的原因还需要从Virtual DOM的实现上解释;本篇文章从简单实现一个Virtual DOM入
木子星兮
2020/07/17
8110
简单实现一个Virtual DOM
MobX状态管理:简洁而强大的状态机
MobX 是一个用于构建可响应的数据模型的库,它提供了一种声明式的方式来管理状态,使得数据的变化能够自动更新相关的视图。
天涯学馆
2024/08/16
2860
从零手写 Vue 之响应式系统
之前的文章把响应式系统基本讲完了,没看过的同学可以看一下 vue.windliang.wang/。这篇文章主要是按照 Vue2 源码的目录格式和调用过程,把我们之前写的响应式系统移动进去。
windliang
2022/09/23
3000
从零手写 Vue 之响应式系统
Vue3响应式原理
Proxy可以在目标对象上加一层拦截/代理,外界对目标对象的操作,都会经过这层拦截
scarsu
2020/10/22
7960
Vue3响应式原理
浅谈前端响应式设计(一)
现实世界有很多是以响应式的方式运作的,例如我们会在收到他人的提问,然后做出响应,给出相应的回答。在开发过程中我也应用了大量的响应式设计,积累了一些经验,希望能抛砖引玉。
有赞coder
2020/08/25
6360
茶余饭后聊聊 Vue3.0 响应式数据那些事儿
"别再更新了,实在是学不动了"这句话道出了多少前端开发者的心声,"不幸"的是 Vue 的作者在国庆区间发布了 Vue3.0 的 pre-Aplha 版本,这意味着 Vue3.0 快要和我们见面了。既来之则安之,扶我起来我要开始讲了。Vue3.0 为了达到更快、更小、更易于维护、更贴近原生、对开发者更友好的目的,在很多方面进行了重构:
政采云前端团队
2019/12/20
9630
茶余饭后聊聊 Vue3.0 响应式数据那些事儿
React知识图谱
规则1:不要在循环,条件或嵌套函数中调用 Hook, 确保总是在你的 React 函数的最顶层调用他们。规则2:只能在函数组件或者自定义hook中使用hook函数。
李才哥
2023/06/25
5470
React知识图谱
javascript基础修炼(11)——DOM-DIFF的实现
在上一篇博文《javascript基础修炼(10)——VirtualDOM和基本DFS》中第三节演示了关于如何利用Virtual-DOM的树结构生成真实DOM的部分,原本希望让不熟悉深度优先算遍历的读者先关注和感受一下遍历的基本流程,所以演示用的DOM节点只包含了类名和文本内容,结构简单,在复现DOM结构时直接拼接字符串在控制台显示出来的方式。许多读者留言表示对如何从Virtual-Dom得到真实的DOM节点仍然很困惑。
大史不说话
2018/12/25
6960
JavaScript 是如何工作的:编写自己的 Web 开发框架 + React 及其虚拟 DOM 原理
Proxy 允许我们创建一个对象的虚拟代理(替代对象),并为我们提供了在访问或修改原始对象时,可以进行拦截的处理方法(handler),如 set()、get() 和 deleteProperty() 等等,这样我们就可以避免很常见的这两种限制(vue 中):
前端小智@大迁世界
2019/03/15
1.3K0
JavaScript 是如何工作的:编写自己的 Web 开发框架 + React 及其虚拟 DOM 原理
响应式系统与React - 笔记
2010 年:Facebook 在其 ph 生态中,引入了 xhp 框架,首次引入了组合式组件的思想,启发了后来的 React 的设计。
TagBug
2023/03/17
8860
响应式系统与React - 笔记
MobX 和 React 十分钟快速入门
这个教程将在十分钟内向你详解 MobX 的所有重要概念。MobX 是一个独立的库,但是大部分人将它和 React 共同使用,所以本教程将重点讲解他们的结合使用。
疯狂的技术宅
2019/03/27
1.4K0
MobX 和 React 十分钟快速入门
vue3.0 源码解析二 :响应式原理(下)
上节我们讲了数据绑定proxy原理,vue3.0用到的基本的拦截器,以及reactive入口等等。调用reactive建立响应式,首先通过判断数据类型来确定使用的hander,然后创建proxy代理对象observed。这里的疑惑点就是hander对象具体做了什么?本文我们将以baseHandlers为着手点,继续分析响应式原理。
用户6835371
2021/06/01
5320
vue3.0 源码解析二 :响应式原理(下)
相关推荐
白话虚拟dom
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
本文部分代码块支持一键运行,欢迎体验
本文部分代码块支持一键运行,欢迎体验