likes
comments
collection
share

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

作者站长头像
站长
· 阅读数 8

前言

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

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

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

回顾DOM编程

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

<!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

<!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中任何一个响应式对象底层是怎么打造的了

<!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 还有组件系统、模板编译器等高级特性

小结

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

转载自:https://juejin.cn/post/7390634729254256655
评论
请登录