Solve vue page modify data without re-rendering problems (view does not refresh after Vue in arrays and objects to change)

vue rendering mechanism and how to solve a variety of methods to modify the data page does not refresh problem

The principles described herein do not speak, they talk about dry easy to learn, (feel able to acquire knowledge, to a small series of trouble to praise!)

First the first point, the data object is a bottom VUE successor, use Object.definePropety, is converted to the setter and getter, therefore, does not support VUE IE8.

1. brief Object.definePropety,

Object.defineProperty(obj, prop, descriptor)
//参数
obj
要在其上定义属性的对象。
prop
要定义或修改的属性的名称。
descriptor
将被定义或修改的属性描述符
  var obj = {}
  Object.defineProperty(obj, 'name', {
    get: function() {
      console.log('我的名字叫'+name);
      return name;
    },
    set: function(value) {
      console.log('你叫'+value)
      name = value;
    }
  });
    obj.name ='张三';//你叫张三
    obj.name//我的名字叫张三

From the above we can simply find. When we assign the name attribute of the object, it triggers set method to get the name attribute is triggered when the get method;

  1. So vue written in the data is that the property can be converted into getter and setter, it is responsive in other words, the definition of other data outside the data is rendered unable to respond, meaning that it will not change the data page refresh, so all the data to be rendered on the page, the data must be written in,

    Does not need to be defined on the this,

    var vm = new Vue({
      data:{
        a:1
      }
    })
    
    // `vm.a` 是响应式的
    
    vm.b = 2
    // `vm.b` 是非响应式的
    

    3. A brief introduction is over, let's enumerate course, the above is also an example of a few do not refresh

    The first: to modify an attribute of an object

    vue will only property already declared in the data changed in response, no declaration is not responding

    <template>
      <div>
          <div v-for='item in list'>{{item}}</div>
          <button @click='click'>改变</button>
          <button @click='hadelClick'>解决方法</button>
      </div>
    </template>
    <script>
      export default({
        data(){
          return{
            list:{a:'a',b:'b'},
          }
        },
        methods: {
              click() {
              //  未声明不触发渲染
               this.list.c='c'
    
              },
              hadelClick(){
                // 解决方法,使用vue提供的$set方法来触发渲染
                this.$set(this.list,'d','d')
              }
            }
      })
       
    </script>
    

    Of course, if we want to add more properties, may be used Object.assign () for all the enumerated attribute values ​​are copied from one or more source object to the target object, the target object and returns. (It simply is merged into the first parameter)

    this.list = Object.assign({},this.list,{c:'c',d:'d'})
    

    The second: an attribute modify an array of objects

    <template>
      <div>
          <div v-for='item in list'>{{item.a}}</div>
          <button @click='click'>改变</button>
          <button @click='hadelClick'>解决方法</button>
      </div>
    </template>
    <script>
      export default({
        data(){
          return{
            list:[{a:'vue'},{a:'react'},{a:'js'}],
          }
        },
        methods: {
              click() {
                //想这样直接给数组中的某一个对象直接赋值,是无法动态渲染的(即改变了数据,页面不渲染)
                this.list[0] = {a:'css'} //页面不渲染
                console.log(this.list)  //[{a:'css'},{a:'react'},{a:'js'}]
              },
              hadelClick(){
                // 解决方法,使用vue提供的$set方法来触发渲染
                this.$set(this.list[1],'a','css')
                console.log(this.list)//[{a:'css'},{a:'css'},{a:'js'}]
              }
            }
      })
       
    </script>
    

    Of course, the foregoing spoken, VUE data will traverse the data, to convert the object into a setter and getter. Therefore, the array is no exception, the above operation

    改成:
    click(){
    	this.list[0].a = css //依旧能够触发setter。实现数据重新渲染
        }
    }
    

    In vue in more of a refresh operation of the array is not, is through an index assignment, one is to modify the array length, how to solve it?

    vue official also gave methods

    API array, capable of changing the original array can trigger an update;

    • push()
    • pop()
    • shift()
    • unshift()
    • splice()
    • sort()
    • reverse()

    The second is to return a new array, the array of fundamental change has occurred in the referenced address, this assignment is to trigger updates (this is the idea of ​​treatment is not refreshed, is to change the reference address, reassigned triggered update)

    Simply put, the array is an array with API changes directly receiving the original array,

      <template>
      <div>
          <div v-for='item in list'>{{item.a}}</div>
          <button @click='click'>改变原数组</button>
          <button @click='hadelClick'>不改变原数组</button>
      </div>
    </template>
    <script>
      export default({
        data(){
          return{
           list:[{a:'vue'},{a:'react'},{a:'js'}],
          }
        },
        methods: {
              click() {
               //改变数组刷新页面
                  this.list.push({a:'css'})
              },
              hadelClick(){
            //重新赋值刷新页面      
                this.list =  this.list.map(item=>{
                      item.a = 'css'
                      return item
                    })
            }
      })
       
    </script>
    

    Finally, providing Solutions (above all else fails words)

    Objects and arrays are passed by reference, to become the new array, to accept, it is necessary to change the source,

    The first

    let arr = []//新数组
    this.list.forEach(item=>{  //需要渲染的数组
        //执行你的操作,最后用放到arr中
        arr.push(item)
    })
    this.list = arr //相当于返回一个新数组可以触发渲染
    

    The second

    //想要直接改变渲染数组中的数据,但没有渲染
    //解决方法:
    let arr = this.list.slice(0);//深拷贝,(等价一个新的数组)
    arr.forEach(item=>{
        //执行你的操作
    })
    //赋值操作
    this.list =  arr
    

Of course, here is a brief introduction, details about a deep copy, see another blog post
js array of deep copy Detailed
above if unable to perform, but your data is missing the real modification, you can use this. $ ForceUpdate () method ( force a refresh)

//this.$forceUpdate();//强制刷新


<template>
  <div>
      <div v-for='item in list'>{{item.a}}</div>
      <button @click='click'>改变</button>
      <button @click='hadelClick'>解决方法</button>
  </div>
</template>
<script>
  export default({
    data(){
      return{
        list:[{a:'vue'},{a:'react'},{a:'js'}],
      }
    },
    methods: {
          click() {
            this.list[0] = {a:'css'} //页面不渲染
            console.log(this.list)  //[{a:'css'},{a:'react'},{a:'js'}]
          },
          hadelClick(){
            this.list[0] = {a:'css'} //页面不渲染
            console.log(this.list)  //[{a:'css'},{a:'react'},{a:'js'}]
              this.$forceUpdate();//强制刷新
          }
        }
  })
   
</script>
Published 52 original articles · won praise 82 · views 30000 +

Guess you like

Origin blog.csdn.net/marendu/article/details/93492642