前言
今天和大家聊一聊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>- 
HTML 结构 : 页面包含一个 span元素和一个button元素。span元素用于显示数据,而button元素用于触发数据更新。
- 
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。
 
- 定义了一个对象 
- 
响应式原理 : 当你点击按钮时, obj.value的值会增加,这触发了watch函数中set方法的执行,set方法不仅更新了obj.value的值,还调用了回调函数,这个回调函数负责更新 DOM,使span元素的内容与新的obj.value值同步。
- 
与 Vue.js 的对比 : Vue.js 的响应式系统更复杂,它使用了依赖收集和调度机制。Vue 使用了 Observer类来递归地遍历对象,将其所有属性转换为 getter/setter。同时,Vue 使用Watcher类来连接数据和视图,它会在数据变化时触发视图更新。此外,Vue 还有组件系统、模板编译器等高级特性
小结
目前我们就做了一个简单的响应式数据的打造原理,更加深层的东西将在以后逐步更新,创作不易,望多支持,如有错误,欢迎指正。