Hi FE !
Ai
git
前端面试题
前端小tip
  • vite
  • webpack
npm
  • vue2
  • vue3
react
GitHub
Ai
git
前端面试题
前端小tip
  • vite
  • webpack
npm
  • vue2
  • vue3
react
GitHub
  • V008-vue中数据变化页面并不变化问题

V008-vue中数据变化页面并不变化问题

由于我们vue2中的数据双向绑定时候经常遇到这种,数据变化了,视图没有变化的情况,这是为什么呢?怎么解决呢?

探索1
data() {
  obj1:{}
}



btn1() {
     this.obj1.name = '123'    
 },          
 btn2() {
     this.obj1.name = '变了呀'    
 },         
<div @click="btn1">按钮1</div>

<div @click="btn2">按钮2</div>

<div>{{obj1}}</div>

当点击按钮1和按钮2时候,页面上的obj1是一点没有变化的,也就是经典的那种数据变了,页面没有变。

但是,当我们给obj1一个初始属性name时候,在改变name,就会发现,页面还是同步的。

探索2
data() {
  obj1:{
    name:'我是初始值'
  }
}
btn1() {
     this.obj1.name = '123'    
 },          
 btn2() {
     this.obj1.name = '变了呀'    
 },         
<div @click="btn1">按钮1</div>

<div @click="btn2">按钮2</div>

<div>{{obj1}}</div>

我们继续探索

我们再加深一层

探索3
data() {
  obj1:{
    name:{
      age:12
    }
  }
}
btn1() {
     this.obj1.name.age = '123'    
 },          
 btn2() {
     this.obj1.name.age = '变了呀'    
 },         
<div @click="btn1">按钮1</div>

<div @click="btn2">按钮2</div>

<div>{{obj1}}</div>

发现这样也是变了的

所以我们可以得出结论

只有在data里初始化的数据才是响应的,Vue不能检测到对象属性的添加或删除,没有在data里声明的属性不是响应的。跟对象的层级多少也没有关系的

明白怎么造成的了,那咋解决呢?

比如这个改变了这个newArr的数据

newArr:[]

我们直接赋值

let arr = [{name:'前端架构师'}]

this.newArr[0].newList = arr

会发现数据变了,页面没有变

有几种方法来解决这个问题

#方法1. 用 Object.assign

this.newArr[0].newList = arr
this.newArr = Object.assign({},this.newArr)

用Object.assign 追加属性

this.newArr = Object.assign({}, this.newArr, {
  age: 12,
  grade: '100'
})

这个Object.assign并不是深拷贝,只复制了一层。。

eg1:

data() {
  obj1:{}
}
btn2() {
    this.obj1.page = 1
    this.obj1 = Object.assign({},this.obj1)
    console.log(this.obj1)
},

这样就同步了

但我们在往深了一层呢?

这里就有一个面试题了

let obj = {
  a:1,
  b:{
    x:1,
    y:1,
  }
}


let obj1 = Object.assign({}, obj)
obj.a= 2

console.log(obj.a)  // 2
console.log(obj1.a)  // 1
说明第一层拷贝没问题

obj.b.x = 2
console.log(obj.b.x)  //2
console.log(obj1.b.x)  //2

说明深层没有拷贝

#方法2. 用 this.$set

let arr = [{name:'前端架构师'}]
this.$set(this.newArr[index],'newList',arr)


或
Vue.set(this.newArr[index],'newList',arr)

有同学说,姨?我怎么用this.$set改了也不管用呢

那是因为

data() {
  obj1:{

  }
}


btn2() {
  this.obj1.name = '小明'
  this.$set(this.obj1,name,'小明')
}

你用this.$set之前你是不是还对相同的属性做了赋值操作,把this.obj1.name = '小明'这个去掉就生效了。

3.生成新数组的方法

数组数据变动,使用某些方法操作数组,变动数据时,有些方法无法被vue监测

push(),pop(),shift(),unshift(),splice(),sort(),reverse()可被vue检测到 filter(), concat(), slice()。这些不会改变原始数组,但总是返回一个新数组。当使用非变异方法时,可以用新数组替换旧数组。

vue不能检测以下变动的数组:
1、当你利用索引直接设置一个项时,vm.items[indexOfItem] = newValue
2、当你修改数组的长度时,例如: vm.items.length = newLength

比如你在监听不到变化的数组后面加个concat

arr 是那个变了数组

arr.concat([]);

4.this.$forceUpdate()

vue多层循环,动态改变数据后渲染的很慢或者不渲染 可在动态改变数据的方法,第一行加上

this.$forceUpdate();

5. 异步更新队列 this.$nextTick()

数据第一次获取到了,也渲染了,但是第二次之后数据只有在再一次渲染页面的时候更新,并不能实时更新。

Vue 异步执行 DOM 更新。只要观察到数据变化,Vue 将开启一个队列,并缓冲在同一事件循环中发生的所有数据改变。如果同一个 watcher 被多次触发,只会被推入到队列中一次。

data() {
  obj:'未更新'
}
btn2() {
  this.obj = '已更新'
  console.log(this.$el.textContent)  //未更新
  this.$nextTick(() => {
      console.log(this.$el.textContent)  //已更新
  })
}

因为 $nextTick()返回一个 Promise 对象,所以上面写法可以优化一下

async btn2() {
  this.obj = '已更新'
  console.log(this.$el.textContent)  //未更新

  await this.$nextTick()
  console.log(this.$el.textContent)  //已更新
}
Edit this page
最近更新: 2025/6/27 02:24
Contributors: qdleader
qdleader
本站总访问量 129823次 | 本站访客数 12人