vue中组件间通信方式总结

115 阅读2分钟

一、组件间通信***

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.自定义事件(on,on,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.attrsattrs与listeners

attrs:属于组件实例的一个属性,可以获取到父组件传递过来的所以props数据(但如果子组件用props接收的属性,那么在attrs:属于组件实例的一个属性,可以获取到父组件传递过来的所以props数据(**但如果子组件用props接收的属性,那么在attrs就没有了**)

$listeners:也属于组件实例的一个属性,可以获取到父组件给子组件绑定的所有的自定义事件

4.childrenchildren与parent

$children:属于组件实例的一个属性,可以获取到当前组件的全部子组件【数组存储

$parent:属于组件实例的一个属性,可以获取当前子组件的父组件

5.混入mixin

封装一个mixin.js模块,将各种组件中具有相同功能的代码写入,提高代码复用性,而且好维护。