MVVM数据双向绑定的理解和简单实现

MVVM基本理解

  • MVVM(Model-View-ViewModel)是一种设计思想,主要实现的效果是数据改变视图会跟着变,视图改变数据也会修改。
  • MVVM将数据、视图、业务逻辑抽离出来;数据(M)定义页面需要展示的内容,视图(V)负责渲染页面,业务逻辑(VM)是核心用来处理视图和数据(属于视图和数据之间的桥梁)。

MVVM模式实现(Object.defineProperty())

通过一个例子解释

  • 现在需要实现一个功能,一个输入框和一个p标签,输入框输入什么内容,p标签就实时的展示什么内容。
//首先想到的实现方式
//缺点:只有input事件中修改了data.value属性,页面会重新渲染;当在其他事件中修改了data.value属性就不会重新渲染页面,需要重新调用update方法才行
<body>
  <input id="input" type="text" value="">
  <p id="show"></p>
  <script>
    let data = {
      value: '123'
    }
    let inputDom = document.getElementById('input')
    let showDom = document.getElementById('show')

    function update() {
      show.innerHTML = data.value
      inputDom.value = data.value
    }
    update()
    inputDom.addEventListener('input', () => {
      data.value = inputDom.value
      update()
    })
  </script>
</body>
//使用Object.defineProperty对data的value属性进行劫持,定义get和set属性,当对data.value进行设置时,会走set方法,可以在此方法中调用update()更新页面
//
  <script>
    let data = {
      value: '123'
    }
    let inputDom = document.getElementById('input')
    let showDom = document.getElementById('show')

    function update() {
      show.innerHTML = data.value
      inputDom.value = data.value
    }
    update()
    inputDom.addEventListener('input', () => {
      data.value = inputDom.value
    })
    let dataVal=data.value
    Object.defineProperty(data, 'value', {
      get() {
        return dataVal
      },
      set(newVal) {
        dataVal = newVal
        update()
      }
    })
  </script>

//将整个data定义成响应式数据(对定义响应式数据方法进行简单封装)
//如果数据中嵌套对象,需要递归处理嵌套数据
<body>
  <input id="input" type="text" value="">
  <p id="show"></p>
  <p>用户名:<span id='userName'></span></p>
  <p>年龄:<span id='userAge'></span></p>
  <script>
    let data = {
      value: '123',
      user:{
        name:"zhangsan",
        age:18
      }
    }
    let inputDom = document.getElementById('input')
    let showDom = document.getElementById('show')

    function update() {
      show.innerHTML = data.value
      inputDom.value = data.value
      userName.innerHTML=data.user.name
      userAge.innerHTML=data.user.age
    }
    update()
    inputDom.addEventListener('input', () => {
      data.value = inputDom.value
    })

    function _toString(obj) {
      return Object.prototype.toString.call(obj).slice(8, -1)
    }

    function observer(data) {
      for (let key in data) {
        let oldVal = data[key]
        if (_toString(oldVal) === 'Object') {
        //当数据中嵌套对象时需要递归处理
          observer(oldVal)
        }
        defineReactive(data, key, oldVal)
      }
    }

    function defineReactive(data, prop, oldVal) {
      Object.defineProperty(data, prop, {
        get() {
          return oldVal
        },
        set(newVal) {
          if (oldVal !== newVal) {
            oldVal = newVal
            update()
          }
        }
      })
    }
    observer(data)
    setTimeout(() => {
      data.user.name='lisi',
      data.user.age=20
      //一秒钟之后将看到页面数据会重新渲染
    }, 1000);
  </script>
</body>
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值