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)
},
```js

这样就同步了

但我们在往深了一层呢?

这里就有一个面试题了

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/12/2 01:46
Contributors: qdleader
qdleader
本站总访问量 129823次 | 本站访客数 12人