首页 > 其他分享 >第142篇:原生js实现响应式原理

第142篇:原生js实现响应式原理

时间:2024-03-11 16:48:50浏览次数:26  
标签:原生 function 142 Dep Watcher input message js data

好家伙,狠狠地补一下代码量

 

本篇我们来尝试使用原生js实现vue的响应式

使用原生js,即代表没有v-bind,v-on,也没有v-model,所有语法糖我们都用原生实现

 

1.给输入框绑个变量

<body>
    <input id="input_1"></input>
</body>
<script>
    let datavalue = "66666"
    const input_1 = document.getElementById("input_1")
    input_1.value = datavalue
    input_1.addEventListener('input', function(e) {
        datavalue = e.target.value
        console.log(datavalue)
    })

    
</script>

 

诶,似乎这样就完成了

但我们要让他更像vue

 

2.加上Dep,Watcher

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <input id="input_1"></input>
</body>
<script>
    // 模拟 Vue 实例
    let data = {
        message: 'Hello'
    };
    const input_1 = document.getElementById("input_1")
    input_1.value = data.message
    input_1.addEventListener('input', function (e) {
        e.target.value = data.message
        console.log(datavalue)
    })

    function defineReactive(obj, key, value) {
        let dep = new Dep(); // 依赖容器

        Object.defineProperty(obj, key, {
            get: function () {
                if (Dep.target) {
                    dep.addDep(Dep.target);
                }
                return value;
            },
            set: function (newValue) {
                value = newValue;
                dep.notify();
            }
        });
    }

    // 依赖容器
    function Dep() {
        this.deps = [];

        this.addDep = function (dep) {
            this.deps.push(dep);
        };

        this.notify = function () {
            this.deps.forEach(dep => {
                dep.update();
            });
        };
    }

    Dep.target = null;

    // Watcher
    function Watcher(updateFunc) {
        this.update = updateFunc;
    }

    // 初始化响应式数据
    defineReactive(data, 'message', data.message);

    // 模拟 Watcher
    let watcher = new Watcher(function () {
        console.log('Message updated:', data.message);
        input_1.value = data.message
    });

    // 模拟视图更新
    Dep.target = watcher;
    data.message; // 触发依赖收集
    setTimeout(() => {
        data.message = '6666'; //触发更新
    }, 1000)
</script>

</html>

 

3.效果图

 

4.代码解释

  1. defineReactive 函数用来定义一个响应式属性,其中通过 Object.defineProperty 给属性添加 getter 和 setter 方法。在 getter 方法中,会判断 Dep.target 是否存在,如果存在则将当前 Watcher 对象添加到依赖容器 Dep 中;在 setter 方法中,更新属性的值,并通过依赖容器 Dep 的 notify 方法通知所有依赖的 Watcher 进行更新。

  2. Dep 函数是一个简单的依赖容器,其中包含了一个 deps 数组用来存储依赖(Watcher),addDep 方法用来添加依赖,notify 方法用来通知所有依赖进行更新。

  3. Watcher 函数用来创建 Watcher 对象,其中包含一个 update 方法,用来在属性发生变化时执行相应的更新操作。

  4. 在初始化响应式数据时,调用 defineReactive 函数定义了一个名为 message 的响应式属性。

  5. 创建了一个 Watcher 对象 watcher,并在其构造函数中定义了一个回调函数,用来在属性变化时输出消息并更新视图。

  6. 将 watcher 赋值给 Dep.target,然后访问 data.message,触发依赖收集,将 watcher 添加到依赖容器 Dep 中。

 

5.补充

一张响应式原理图

 

标签:原生,function,142,Dep,Watcher,input,message,js,data
From: https://www.cnblogs.com/FatTiger4399/p/18066047

相关文章

  • jsoncpp编译错误
    在Ubuntu下面编译jsoncpp的代码时候,爆出大量错误,/usr/include/x86_64-linux-gnu/sys/cdefs.h:41:20:error:missingbinaryoperatorbeforetoken"("#if__GNUC_PREREQ(4,6)&&!defined_LIBC^/usr/include/x86_64-linux-gnu/sys/cdefs.......
  • Vue.js 与 ViewDesign:为企业级 Web 应用提供高效可靠的解决方案
    Vue.js与ViewDesign:为企业级Web应用提供高效可靠的解决方案在当今瞬息万变的商业环境中,企业需要高效、稳定且易于维护的Web应用程序来支持其日常运营和业务发展。幸运的是,Vue.js和ViewDesign的强大组合为开发人员提供了构建复杂企业级Web应用程序的完美解决方案。......
  • JS正则常用校验
    手机号(mobilephone)中国(严谨),根据工信部2019年最新公布的手机号段1constreg=/^(?:(?:\+|00)86)?1(?:(?:3[\d])|(?:4[5-79])|(?:5[0-35-9])|(?:6[5-7])|(?:7[0-8])|(?:8[\d])|(?:9[189]))\d{8}$/;2conststr="19119255642";3console.log(`校验${reg.test(str)?......
  • js获取URL参数
    1.正则functionqueryURLparamsRegEs5(url){letobj={}letreg=/([^?=&]+)=([^?=&]+)/g//使用arguments伪数组url.replace(reg,function(){//arguments[1]是参数的key;arguments[2]是参数的valueobj[arguments[1]]=arguments[2]......
  • python json格式转url参数&分割, url参数转json格式
    前言全局说明一、json格式转url参数&分割>>>fromurllib.parseimporturlencode>>>params={'user':'admin','pwd':'123456'}>>>print(urlencode(params))二、url参数转json格式>>>importj......
  • fabricjs怎么添加网格线
    html文件:1<canvasid="c"width="600"height="400"></canvas>css文件:1canvas{2border:1pxsolidlightgrey;3} javascript文件1varcanvas=newfabric.Canvas('c',{2selection:false3});4v......
  • Dynamics CRM 2013 常用JS脚本
    Xrm.Page.data获取记录的主键Id的值(getId)varId=Xrm.Page.data.entity.getId();获取记录的表的逻辑名称(getEntityName)varentityName=Xrm.Page.data.entity.getEntityName();获取引用记录的查找值(getEntityReference)varerEntity=Xrm.Page.data.entity.getEnt......
  • jsPlumb导航器
    开源项目地址:https://gitee.com/easyxaf/jsplumb-navigator前言jsPlumb可用于连接DOM元素,它不依赖框架,所以与主流框架都可以无缝的集成。但比较遗憾的是社区版中没有平移、缩放等功能,如果用它来开发工作流等项目,用户体验会大打折扣。我的项目是用Blazor开发的,在比较了多款开源流......
  • js 实现深拷贝/深复制
    //深拷贝constdeepClone=(obj)=>{vartarget={};for(varkeyinobj){if(Object.prototype.hasOwnProperty.call(obj,key)){if(typeofobj[key]==='object'){target[key]=deepClone(obj[key])......
  • Nestjs系列 Nestjs基础(四)
    Nest中的middlewaremiddware基础用法已经在Nest的AOP架构章节中存在。此次记录middleware的更详细用法新建项目,然后创建一个middleware模板nestgmiddlewaretest--no-spec--flat可以看到此时的req和res都是any,可以对其进行明确的类型标注,express就从......