準備
目錄結構
cli服務 npm i @vue/cli-service-global -g
入口文件:main.js
import Vue from "vue";
import App from "./App"
new Vue({
el:"#app",
render:h=>h(App)
})
根組件:APP.Vue.js
<template>
<div>
<parent></parent>
</div>
</template>
<script>
import parent from "./components/parent"
export default{
components: {
parent
}
}
</script>
組件通信
1. props
父組件通過props
的方式向子組件傳遞數據,而通過$emit
子組件可以向父組件通信。
- 父傳子
parent.vue
<template>
<div>
parent--->{{number}}
<hr />
<son :number = number @changeInParent="changeInParent"></son>
</div>
</template>
<script>
import son from "./son";
export default {
data() {
return {
number: 100
};
},
methods: {
changeInParent(newValue){
this.number = newValue
}
},
components: {
son
}
};
</script>
son.vue
<template>
<div>
<p>son--->{{number}}</p>
<button @click ="changeInSon()" >change</button>
<hr>
</div>
</template>
<script>
export default {
props: {
number: Number
},
methods: {
changeInSon() {
this.$emit("changeInParent",200)
}
},
};
</script>
2. $emit
- 父傳子,子傳孫
在上面的基礎上加上grandson.vue
組件,parent.vue
不做修改
son.vue
<template>
<div>
<p>son--->{{number}}</p>
<button @click ="changeInSon()" >change</button>
<hr>
<grandson :number = "number" @change="change"></grandson>
</div>
</template>
<script>
import grandson from "./grandson"
export default {
props: {
number: Number
},
methods: {
changeInSon() {
this.$emit("changeInParent",200)
},
change(newValue){
this.$emit("changeInParent",newValue)
}
},
components:{
grandson
}
};
</script>
grandson.vue
<template>
<div>
<p>grandson--->{{number}}</p>
<button @click="changeInGrandson()">change</button>
</div>
</template>
<script>
export default {
props: {
number: Number
},
methods: {
changeInGrandson(){
this.$emit("change",300)
}
}
};
</script>
同步父子組件的數據=>語法糖的寫法
2.1. .sync/update
parent.vue
<template>
<div>
parent--->{{number}}
<hr />
<son :number = number @update:number="changeInParent"></son>
</div>
</template>
<script>
import son from "./son";
export default {
data() {
return {
number: 100
};
},
methods: {
changeInParent(newValue){
this.number = newValue
}
},
components: {
son
}
};
</script>
</script>
以上還可以簡化爲:
parent.vue
<template>
<div>
parent--->{{number}}
<hr />
<!-- <son :number = number @update:number="newValue=>number = newValue"></son> -->
<son :number.sync = number></son>
</div>
</template>
<script>
import son from "./son";
export default {
data() {
return {
number: 100
};
},
components: {
son
}
};
</script>
son.vue
<template>
<div>
<p>son--->{{number}}</p>
<button @click ="changeInSon()" >change</button>
<hr>
</div>
</template>
<script>
export default {
props: {
number:Number,
},
methods: {
changeInSon() {
this.$emit("update:number",600)
},
},
};
</script>
2.2 .v-model/input/value
v-mode
只能給子組件傳遞一個屬性
parent.vue
<template>
<div>
parent--->{{number}}
<hr />
<!-- <son :value = number @input="newValue => number = newValue"></son> -->
<son v-model="number"></son>
</div>
</template>
<script>
import son from "./son";
export default {
data() {
return {
number: 100
};
},
components: {
son
}
};
</script>
son.vue
<template>
<div>
<p>son--->{{value}}</p>
<button @click ="changeInSon()" >change</button>
<hr>
</div>
</template>
<script>
export default {
props: {
value: Number
},
methods: {
changeInSon() {
this.$emit("input",700)
},
},
};
</script>
3. $children/$parent
使用 this.$parent
查找當前組件的父組件,可直接觸發父組件的父組件的方法
使用 this.$children
查找當前組件的直接子組件,可以遍歷全部子組件,但$children
並不保證順序,也不是響應式的。
parent.vue
<template>
<div>
parent--->{{number}}
<hr />
<son :number = number @changeInParent="changeInParent"></son>
</div>
</template>
<script>
import son from "./son";
export default {
data() {
return {
number: 100
};
},
methods: {
changeInParent(newValue){
this.number = newValue
}
},
components: {
son
}
};
</script>
son.vue
<template>
<div>
<p>son--->{{number}}</p>
<button @click ="changeInSon()" >change</button>
<hr>
<grandson :number = "number"></grandson>
</div>
</template>
<script>
import grandson from "./grandson"
export default {
props: {
number: Number
},
methods: {
changeInSon() {
this.$emit("changeInParent",200)
},
},
components:{
grandson
}
};
</script>
grandson.vue
<template>
<div>
<p>grandson--->{{number}}</p>
<button @click="changeInGrandson()">change</button>
</div>
</template>
<script>
export default {
props: {
number: Number
},
methods: {
changeInGrandson(){
this.$parent.$emit("changeInParent",400)
}
}
};
</script>
出現多層時使用 :$disptch/broadcast
如果層級很深就會出現$parent.$parent
…這裏封裝一個$dispach
方法進行向上派發
parent.vue
和son.vue
較上一個案例不做修改,
在main.js
中定義一個dispatch
方法,$dispatch
可以逐級往上找父中的方法,
在main.js
中定義一個broadcast
方法,broadcast
可以逐級往上找父中的方法.
main.js
import Vue from "vue";
import App from "./App"
// 自己定義一個disptch方法
Vue.prototype.$dispatch = function(evenName,value){
let parent = this.$parent;
while(parent){
parent.$emit(evenName,value)
parent = parent.$parent
}
}
new Vue({
el:"#app",
render:h=>h(App)
})
grandson.vue
<template>
<div>
<p>grandson--->{{number}}</p>
<button @click="changeInGrandson()">change</button>
</div>
</template>
<script>
export default {
props: {
number: Number
},
methods: {
changeInGrandson(){
this.$dispatch("changeInParent",500)
}
}
};
</script>
4.$attrs、 $listeners
$attrs、 $listeners
均可跨級傳值
$attrs
用來接收傳過來的多個屬性,跨級傳用 v-bind
$listeners
用來接收傳過來的多個方法,跨級傳用 v-on
parent.vue
<template>
<div>
parent--->{{number}}--->{{sum}}
<hr />
<son :number="number" :sum="sum" @click="showclick" @mousedown="showmouse"></son>
</div>
</template>
<script>
import son from "./son";
export default {
data() {
return {
number: 100,
sum: 0
};
},
methods: {
showclick() {
window.console.log("clickEvent...");
},
showmouse(){
window.console.log("mouseEvent...");
}
},
components: {
son
}
};
</script>
son.vue
<template>
<div>
<p>son--->{{$attrs.number}}--->{{$attrs.sum}}</p>
<hr>
<grandson v-bind="$attrs" v-on = "$listeners" ></grandson>
</div>
</template>
<script>
import grandson from "./grandson"
export default {
inheritAttrs: false, //可以把傳遞過來的屬性不作爲標籤真正的屬性
components:{
grandson
},
};
</script>
grandson.vue
<template>
<div>
<p>grandson--->{{$attrs}}</p>
<p>grandson--->number:{{$attrs.number}}--->{{$attrs.sum}}</p>
<button @click="$listeners.click()">triggerClickEvent</button>
<br><br>
<button @click="$listeners.mousedown()">triggerMouseEvent</button>
</div>
</template>
5. Provide&Inject
數據比較多的情況下,不建議使用
Provide
在父級中提供數據
<template>
<div>
<parent></parent>
</div>
</template>
<script>
import parent from "./components/parent";
export default {
provide() {
return {
name: "wangcai"
};
},
components: {
parent
}
};
</script>
Inject
在任意子組件中可以注入父級數據
<template>
<div>
{{name}}
</div>
</template>
<script>
export default {
inject: ["name"],
};
</script>
6. ref/refs
獲取組件實例,在父組件中得到子組件,並且調用子組件的方法
利用ref
給子組件起一個name
,然後在父組件中利用this.$refs.name.alertINfo()
去獲取子組件中的alertINfo()
方法
parent.vue
<template>
<div>
<son ref="sonMethods"></son>
</div>
</template>
<script>
import son from "./son";
export default {
mounted() {
this.$refs.sonMethods.alertINfo()
},
components: {
son
}
};
</script>
son.vue
<template>
<div>
</div>
</template>
<script>
export default {
methods: {
alertINfo() {
window.console.log("this is a methods on son ......");
}
}
};
</script>
7. EventBus
事件總線,用於跨組件通知
在入口文件中將$bus
掛載到Vue原型上
然後利用this.$bus.$on("event",function(){ })
在父組件註冊事件
然後利用this.$bus.$emit("event")
在子組件註冊事件
main.js
import Vue from "vue";
import App from "./App";
// 將$bus掛載到Vue原型上面的一個vm
Vue.prototype.$bus = new Vue()
new Vue({
el: "#app",
render: h => h(App)
});
parent.vue
<template>
<div>
<son></son>
</div>
</template>
<script>
import son from "./son";
export default {
mounted() {
this.$bus.$on("change",function(){
window.console.log("change...");
})
},
components: {
son
}
};
</script>
grandson.vue
<template>
<div>
</div>
</template>
<script>
export default {
mounted(){
this.$nextTick(()=>{
this.$bus.$emit("change")
})
}
};
</script>