深入理解响应式原理案例

  1. 如果一个属性你在data的时候没有初始化,那么后面不能直接在已经创建的实例上动态添加新的属性,否则这个新添加的属性就不会是响应式的。
ar vm = new Vue({
  data:{
    a:1
  }
})

// `vm.a` 是响应的

vm.b = 2
// `vm.b` 是非响应的
  1. 通过请求拿到的原始数据,如果你想给它动态添加一个属性,正常情况下它也不会是响应式的,比如原始数据如下
{
  "status": 200,
  "message": "",
  "cartList": [
    {
      "shopTitle": "寻找田野",
      "shopId": 75960,
      "goodsList": [
        {
          "id": 73835,
          "img": "http://dummyimage.com/90x90/f27988",
          "number": 2,
          "price": 75,
          "sku": "全网通,玫瑰金,3+32G",
          "title": "VIVO-Y66 全网通/移动版 3+32GB"
        },
        {
          "id": 75572,
          "img": "http://dummyimage.com/90x90/79abf2",
          "number": 2,
          "price": 31,
          "sku": "全网通,香槟金,3+32G",
          "title": "VIVO-Y66 全网通/移动版 3+32GB"
        }
      ]
    },
    {
      "shopTitle": "猫咪森林",
      "shopId": 51336,
      "goodsList": [
        {
          "id": 57979,
          "img": "http://dummyimage.com/90x90/cef279",
          "number": 9,
          "price": 44,
          "sku": "全网通,玫瑰金,3+32G",
          "title": "VIVO-Y66 全网通/移动版 3+32GB"
        }
      ]
    },
    {
      "shopTitle": "老爹果园",
      "shopId": 94835,
      "goodsList": [
        {
          "id": 44271,
          "img": "http://dummyimage.com/90x90/f279f2",
          "number": 5,
          "price": 105,
          "sku": "全网通,香槟金,3+32G",
          "title": "VIVO-Y66 全网通/移动版 3+32GB"
        },
        {
          "id": 81594,
          "img": "http://dummyimage.com/90x90/79f2ce",
          "number": 8,
          "price": 39,
          "sku": "全网通,玫瑰金,3+32G",
          "title": "VIVO-Y66 全网通/移动版 3+32GB"
        }
      ]
    }
  ]
}

通过axios拿到数据通过vue渲染到dom上

<div class="js-shop-list shop-list" v-for="(shop,index) in list">
  <ul class="js-list block block-list block-list-cart border-0">
    <li class="block-item block-item-cart" v-for="(good,goodIndex) in shop.goodsList">
       <div class="check-container" @click="checkedGood(good)">
         <span class="check" :class="{checked:good.checked}"></span>
       </div>
    </li>
  </ul>
</div>
let app = new Vue({
    el: '#app',
    data: {
        list: null
    },
    created(){
        this.getLists()
    },
    methods: {
        getLists(){
            axios.get(url.cartList)
            .then((res)=>{
                this.list = res.data.cartList
                this.list.forEach(shop => {
                    shop.goodsList.forEach(good=>{
                        good.checked = true
                    })
                });
            })
        },
        checkedGood(good){
            good.checked = !good.checked
            console.log(good.checked)
        }
    },
})

显示效果如下:



因为原始数据里面没有checked这个属性,所以你直接将原始数据赋给了data里的list,它就等同于第一条的例子,在实例创建完后直接给good加一个checked属性,这时候你点击选中按钮通过checkedGood方法更改选中状态,你会发现虽然后台显示的值已经在true和false之间切换了,但是vue里的数据和视图显示并没有改变,也就是没有发生响应式。

点击选中按钮,控制台打印出每次的checked的值都在变,但是视图显示一直是选中状态,不管你怎么点击按钮都是选中状态,视图没有改变


vue里的数据也一直没有变化过


针对上面的两个问题有两种解决办法:

  1. 针对第一中简单的数据添加可以直接使用实例的set方法
this.$set(this.someObject,'b',2)
  1. 针对第二种复杂结构的原始数据,可以先对原始数据操作最后再赋值给vue实例
getLists(){
  axios.get(url.cartList)
  .then((res)=>{
      //将原始数据res.data.cartList赋值给一个变量
      let list = res.data.cartList
      //然后对这个变量直接进行动态属性添加
      list.forEach(shop => {
          shop.goodsList.forEach(good=>{
              good.checked = true
          })
      });
      //最后再赋值给实例里的list
      this.list = list
  })
}

这样就可以实现数据和视图的同步更改了,也就是可以响应了

©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容