首页 > 其他分享 >Vue监测数据改变的原理

Vue监测数据改变的原理

时间:2023-03-14 18:32:22浏览次数:64  
标签:监测数据 Vue name age sex student 原理 data


目录

​​1.Vue数据更新却监测不到的问题​​

​​2.Vue监测数据改变的原理​​

​​2.1 Vue是如何监测对象中数据的改变的​​

​​2.2 简单模拟Vue监视属性的代码​​

​​2.3 Vue.set()方法的使用​​

​​2.4 Vue是如何监测数组中数据的改变的​​

​​3.总结​​


我们之前都用过好多Vue的配置项以及插值语法。比如我们在data配置项中配置一个name,然后在页面上再写个插值语法 {{name}} ,我们都知道,当我们把data中的name改掉以后,那么页面上插值语法中的name也会自动更新。这里的前因后果是因为,我们改了data中的数据被Vue监测到了,随后Vue才将插值语法中的name进行了改变。那么我们这里要研究的就是Vue是如何监测到我们改掉了data中的数据的,并且拿到我们改变的最新值的。

这个时候有人说了,这难道不是通过Vue的监视属性watch实现的吗?这里就要注意了,我们通过watch可以监测到某一个属性的变化这只是表象,Vue拿到这个watch之后具体得怎么写才能监视呢?那就又涉及到底层原理了。

所以其实是这么回事,Vue默认就有一个监视,这个监视是用来干嘛的?就是用来当我们改掉数据的时候,去帮我们更新页面上用到这个数据的地方。而Vue还给我们提供了一个watch配置项也叫监视,但这个watch是给程序员使用的。那么无论是watch,还是Vue默认的监视,它里面的原理都是一样的,他两底层用的是一套类似的逻辑。

1.Vue数据更新却监测不到的问题

Vue监测数据改变的原理我们必须得懂,要不然在未来的某一天,当我们写了一个我们认为很正常的一段代码,可是无论我们怎么改这个数据,Vue都监测不到。

接下来我们就暴露一下这个问题,就是看起来很正常,但是改完数据Vue却监测不到的问题。

我们下面实现一个需求,点击按钮,更新人员中马冬梅的信息

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>列表排序</title>
<!--引入Vue-->
<script type="text/javascript" src="../js/vue.js"></script>
<style>

</style>
</head>
<body>
<!--准备好一个容器-->
<div id="root">
<!-- 遍历列表 -->
<h2>人员列表</h2>
<button @click="updateMei">更新马冬梅的信息</button>
<ul>
<li v-for="(p,index) in persons" :key="p.id">
{{p.name}} -- {{p.age}} -- {{p.sex}}
</li>
</ul>

</div>
</body>

<script type="text/javascript">
Vue.config.productionTip = false //阻止Vue在启动时生成生产提示
const vm = new Vue({
el:'#root',
data:{
persons:[
{id:'001',name:'马冬梅',age:30,sex:'女'},
{id:'002',name:'周冬雨',age:31,sex:'女'},
{id:'003',name:'周杰伦',age:21,sex:'男'},
{id:'004',name:'温兆伦',age:22,sex:'男'}
]
},
methods: {
updateMei(){
this.persons[0].name = '马老师'
this.persons[0].age = 50
this.persons[0].sex = '男'
}
},
computed:{

}
})

</script>
</html>

Vue监测数据改变的原理_Vue

实现效果:

Vue监测数据改变的原理_数据_02

Vue监测数据改变的原理_Vue_03编辑

这时有人就说了,这不是更新的好好的嘛?也没啥问题呀。

不要着急,马上就有问题了,上面写的这种是正确的写法,我们是一个属性一个属性改的,接下来就是有问题的写法。

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>列表排序</title>
<!--引入Vue-->
<script type="text/javascript" src="../js/vue.js"></script>
<style>

</style>
</head>
<body>
<!--准备好一个容器-->
<div id="root">
<!-- 遍历列表 -->
<h2>人员列表</h2>
<button @click="updateMei">更新马冬梅的信息</button>
<ul>
<li v-for="(p,index) in persons" :key="p.id">
{{p.name}} -- {{p.age}} -- {{p.sex}}
</li>
</ul>

</div>
</body>

<script type="text/javascript">
Vue.config.productionTip = false //阻止Vue在启动时生成生产提示
const vm = new Vue({
el:'#root',
data:{
persons:[
{id:'001',name:'马冬梅',age:30,sex:'女'},
{id:'002',name:'周冬雨',age:31,sex:'女'},
{id:'003',name:'周杰伦',age:21,sex:'男'},
{id:'004',name:'温兆伦',age:22,sex:'男'}
]
},
methods: {
updateMei(){
// this.persons[0].name = '马老师' //奏效
// this.persons[0].age = 50 //奏效
// this.persons[0].sex = '男' //奏效
this.persons[0] = {id:'001',name:'马老师',age:50,sex:'男'}
}
},
computed:{

}
})

</script>
</html>

Vue监测数据改变的原理_html_04

实现效果:

Vue监测数据改变的原理_数据_05

Vue监测数据改变的原理_html_06编辑

我们可以看到,在这种写法下,无论怎么点击,数据都不会发生变化。 

这个时候就有人懵了,那这到底是改了还是没改呢?

是这样的。从代码的层面上来说,我们的确是把数组中的某一项给彻底替换掉了。但是Vue并没有监测到。

这时有人就会问,那怎么才能证明这个数据已经被真正的替换掉了呢?Vue的开发者工具中都没有体现变化。这是因为Vue根本就没有监测到数据的变化,所以在Vue的开发者工具中自然也就不会体现这种变化。

为了说明数组中已经发生了变化,我们可以在控制台输出一下。

Vue监测数据改变的原理_数据_07

Vue监测数据改变的原理_数据_08编辑

那么讲到这里我们就把我们想要暴露的问题给暴露出来了。

2.Vue监测数据改变的原理

为了把刚才我们暴露出来的问题说明白,我们就得知道Vue是如何监测数组中元素的改变的。但是我们要讲的话,最好先讲清楚Vue是如何监测对象中数据改变的,随后再引出来Vue是如何监测数组的。之后就可以把我们刚才暴露的问题给解答清楚了。

2.1 Vue是如何监测对象中数据的改变的

​12.Vue中的数据代理_爱米酱的博客-CSDN博客上一节我们知道了什么是数据代理之后,那么我们这一节就来看看Vue中是如何应用数据代理的。https://liufr.blog.csdn.net/article/details/123044053​​我们在之前Vue的数据代理中讲到过,vm身上的属性都是来自于_data中,而_data中的数据都是来自于咱们配置的data,也就是vm._data = data。但是Vue在执行vm._data = data的时候已经是第二步了。它在第一步还做了一个操作那就是加工data,改变了data中的一些小东西,随后才将值给了_data。

那我们要怎么证明这件事呢?

如果我们没有第一步对data的加工步骤,直接执行了第二步的vm._data = data,那么就意味着,_data的值和我们配置的data应该是一摸一样的。

所以接下来我们就看看_data到底是什么样的。

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Vue监测数据改变的原理</title>
<!--引入Vue-->
<script type="text/javascript" src="../js/vue.js"></script>
<style>

</style>
</head>
<body>
<!--准备好一个容器-->
<div id="root">
<h2>学校名称:{{name}}</h2>
<h2>学校地址:{{address}}</h2>

</div>
</body>

<script type="text/javascript">
Vue.config.productionTip = false //阻止Vue在启动时生成生产提示
const vm = new Vue({
el:'#root',
data:{
name:'北大',
address:'北京'
},
methods: {

},
computed:{

}
})

</script>
</html>

Vue监测数据改变的原理_Vue_09

实现效果:

Vue监测数据改变的原理_html_10

Vue监测数据改变的原理_数据_11编辑

我们可以看到_data很明显和咱们当时配置项里写的data不一样。 

_data做了一件事,就是把data中的每一组key-value都生成了getter,setter的写法,如下图:

Vue监测数据改变的原理_Vue_12

Vue监测数据改变的原理_html_13编辑

这里就会有人问,加工一下data能起到什么作用呢? 答案就是加工完data就可以做响应式了。

什么是响应式呢?数据变了,页面也跟着变,这就叫响应式

当我们修改了_data中的name的时候,就会引起name所对应的setter的调用,而setter中又写了可以重新解析模板的调用。模板重新解析之后,就会生成新的虚拟DOM,然后就会有新旧DOM的对比,最后就更新了页面。这样就把一整套流程走通了。

也就是说Vue通过对data的加工,实现了针对对象中属性的监视。

2.2 简单模拟Vue监视属性的代码

其实很多人对这个_data都会有疑问,为什么不能直接通过data来实现属性监视,却需要通过_data再中转一下,是不是多此一举呢?

接下来我们就用简单的代码来模拟一下,看看是不是多此一举。

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>模拟一个数据监测</title>

<style>

</style>
</head>
<body>

</body>

<script type="text/javascript">

let data = {
name:'北京'
}

Object.defineProperty(data,'name',{
get(){
return data.name
},
set(val){
data.name = val
}
})

</script>
</html>

Vue监测数据改变的原理_html_14

实现效果:

Vue监测数据改变的原理_Vue_15

Vue监测数据改变的原理_html_16编辑我们可以看到,当我们试图直接通过data来实现属性的监视的时候,无论是读取操作,还是修改操作都会报错,尽管他看起来与Vue实现的_data结构是一样的,都有属性名称及对应的getter和setter。

Vue监测数据改变的原理_html_17

Vue监测数据改变的原理_数据_18编辑那么这个时候,我们再回过头来看看我们试图通过直接使用data实现属性监视的代码。

在代码中,只要有人读取data中的name,那么就会调用代码中的getter,而getter方法中又在读取data中的name,这样的话,就相当于形成了一个死循环。同理,只要有人修改data中的name,就会调用setter,而setter中又在修改data中的name,也是死循环。

所以_data的这种中转存在才是有意义的。并不能直接通过data来实现属性监视。

那么接下来我们再写写正确的模拟代码

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>模拟一个数据监测</title>

<style>

</style>
</head>
<body>

</body>

<script type="text/javascript">

let data = {
name:'北京',
address:'beijing'
}



//创建一个监视的实例对象,用于监视data中的属性变化
const obs = new Observer(data);

let vm = {}
vm._data = data = obs

//这个构造函数可以创建一个监视的实例对象
function Observer(obj){
//汇总对象中所有的属性形成一个数组
const keys = Object.keys(obj)
keys.forEach((k)=>{
/**
* 这里的this并不是指的data本身,
* 而是这个函数将要生成的实例对象
* 相当于通过另一个对象做了中转
* 这样就不会出现死循环的情况
* */
Object.defineProperty(this,k,{
get(){
return obj[k]
},
set(val){
console.log(`${k} 被改了,我要去解析模板,生成虚拟DOM...`)
obj[k] = val
}
})
})
}

</script>
</html>

Vue监测数据改变的原理_数据_19

实现效果:

Vue监测数据改变的原理_html_20

Vue监测数据改变的原理_数据_21编辑

2.3 Vue.set()方法的使用

虽然现在我们知道了Vue监测对象数据变化的原理,但是有一个Api我们还没学,那就是Vue.set(),这个Api特别适合在了解了对象监测之后去学。我们先把这个了解清楚,然后再去讲如何监测数组,然后再去讲1中我们暴露出来的Vue数据更新却监测不到的问题。

下面我们看看这种有嵌套结构的数据

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Vue监测数据改变的原理</title>
<!--引入Vue-->
<script type="text/javascript" src="../js/vue.js"></script>
<style>

</style>
</head>
<body>
<!--准备好一个容器-->
<div id="root">
<h2>名称:{{name}}</h2>
<h2>地址:{{address}}</h2>
<hr>
<h2>姓名:{{student.name}}</h2>
<h2>年龄:真实{{student.age.rAge}},对外:</h2>
<h2>朋友们</h2>
<ul>
<li v-for="(f,index) in student.friends" :key="index">
{{f.name}} -- {{f.age}}
</li>
</ul>
</div>
</body>

<script type="text/javascript">
Vue.config.productionTip = false //阻止Vue在启动时生成生产提示
const vm = new Vue({
el:'#root',
data:{
name:'北大',
address:'北京',
student:{
name:'tom',
age:{
rAge:40,
sAge:29
},
friends:[
{name:'jerry',age:35},
{name:'tony',age:36}
]
}
}
})

</script>
</html>

Vue监测数据改变的原理_html_22

实现效果:

Vue监测数据改变的原理_Vue_23

Vue监测数据改变的原理_Vue_24编辑

呈现出来以后我们就会发现Vue做的真的很不错,有student就会有它对应的getter和setter。

Vue监测数据改变的原理_html_25

Vue监测数据改变的原理_数据_26编辑

 展开student以后,可以看到在student中的age也有对应的getter和setter。

Vue监测数据改变的原理_数据_27

Vue监测数据改变的原理_Vue_28编辑而展开age之后,里面的rAge和sAge仍然有对应的getter和setter,可以看到Vue的这种结构是层层递进的 ,虽然Vue这种方式做的很不错,但也不是那么完善,我们接下来看看。

如果我们想给这个学生添加一个性别,并且性别是男,我们应该怎么写?

这个时候就会有人说,那还不简单嘛?直接是data中加一个sex,然后用插值语法,写一个 {{student.sex}} 不就行了嘛?

那如果是这样的情况呢?页面上本来就有 {{student.sex}} 的设置,但是data中一开始并没有student.sex的属性,这个属性需要在之后的交互中动态的去添加。那该怎么办?

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Vue监测数据改变的原理</title>
<!--引入Vue-->
<script type="text/javascript" src="../js/vue.js"></script>
<style>

</style>
</head>
<body>
<!--准备好一个容器-->
<div id="root">
<h2>名称:{{name}}</h2>
<h2>地址:{{address}}</h2>
<hr>
<h2>姓名:{{student.name}}</h2>
<h2>性别:{{student.sex}}</h2>
<h2>年龄:真实{{student.age.rAge}},对外:</h2>
<h2>朋友们</h2>
<ul>
<li v-for="(f,index) in student.friends" :key="index">
{{f.name}} -- {{f.age}}
</li>
</ul>
</div>
</body>

<script type="text/javascript">
Vue.config.productionTip = false //阻止Vue在启动时生成生产提示
const vm = new Vue({
el:'#root',
data:{
name:'北大',
address:'北京',
student:{
name:'tom',
age:{
rAge:40,
sAge:29
},
friends:[
{name:'jerry',age:35},
{name:'tony',age:36}
]
}
}
})

</script>
</html>

Vue监测数据改变的原理_html_29

实现效果:

Vue监测数据改变的原理_html_30

Vue监测数据改变的原理_数据_31编辑

这里要注意student是存在的,但是student中不存在sex的属性,所以读取了一个对象中不存在的属性值,返回的就是undefined,是不会报错的。那为什么页面上没有显示undefined呢?这是因为Vue做了处理,如果是undefined值是不会显示到页面的。

那么接着说,如果我们一开始的data中没有student.sex的属性,以后想动态添加该怎么添?

这个时候就会有人说,那不是很简单嘛?直接通过student.sex = '男' 设置一下不行嘛?

真的有这么简单嘛?我们可以试一下。

Vue监测数据改变的原理_Vue_32

Vue监测数据改变的原理_数据_33编辑

我们可以看到,性别那一行,在添加完属性之后并没有任何变化,也没有出现我们能刚才添加的值。这是为什么呢?

我们在控制台输出看一下

Vue监测数据改变的原理_Vue_34

Vue监测数据改变的原理_Vue_35编辑我们可以看到,刚刚动态添加的sex值,并没有生成对应的getter和setter方法 ,那这样就可以解释为什么我们明明设置值了,但是页面却没有任何变化。

我们代码中的age,name都是一开始在new Vue实例的时候就写好的,而这些属性都会被Vue生成对应的getter和setter。其中最重要的就是setter,因为setter可以影响页面。所以我们后添加的sex,由于没有getter和setter,自然也就不是一个响应式的数据。

那么我们想要动态的去添加属性就没有办法了嘛?难道只能一开始就在data中配置好才行嘛?

也不是,Vue为这种情况,给我们提供了一个办法,它为我们提供了一个API,让我们可以实现动态添加的属性也可以有响应式的功能。它就是 Vue.set(target,key,val)

其中target是需要添加属性的目标对象,key是需要添加的属性名称,val是需要添加的属性值。

我们再用这个API试试

Vue监测数据改变的原理_html_36

Vue监测数据改变的原理_Vue_37编辑

我们可以看到这次页面就有变化了,后添加的性别属性值也可以成功在页面显示了。

Vue监测数据改变的原理_html_38

Vue监测数据改变的原理_数据_39编辑

而且通过这个API添加的属性,也会有对应的getter和setter,就会是一个响应式的数据。

那么除了可以使用Vue.set()这个API,还有另一个API可以用,它和Vue.set()一模一样只是换了个名字,它就是 vm.$set(target,key,val)

下面我们再用这个API试一下

Vue监测数据改变的原理_html_40

Vue监测数据改变的原理_数据_41编辑

我们可以看到,这个API同样好用。

虽然Vue.set()vm.$set()都很好用,但是它们也有局限性,接下来我们就演示一下这个局限。

我们刚刚是给data中的student添加的sex,接下来我们直接在data中添加一个属性leader试试。

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Vue监测数据改变的原理</title>
<!--引入Vue-->
<script type="text/javascript" src="../js/vue.js"></script>
<style>

</style>
</head>
<body>
<!--准备好一个容器-->
<div id="root">
<h2>名称:{{name}}</h2>
<h2>地址:{{address}}</h2>
<h2>校长:{{leader}}</h2>
<hr>
<h2>姓名:{{student.name}}</h2>
<h2>性别:{{student.sex}}</h2>
<h2>年龄:真实{{student.age.rAge}},对外:</h2>
<h2>朋友们</h2>
<ul>
<li v-for="(f,index) in student.friends" :key="index">
{{f.name}} -- {{f.age}}
</li>
</ul>
</div>
</body>

<script type="text/javascript">
Vue.config.productionTip = false //阻止Vue在启动时生成生产提示
const vm = new Vue({
el:'#root',
data:{
name:'北大',
address:'北京',
student:{
name:'tom',
age:{
rAge:40,
sAge:29
},
friends:[
{name:'jerry',age:35},
{name:'tony',age:36}
]
}
}
})

</script>
</html>

Vue监测数据改变的原理_Vue_42

实现效果:

Vue监测数据改变的原理_Vue_43

Vue监测数据改变的原理_数据_44编辑

注意,这里的报错是正常的,因为data中确实没有leader这个属性。

Vue监测数据改变的原理_Vue_45

Vue监测数据改变的原理_Vue_46编辑

我们可以看到在给data动态添加属性的时候报错了,而且报错提示不允许给根节点添加动态属性。 

也就是说Vue.set()vm.$set()  只能给data中的某一个对象添加属性 而不能给data添加属性

2.4 Vue是如何监测数组中数据的改变的

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Vue监测数据改变的原理</title>
<!--引入Vue-->
<script type="text/javascript" src="../js/vue.js"></script>
<style>

</style>
</head>
<body>
<!--准备好一个容器-->
<div id="root">
<h2>名称:{{name}}</h2>
<h2>地址:{{address}}</h2>
<h2>校长:{{leader}}</h2>
<hr>
<h2>姓名:{{student.name}}</h2>
<h2>性别:{{student.sex}}</h2>
<h2>年龄:真实{{student.age.rAge}},对外:</h2>
<h2>爱好</h2>
<ul>
<li v-for="(h,index) in student.hobby" :key="index">
{{h}}
</li>
</ul>
<h2>朋友们</h2>
<ul>
<li v-for="(f,index) in student.friends" :key="index">
{{f.name}} -- {{f.age}}
</li>
</ul>
</div>
</body>

<script type="text/javascript">
Vue.config.productionTip = false //阻止Vue在启动时生成生产提示
const vm = new Vue({
el:'#root',
data:{
name:'北大',
address:'北京',
student:{
name:'tom',
age:{
rAge:40,
sAge:29
},
hobby:['抽烟','喝酒','烫头'],
friends:[
{name:'jerry',age:35},
{name:'tony',age:36}
]
}
}
})

</script>
</html>

Vue监测数据改变的原理_html_47

实现效果:

Vue监测数据改变的原理_数据_48

Vue监测数据改变的原理_数据_49编辑我们可以看到即使是层层递进的属性也都有对应的get和set,而hobby这个数组中的0,1,2 却没有对应的get和set,那也就意味着当有一天我们需要改变这个数组中的0,1,2的数据的时候,数据能被改掉,但是Vue监测不到,也就不会引起页面的更新。所以这也就解释了为什么在1中我们想直接改掉数组中的数据,但是页面上却没有任何变化的问题。

我们这里再看一下这问题:

Vue监测数据改变的原理_html_50

Vue监测数据改变的原理_html_51编辑那么Vue不是靠get和set实现数组监视的,又是靠什么呢?怎么才能让Vue监视到我们修改了数组中的值呢?

因为数组本身就有很多方法,所以Vue在针对数组做操作的时候,就把监视搞到了数组的那些方法上。

push 新增一个元素到末尾

pop   删除末尾的元素

shift  删除第一个元素

unshift  在开头新加一个元素

splice   在数组的指定位置插入一个元素/ 在指定位置删除一个元素/ 替换掉指定位置的某个元素

​js数组的splice()方法_爱米酱的博客-CSDN博客第一个参数(起始位置),第二个参数(删除的项数),第三个参数(插入任意数量的项)三个参数,第一个参数(起始位置),第二个参数(0),第三个参数(插入的项)两个参数,第一个参数(要删除第一项的位置),第二个参数(要删除的项数)...https://blog.csdn.net/qq_37050372/article/details/125803856​​sort   对数组进行排序

reverse  反转数组

可以看到我们上面列举出来的这七个数组方法,都是可以修改数组的,所以Vue就规定,只有调用了数组身上的这7个可以修改数组的方法,Vue才会承认数组被修改了。

那么下面我们再用这些方法试试

Vue监测数据改变的原理_html_52

Vue监测数据改变的原理_Vue_53编辑

我们可以看到,只要调用了数组的这些修改方法,那么页面上就会发生变化,那也就意味着修改操作被Vue承认了。

那么再回到第一节中我们暴露出来的那个问题,我们再看看该怎么解决

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>列表排序</title>
<!--引入Vue-->
<script type="text/javascript" src="../js/vue.js"></script>
<style>

</style>
</head>
<body>
<!--准备好一个容器-->
<div id="root">
<!-- 遍历列表 -->
<h2>人员列表</h2>
<button @click="updateMei">更新马冬梅的信息</button>
<ul>
<li v-for="(p,index) in persons" :key="p.id">
{{p.name}} -- {{p.age}} -- {{p.sex}}
</li>
</ul>

</div>
</body>

<script type="text/javascript">
Vue.config.productionTip = false //阻止Vue在启动时生成生产提示
const vm = new Vue({
el:'#root',
data:{
persons:[
{id:'001',name:'马冬梅',age:30,sex:'女'},
{id:'002',name:'周冬雨',age:31,sex:'女'},
{id:'003',name:'周杰伦',age:21,sex:'男'},
{id:'004',name:'温兆伦',age:22,sex:'男'}
]
},
methods: {
updateMei(){
// this.persons[0].name = '马老师' //奏效
// this.persons[0].age = 50 //奏效
// this.persons[0].sex = '男' //奏效
//this.persons[0] = {id:'001',name:'马老师',age:50,sex:'男'} //不奏效
this.persons.splice(0,1,{id:'001',name:'马老师',age:50,sex:'男'})
}
},
computed:{

}
})

</script>
</html>

Vue监测数据改变的原理_html_54

实现效果:

Vue监测数据改变的原理_Vue_55

Vue监测数据改变的原理_Vue_56编辑

那么这个时候又有同学会有疑问,Vue是怎么监测到我们使用了数组的这些修改方法的呢?

Vue在这里使用了一种技术,叫包装。

什么意思呢?也就是说当我们在使用vm._data.student.hobby.push('学习')中的push的时候,这里的push已经不是数组中原汁原味的push了。也就是Array.prototype.push

我们先来验证一下,它和普通数组是否相等。

Vue监测数据改变的原理_html_57

Vue监测数据改变的原理_数据_58编辑

可以看到普通数组是和 Array.prototype.push相等的

我们再看看被Vue管理的数组中的push方法是不是还是原汁原味的。

Vue监测数据改变的原理_数据_59

Vue监测数据改变的原理_Vue_60编辑

可以看到,这个push已经不是原本的push了。 

vm._data.student.hobby.push('学习')中的push,其实是Vue给我们写的push,它在这个push方法中做了两件事,第一件事就是先调用了正常的数组的push方法。第二件事就是重新解析模板,生成虚拟DOM那一套流程。

也就是说Vue对数组的监测其实是靠包装数组身上常用修改数组的方法实现的。

具体的我们可以在Vue官网找到详细解释:

Vue监测数据改变的原理_html_61

Vue监测数据改变的原理_html_62编辑那么是不是我们只能通过这些数组方法来让页面发生和数据的联动呢?

其实也不是,我们可以使用刚刚说过的Vue.set,也能实现同样的效果。下面我们试试

Vue监测数据改变的原理_数据_63

Vue监测数据改变的原理_数据_64编辑

我们看到,同样可以实现。

3.总结

Vue监视数据的原理:

        1.Vue会监视data中所有层次的数据

        2.如何监测对象中的数据?

                通过setter实现监视,且要在new Vue时就传入要监测的数据

                (1)对象中后追加的属性,Vue默认不做响应式处理

                (2)如果需要给后添加的属性做响应式,请使用如下API

                        Vue.set(target,key,value)

                        或

                        vm.$set(target,key,value)

        3.如何监测数组中的数据?

                通过包裹数组更新元素的方法实现,本质就是做了两件事:

                (1)调用原生对应的方法对数据进行更新

                (2)更新解析模板,进而更新页面

        4.在Vue修改数组中的某个元素一定要用如下方法:

                1.使用这些API:push,pop,shift,unshift,splice,sort,reverse

                2.Vue.set() 或 vm.$set()

        特别注意:Vue.set() 和vm.$set() 不能给vm或vm的根数据对象添加属性


标签:监测数据,Vue,name,age,sex,student,原理,data
From: https://blog.51cto.com/u_10745109/6120588

相关文章

  • nodejs、vue安装
    安装完成软件后注意点:本人只做记录防止原文删除原文:https://www.jb51.net/article/251371.htm一、创建全局安装目录和缓存日志目录运行 npmconfigsetcache"D:\Pro......
  • 使用vscode + vite + vue3+ vant 搭建vue3脚手架
    【术栈】开发工具:VSCode代码管理:Git前端框架:Vue3构建工具:Vite路由:vue-router4x状态管理:vuex4xAJAX:axiosUI库:vant数据模拟:mockjscss预处理:sass构建vue3项目1,安装 vite......
  • 缓存原理
    Redis属于单线程还是多线程?Redis是单线程的,主要是指Redis的网络I/O线程,以及键值的SET和GET等读写操作都是由一个线程来完成的但Redis的持久化、集群同步等操......
  • vue经常遗忘基础知识汇总
    Vueexportdefault和export的使用方式原文链接:https://blog.csdn.net/u012887259/article/details/108119368  ......
  • VueX插件 --- 共享数据的读写处理
    vueX:vue插件,处理组件之间共享数据的读&&写引入demo(就一个Count组件,加法计算)###Count.vue(基础的写死版)<template> <div> <h1>当前求和为???</h1> <se......
  • scanf的原理
    //1、scanf来读取输入数据时会阻塞,因为标准缓冲区为空。//2、scanf用来读取标准输入,scnaf把标准输入内的内容,需要放到某个变量空间里,因此变量必须取地址。/*3、scanf在读取......
  • vue el-dialog 模态框拖拽
    一、el-dialog拖拽效果展示二、代码实现1.在utils目录写两个文件drag.js和directive.jsdrag.js拖拽元素js代码directive.js注册vue的自定义指令drag.js拖拽......
  • Vue项目中将px转化为rem来实现移动端的适配(亲测有效)
     最近做项目有个需求:vuepc端需要嵌套移动端页面涉及到将px转化为rem来实现移动端的适配问题,两步解决!绝绝子教你哈1.index.html页面放入:px转rem公共的方法  (fu......
  • Ioc原理
    Spring提供的容器又称为IoC容器,什么是IoC?IoC全称InversionofControl,直译为控制反转。那么何谓IoC?在理解IoC之前,我们先看看通常的Java组件是如何协作的。我们假定一个在线......
  • less & saas/scss & css 深度选择器语法在 Vue2 & Vue3中的使用
    vue2中原生css>>>.el-card__header saas\scss::v-deep.el-card__headerless/deep/.el-card__header vue3中:deep(){......