数据流的单向性
先来看个例子
<!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>Document</title>
</head>
<body>
<div id="app">
<h2>我是{{father}},我有一个儿子叫做{{son}}</h2>
<son :son-name="son"></son>
</div>
<template id="temp1">
<div class="box">
<h3>我是儿子,我叫{{sonName}}</h3>
</div>
</template>
</body>
<script src="js/vue.js"></script>
<script>
var son = {
template:"#temp1",
props:["sonName"]
}
new Vue({
el:"#app",
data:{
father:"baba",
son:"erzi"
},
components:{
son
}
})
</script>
</html>
在上面的案例中,我们向子组件传递了一个数据 :son-name=“son” , 子组件拿到后就渲染在了页面上,所以数据是由父组件传递给子组件的
现在有两个问题
1、父级组件如果改变了son这个数据,子级是否会改变?
2、子级能不能改变父级传递的son?
结论一:父级改变,子级也会改变
<div id="app">
<h2>我是{{father}},我有一个儿子叫做{{son}}</h2>
<button type="button" @click="son='girl'">改父级</button>
<son :son-name="son"></son>
</div>
结论二:子级不能改变父级传递过来的数据,并且还会带一个报错,因为破坏了数据的统一性
<template id="temp1">
<div class="box">
<h3>我是儿子,我叫{{sonName}}</h3>
<button type="button" @click="sonName='mama'">改子级</button>
</div>
</template>
在上面的两个结论中,我们可以到数据流是一个单方向的,只能由父到子,不能由子到父
破坏数据流的单向性
在某些场合我们要做一个数据流的改变,这个我们就需要去破坏数据流的单向性,从而能够让数据互传,这个时候用下面两种方式
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>Document</title>
</head>
<body>
<div id="app">
<h2>我是{{father}},我有一个儿子叫做{{obj.son}}</h2>
<button type="button" @click="obj.son='girl'">改父级</button>
<son :bbb="obj"></son>
</div>
<template id="temp1">
<div class="box">
<h3>我是儿子,我叫{{bbb.son}}</h3>
<button type="button" @click="bbb.son='mama'">改子级</button>
</div>
</template>
</body>
<script src="js/vue.js"></script>
<script>
var son = {
template:"#temp1",
props:["bbb"]
}
new Vue({
el:"#app",
data:{
father:"baba",
obj:{
son:"erzi"
}
},
components:{
son
}
})
</script>
</html>
2、通过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>Document</title>
</head>
<body>
<div id="app">
<h2>我是{{father}},我有一个儿子叫做{{mySonName}}</h2>
<!-- 在父组件当中调用子组件son,同时传值tanme:mySonName
在父组件中监听自定义事件dadchangemyname -->
<son :tname="mySonName" @dadchangemyname="changeSonName"></son>
</div>
<template id="temp1">
<div class="box">
<h3>我是儿子,我叫{{tname}}</h3>
<!-- 在子组件的按钮上绑定一个点击事件,执行childChangeName,
当该方法被执行会触发一个自定义事件dadchangemyname -->
<button type="button" @click="childChangeName">改子级</button>
</div>
</template>
</body>
<script src="js/vue.js"></script>
<script>
var son = {
template:"#temp1",
//接收父组件传递过来的tname属性,他的值是"son"
props:["tname"],
methods:{
childChangeName(){
//触发一个自定义事件
this.$emit("dadchangemyname","xinerzi");
}
}
}
new Vue({
el:"#app",
data:{
father:"baba",
mySonName:"son",
obj:{
son:"erzi"
}
},
methods:{
changeSonName(newName){
this.mySonName = newName;
}
},
components:{
son
}
})
</script>
</html>
在子组件的内部触发了一个自定义事件,然后这个自定义事件通过 this.$emit(“事件名”,“参数”),掉调用这个组件的时候,我们可以使用@自定义事件去监听
自定义事件
在上面的案例中,我们去破坏了数据流的单向性的时候使用了自定义事件,其实在vue开发里面,自定义事件使用是非常频繁的,我们先把刚才的自定义流程整理
子组件 $emit() 自定义事件 ----> 父组件监控这个@自定义事件 —> 父组件调用方法执行
自定义事件案例
<!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>Document</title>
</head>
<body>
<div id="app">
<my-button @abc="aaa"></my-button>
</div>
<template id="temp1">
<button type="button" @click="innerClick($event)">{{text}}</button>
</template>
</body>
<script src="js/vue.js"></script>
<script>
let myButton = {
template:"#temp1",
props:{
text:{
type:String,
//props主要是用来接收传递过来的值,但是如果再props当中声明的属性没有接收到值
//我们可以给他设置一个默认值来使用
default: () => "按钮"
}
},
methods:{
innerClick(event){
this.$emit("abc",event);
}
}
}
new Vue({
el:"#app",
data:{
},
components:{
myButton
},
methods:{
aaa(){
alert("hello world");
console.log(event);
}
}
})
</script>
</html>