解决vue修改数据页面不重新渲染问题(Vue中数组和对象更改后视图不刷新)

vue渲染机制和如何解决数据修改页面不刷新问题的多种方法

本文不讲原理,只讲干货易懂易学,(感觉能学到知识,麻烦给小编来个赞!)

首先 第一点,vue底层是 将data对象传人,使用Object.definePropety,转换为getter和setter,所以,vue不支持IE8.

1.简单介绍一下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//我的名字叫张三

从上述我们可以简单发现。当我们对这个对象的name属性赋值的时候,就会触发set方法,获取name属性的时候就会触发get方法;

  1. 因此在vue中写在data中的属性是是可以转换成getter和setter,换一句话就是响应式的,其他定义在data之外的数据,是无法响应的渲染,意思就是改变数据页面也不会刷新,所以一切要渲染到页面上的数据,必须写在data中,

    不需要的,可以定义在this上,

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

    3.简单介绍完了,我们来列举几个不刷新的实例当然上述也是一种

    第一种:修改对象的某一属性

    vue只会将已经在data中声明的属性变为响应,没有声明的是不响应的

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

    当然如果我们要添加多个属性,可以使用 Object.assign() 用于将所有可枚举属性的值从一个或多个源对象复制到目标对象,并返回目标对象。(简单说就是合并到第一个参数中)

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

    第二种:修改数组对象的某一属性

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

    当然前文讲过,vue会遍历data中的数据,将对象转换成setter和getter。所以数组中的也不例外,所以上述操作

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

    在vue中更多的是数组的操作不刷新,一种是通过索引赋值,一种是修改数组长度,如何解决呢?

    vue官方也给了方法

    数组的API,中能够改变原始数组的都能触发更新;

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

    第二种是返回一个新数组的,这种数组在引用地址上已经发生根本改变,这样的赋值操作是能触发更新的(这是处理不刷新的思路,就是改变引用地址,重新赋值触发更新)

    简单说,用数组的API就是直接用原数组接收改变的数组,

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

    最后提供解决思路(以上都搞不定的话)

    对象和数组都是引用传递,要变成新数组,来接受,就需要改变源,

    第一种

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

    第二种

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

当然这里只是简单介绍了,有关深拷贝的详细介绍,请参看另一篇博文
js数组深拷贝详解
上述如果都无法执行,但你的数据缺实修改了,可以使用this.$forceUpdate()方法 (强制刷新)

//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>
发布了52 篇原创文章 · 获赞 82 · 访问量 3万+

猜你喜欢

转载自blog.csdn.net/marendu/article/details/93492642