MVVM思想解题,vue响应式数据底层实现原理

前言

今天和大家聊一聊ref,响应式数据的底层实现原理。

vue中template是我们的视图层也就是views,每一个views都对应一个组件,此时我们的数据模型Model的url就应该从/去到我们的/about(例如切换了首页到关于页),此时显示的组件就发生了改变

vue中就是这种开发思想,把视图views和model结合起来(VM)总的结合来说就是MVVM开发框架

回顾DOM编程

没有vue的时候我们的dom编程,操作dom元素,获取到一个dom然后做...事情,是这样的

html 复制代码
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Vue MVVM开发框架</title>
</head>

<body>
    <span id="container">1</span>
    <button id="btn">点击加1</button>
    <script>
        const oSpan = document.querySelector("#container")
        const oBtn = document.querySelector("#btn")

        oBtn.addEventListener("click", function () {
            oSpan.innerHTML = parseInt(oSpan.innerHTML) + 1
        })
    </script>
</body>

</html>

获取到dom元素,添加绑定事件,点击做加1。很明显的发现,在这种开发模式下,完全涉及不到model的概念,现在的数据源纯粹来自于页面中的1,但是页面中到底显示的数据是多少他应该是一个响应式的,需要有一个model来承接

接下来我们想转换一下思想,从原生的dom编程走向vue,用vue的MVVM思想来完成这个事情应该如何完成呢?

MVVM开发思想

首先我们就需要准备一个数据源,定义一个obj对象(json对象),接下来我们的业务就是,当obj中的value发生改变时,页面就应该更新

es5中有一个监控对象,它可以让我们定义一个对象上的属性defineProperty

js 复制代码
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Vue 最受欢迎的MVVM开发框架</title>
</head>

<body>
    <span id="container">1</span>
    <button id="btn">点击加1</button>
    <script>
        const oSpan = document.querySelector("#container")
        const oBtn = document.querySelector("#btn")

        var obj = {
            value: 1
        }

        var value = 1
        oBtn.addEventListener("click", function () {
            obj.value++
        })

        // 监控对象 es5
        Object.defineProperty(obj, 'value', {
            get: function () {
                return value
            },
            set: function (newValue) {
                value = newValue
                console.log('点击了按钮...');
                oSpan.innerHTML = newValue
            }
        })
    </script>
</body>

</html>

可以看见,当我们点击按钮,obj对象上的value属性值就会发生改变,并且通过es5中的监控对象监控obj,当其值发生改变,我们就打印点击了按钮...

  • 既如此,我们就可以把这个newValue给到页面重新渲染
  • 这样我们就做到了每次我们的操作,都是操作模型层数据,现在的dom编程就直接被封装到了defineproperty的内部。

理解了这些,接下来看看我们的代码,你就能够理解vue中任何一个响应式对象底层是怎么打造的了

html 复制代码
<!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>
    <span id="container">1</span>
    <button id="btn">点击加1</button>
    <script>
        // 不用dom操作,针对数据状态做业务
        var obj = {
            value: 1,
        }
            ; (function () {
                function watch(obj, key, func) {
                    console.log('监听数据');
                    var value = obj[key]
                    // 数据拦截
                    Object.defineProperty(obj, key, {
                        get: function () {
                            return value
                        },
                        set: function (newValue) {
                            value = newValue
                            func(newValue)
                        }
                    })
                }
                this.watch = watch
            })()

        // 数据可以被监听
        watch(obj, 'value', function (newValue) {
            document.getElementById('container').innerHTML = newValue
        })

        document.getElementById('btn').onclick = function () {
            obj.value++
        }
    </script>
</body>

</html>
  1. HTML 结构 : 页面包含一个 span 元素和一个 button 元素。span 元素用于显示数据,而 button 元素用于触发数据更新。

  2. JavaScript 实现:

    • 定义了一个对象 obj,它有一个属性 value,初始值为 1
    • 使用立即执行函数表达式(IIFE)定义了一个 watch 函数,该函数接受三个参数:要观察的对象、要观察的键以及当值改变时调用的回调函数。
    • watch 函数内部,使用了 Object.defineProperty 方法来对 obj 对象的 key 属性进行 getter 和 setter 拦截。getter 返回当前值,setter 更新值并调用回调函数。
    • watch 函数被调用来观察 obj.value 的变化,并在值改变时更新 DOM。
    • button 的点击事件处理器调用了 obj.value++,这将触发 watch 函数中的 setter,从而更新 DOM。
  3. 响应式原理 : 当你点击按钮时,obj.value 的值会增加,这触发了 watch 函数中 set 方法的执行,set 方法不仅更新了 obj.value 的值,还调用了回调函数,这个回调函数负责更新 DOM,使 span 元素的内容与新的 obj.value 值同步。

  4. 与 Vue.js 的对比 : Vue.js 的响应式系统更复杂,它使用了依赖收集和调度机制。Vue 使用了 Observer 类来递归地遍历对象,将其所有属性转换为 getter/setter。同时,Vue 使用 Watcher 类来连接数据和视图,它会在数据变化时触发视图更新。此外,Vue 还有组件系统、模板编译器等高级特性

小结

目前我们就做了一个简单的响应式数据的打造原理,更加深层的东西将在以后逐步更新,创作不易,望多支持,如有错误,欢迎指正。

相关推荐
zhougl9962 小时前
html处理Base文件流
linux·前端·html
花花鱼2 小时前
node-modules-inspector 可视化node_modules
前端·javascript·vue.js
HBR666_2 小时前
marked库(高效将 Markdown 转换为 HTML 的利器)
前端·markdown
careybobo3 小时前
海康摄像头通过Web插件进行预览播放和控制
前端
TDengine (老段)4 小时前
TDengine 中的关联查询
大数据·javascript·网络·物联网·时序数据库·tdengine·iotdb
杉之5 小时前
常见前端GET请求以及对应的Spring后端接收接口写法
java·前端·后端·spring·vue
喝拿铁写前端5 小时前
字段聚类,到底有什么用?——从系统混乱到结构认知的第一步
前端
再学一点就睡5 小时前
大文件上传之切片上传以及开发全流程之前端篇
前端·javascript
木木黄木木6 小时前
html5炫酷图片悬停效果实现详解
前端·html·html5
请来次降维打击!!!6 小时前
优选算法系列(5.位运算)
java·前端·c++·算法