一、组件间通信***
1.props配置
适用于场景:父子组件通信
注意:
如果父组件给子组件传递数据(非函数),本质就是父组件给子组件传递数据
如果父组件给子组件传递数据(函数),本质就是子组件给父组件传递数据(相当于自定义事件)
school组件:
<template>
<div>
<h1>学校名称:{{name}}</h1>
<h3 v-show="age != 0">展示学生年龄:{{age}}</h3>
<br>
<br>
<Student :studentName="studentName" :age="age" :sex="sex" @changeAge="changeAge"/>
</div>
</template>
<script>
import Student from '../components/Student.vue'
export default {
components:{Student},
data() {
return {
name:'家里蹲',
studentName:'张三',
sex:'男',
age:0,
}
},
methods: {
changeAge(age){
this.age = age;
}
},
}
</script>
Student组件:
<template>
<div>
<h1>{{msg}}</h1>
<h3>学生姓名:{{name}}</h3>
<h3>学生性别:{{sex}}</h3>
<h3>学生年龄:{{studentAge}}</h3>
<button @click="updateAge">通过父组件传递过来的函数将子组件中的年龄传过去</button>
</div>
</template>
<script>
export default {
// 简单声明接收
props:['name','age','sex'],
data() {
return {
msg:'我是一个学生',
studentAge:18
}
},
methods: {
updateAge(){
this.$emit('changeAge',this.studentAge);
}
},
}
</script>
props另外两种接收方式:
接收的同时对数据进行类型限制
props:{ name:String, age:Number, sex:String}
接收的同时对数据:进行类型限制+默认值的指定+必要性的限制
props:{
name:{
type:String, //name的类型是字符串
required:true, //name是必要的
},
age:{
type:Number,
default:99 //默认值
},
}
2.自定义事件(emit)
适用于常见:父子组件通信
School组件:
<template>
<div class="school">
<h2>学校名称:{{name}}</h2>
<h2>学生名字:{{studentName}}</h2>
<!-- 通过父组件给子组件传递函数类型的props实现:子给父传递数据 -->
<School :getStudentName="getStudentName"/>
<!-- 通过父组件给子组件绑定一个自定义事件实现:子给父传递数据(第二种写法,使用ref) -->
<Student ref="student" />
</div>
</template>
<script>
export default {
name:'School',
data() {
return {
name:'家里蹲'
msg:'你好啊!',
studentName:''
}
},
methods: {
getStudentName(name,...params){
console.log('学校收到了学生名:',name,params)
this.studentName = name
},
},
mounted() {
this.$refs.student.$on('getName',this.getStudentName) //绑定自定义事件
// this.$refs.student.$once('atguigu',this.getStudentName) //绑定自定义事件(一次性)
},
}
</script>
Student组件:
<template>
<div class="student">
<h2>学生姓名:{{name}}</h2>
<button @click="sendStudentName">把学生名给学校</button>
<button @click="unbind">解绑事件</button>
<button @click="death">销毁当前Student组件的实例(vc)</button>
</div>
</template>
<script>
export default {
name:'Student',
//props:['getStudentName']
data() {
return {
name:'张三',
}
},
methods: {
sendStudentlName(){
//this.$emit('getStudentName',this.name)
//触发Student组件实例身上的getName事件
this.$emit('getName',this.name,666,888,900)
},
unbind(){
this.$off('getName') //解绑一个自定义事件
// this.$off(['getName']) //解绑多个自定义事件
// this.$off() //解绑所有的自定义事件
},
death(){
this.$destroy() //销毁了当前Student组件的实例,销毁后所有Student实例的自定义事件全都不奏效。
}
},
}
</script>
3.全局事件总线 ($bus)
适用场景:全能
new Vue({
el:'#app',
render: h => h(App),
beforeCreate() {
Vue.prototype.$bus = this //安装全局事件总线
},
})
//其余使用方法和自定义事件类似,只需要加上this.$bus.$on,this.$bus.$emit
4.消息于订阅
适用场景:全能
注意:不过在Vue中使用特别少,在此就不过多展示(利用到了插件pubsub-js)
5.插槽
适用场景:全能
分别有:默认插槽、具名插槽、作用域插槽(使用也比较少,不过作用域插槽经常在element-ui中使用)
6.vuex
适用场景:全能
展示下简单使用(还有更多方法自行了解)
Count组件:其请求都发送到一个JS模块(Store)去了
<template>
<div>
<h1>当前求和为:{{$store.state.sum}}</h1>
<select v-model.number="n">
<option value="1">1</option>
<option value="2">2</option>
<option value="3">3</option>
</select>
<button @click="increment">+</button>
<button @click="decrement">-</button>
<button @click="incrementOdd">当前求和为奇数再加</button>
<button @click="incrementWait">等一等再加</button>
</div>
</template>
<script>
export default {
name:'Count',
data() {
return {
n:1, //用户选择的数字
}
},
methods: {
increment(){
this.$store.commit('JIA',this.n)
},
decrement(){
this.$store.commit('JIAN',this.n)
},
incrementOdd(){
this.$store.dispatch('jiaOdd',this.n)
},
incrementWait(){
this.$store.dispatch('jiaWait',this.n)
},
},
}
</script>
Store.js模块:
//该文件用于创建Vuex中最为核心的store
import Vue from 'vue'
//引入Vuex
import Vuex from 'vuex'
//应用Vuex插件
Vue.use(Vuex)
//准备actions——用于响应组件中的动作
const actions = {
// 如果没有逻辑处理等方面,可以直接commit,不需要dispacth
/* jia(context,value){
console.log('actions中的jia被调用了')
context.commit('JIA',value)
},
jian(context,value){
console.log('actions中的jian被调用了')
context.commit('JIAN',value)
}, */
jiaOdd(context,value){
console.log('actions中的jiaOdd被调用了')
if(context.state.sum % 2){
context.commit('JIA',value)
}
},
jiaWait(context,value){
console.log('actions中的jiaWait被调用了')
setTimeout(()=>{
context.commit('JIA',value)
},500)
}
}
//准备mutations——用于操作数据(state)
const mutations = {
JIA(state,value){
console.log('mutations中的JIA被调用了')
state.sum += value
},
JIAN(state,value){
console.log('mutations中的JIAN被调用了')
state.sum -= value
}
}
//准备state——用于存储数据
const state = {
sum:0 //当前的和
}
//创建并暴露store
export default new Vuex.Store({
actions,
mutations,
state,
})
7.$ref----父子
ref:这个属性用在子组件上,它的用用就指向了子组件的实例,可以通过实例来访问组件的数据和方法
二、高级组件间通信
1.v-model深入
Parent组件:
<template>
<div>
<!-- 最常使用的v-model搭配表单元素 -->
<input type="text" v-model="msg"><span>{{msg}}</span>
<!-- 元素DOM当中有oninput事件,它通常结合表单元素一起使用,当表单元素发生变化时就触发回调函数 -->
<input type="text" :value="msg" @input="msg = $event.target.value" /> <span>{{msg}}</span>
<!--
深入v-model:实现父子数据同步
这里的msg是传递给子组件的数据
@input是自定义事件
-->
<!-- <Childer :value="msg" @input="msg = $event"/> -->
<Children v-model="msg" />
</div>
</template>
<script>
import Children from '../components/Children.vue'
export default {
data() {
return {
msg:'',
}
},
components:{
Children,
}
}
</script>
Children组件:
<template>
<div>
<input type="text" :value="value"
@input="$emit('input',$event.target.value)">
</div>
</template>
<script>
export default {
props:['value'],
}
</script>
2.Sync修饰符
Sync组件:
<template>
<div>
<!--
:money 父组件给子组件传递的数据
@update:money 绑定的自定义事件
目前这种操作和v-model很类似
-->
<h2>不是用Sync修饰符</h2>
<Child1 :money="money" @update:money="money = $event"/>
<!--
:money.sync(语法糖)
第一:给子组件传递money数据
第二:绑定了一个update:money事件
-->
<h2>使用Sync修饰符</h2>
<Child2 :money.sync="money" />
</div>
</template>
<script>
import Child1 from '../components/Child1.vue'
import Child2 from '../components/Child2.vue'
export default {
data() {
return {
money:100,
}
},
components:{
Child1,
Child2
}
}
</script>
Child子组件内容代码差不多,只展示一个:
<template>
<div>
<h3>每次花十块</h3>
<button @click="$emit('update:money',money - 10)"></button>
<span>{{money}}</span>
</div>
</template>
<script>
export default {
props:['money'],
}
</script>
3.listeners
attrs就没有了**)
$listeners:也属于组件实例的一个属性,可以获取到父组件给子组件绑定的所有的自定义事件
4.parent
$children:属于组件实例的一个属性,可以获取到当前组件的全部子组件【数组存储】
$parent:属于组件实例的一个属性,可以获取当前子组件的父组件
5.混入mixin
封装一个mixin.js模块,将各种组件中具有相同功能的代码写入,提高代码复用性,而且好维护。