Vue2组件通信方式
一 、props
-
使用场景:[父子通信]
-
传递数据类型:
1:可能是函数 -----------实质子组件想给父亲传递数据
2:可能不是函数-----------实质就是父亲给子组件传递数据<TodoList :todos="123" @updateChecked="hander"> // 子传父,在子组件中调用hander 但 hander 函数是写在父组件中的
二、 自定义事件
- 使用场景:[子给父传递数据]
儿子$emit
----> 父亲$on[简写@]
父亲中的两种写法:
[简单写法|复杂写法]<Todos @erha="handler"> <Todos ref='erha'> mounted(){ this.$refs.erha.$on('xx',callBack) }
- 自定义事件
- 子向父传递数据
- 事件类型 回调函数 谁调用 默认传递的是什么?
- 1、事件类型 无数个
- 2、回调函数 自己去定义的
- 3、谁调用 自己去调用自己使用$emit触发调用的
- 4、默认传递的是什么? 默认传递的是自己给的参数有就有,没有就没有 (undefined)
this.$emit( 'haha' ,10)
三、全局事件总线
- 使用场景: [所有场合]
- 全局事件总线的角色标准
1、所有的组件对象都可以看到它
2、可以使用$on
和$emit
方法
vm对象
vm对象必须挂在Vue的原型上 - 怎么添加事件总线?
1、安装总线
2、在接收数据的组件对象当中获取总线给总线绑定自定义事件this.$bus.$on
3、在发送数据的组件对象当中︰获取总线触发总线身上绑定的自定义事件this. $bus.$emit
四、 pubsub-js【发布订阅消息】*****在vue中根本不用【React用】 ----万能
- 类似于全局事件总线 但是在vue当中因为有了全局事件总线 所有一般不用
- 是一个第三方包来实现地消息的订阅和发布 但是这个包使用起来会增加体积
五、 Vuex
- 使用场景 : Vuex[仓库] ----万能的
- 注意点: 数据非持久化(刷新会丢失,自动登录的时候需要考虑(可以放在本地存储里))
- 什么时候用? 看项目大小,项目大就用这个
看项目的大小来决定要不要使用vuex
一般我们都要用的,一般情况我们的项目都比较大,项目比较复杂,使用vuex比较方便
项目如果很小,使用vuex反而会降低效率,因为vuex是需要占用打包体积的 - 核心概念:5
js { state mutations actions getters modules }
六、 插槽
- 使用场景: -----父子通信【结构】
slot
默认插槽
具名插槽
作用域插槽:子组件的数据来源于父组件,但是子组件的自己的结构由父亲决定。
七、 v-model实现组件通信,(父子同步)
-
v-model:指令,可以收集表单数据【text、radio、checkbox、range】等等
-
切记:v-model收集checkbox需要用数组收v-model在不同身上的作用
- :value="msg"在html标签身上是单向数据绑定
- :value="msg"在组件标签身上是props组件通信
- @input html标签身上是原生dom事件
- @input 组件标签身上是自定义事件
使用我们的v-model 达到父子同步的效果!!!
v-model本质其实是单向数据绑定v-bind和input事件的组合
在html标签中, :value是负责读取的 @input是负责赋值的 ,这样就形成了双向数据绑定
// <input type="text" :value="msg" @input=" msg = $event.target.value" >
// <span>塞北的大雪{{msg}}</span>
父组件(Communication)中的代码
:value给子组件传递数据,然后通过自定义事件在从子组件中拿数据,就形成了父子同步
<CustomInput :value="msg" @input="msg = $event" ></CustomInput>
// <CustomInput v-model="msg"></CustomInput> 这两个的效果是一样的,写哪个都行!
value是我们的props传参方式 @ipnut是我们的自定义事件 $event是触发自定义事件接受的参数
子组件(CustomInput)中的代码
<div>
<h2>input包装组件</h2>
第一个value是单向数据绑定值是父组件传过来的 这个@input是原生dom事件 $emit是触发事件 input是自定义事件名称 后面的是input框的值作为参数传递过去了
<input type="text" :value="value" @input="$emit('input',$event.target.value)" >
</div>
<script type="text/ecmascript-6">
export default {
name: 'CustomInput',
props:['value']
}
</script>
八、 属性修饰符.sync,可以实现父子数据同步。
.sync和v-model用在组件标签上,都可以达到父子组件数据同步
区别:
.sync达到数据同步: 子组件内部不是表单类元素
v-model达到数据同步:子组件内部一定是表单类元素
- 以后在elementUI组件中出现,实现父子数据同步。
// 父组件
<div>
小明的爸爸现在有{{money}}元
<h2>不使用sync修改符</h2>
<Child :money="money" @update:money="money = $event" ></Child>
//必须用@update:xxx ,这么写相当与.sync
-------------------------------------------------------------------------------------
<h2>使用sync修改符</h2>
<Child :money.sync="money"></Child >
------------------------------------------------------------------------------------
<h2>使用v-model修改符</h2>
<Child2 :value="money" @input="money = $event" ></Child2 >
<Child2 v-model="money" ></Child2>
----------------------------------------------------------------------------
</div>
.sync子组件----------------------------------------------------------------------
<template>
<div style="background: #ccc; height: 50px;">
<span>小明每次花100元</span>
<button @click="$emit('update:money',money - 100)" >花钱</button>
爸爸还剩 {{money}} 元
</div>
</template>
<script type="text/ecmascript-6">
export default {
name: 'Child',
props:['money'],
}
</script>
v-model子组件----------------------------------------------------------------------
<template>
<div style="background: #ccc; height: 50px;">
<span>小明每次花100元</span>
<button @click="$emit('input',value-100)" >花钱</button>
爸爸还剩 {{value}} 元
</div>
</template>
<script type="text/ecmascript-6">
export default {
name: 'Child2',
props:['value']
}
</script>
九、 $attrs 与 $listeners
- 使用场景: -----父子通信
$attrs:组件实例的属性,可以获取到父亲传递的props数据(前提子组件没有通过props接收)
$listeners:组件实例的属性,可以获取到父亲传递自定义事件(对象形式呈现)
<div>
<h2>自定义带Hover提示的按钮</h2>
<!-- 二次封装的HintButton按钮的时候,把人家el-button需要的数据传递过去 -->
<HintButton type="success" icon="el-icon-plus" title="我是中国人" @click="handler"/>
</div>
下面是对el-button的二次封装
<a :title="title">
<el-button v-bind="$attrs" v-on="$listeners">添加</el-button>
</a>
export default {
name: "",
props:['title'],
mounted(){
//this.$attrs:可以获取到父亲传递的数据【props】
//this.$attrs是可以获取父亲传递的props数据,如果子组件通过
//props:[],接受,this.$attrs属性是获取不到的
console.log(this.$attrs);
console.log(this.$listeners);
}
};
十、 $children
与 $parent
- 使用场景: -----父子通信
ref:可以在父组件内部获取子组件—实现父子通信,可以给所有的子组件打标识,从而拿到某个子组件中的数据
$children:可以在父组件内部获取全部的子组件【返回数组】 配合ref使用,可以一次性拿到所有子组件中的数据
$parent:可以在子组件内部获取唯一的父组件【返回组件实例】
下面是$ref
和$children
的使用
<h2>爸爸有存款: {{ money }}</h2>
<button @click="JieQianFromXM(100)">找小明借钱100</button>
<Son ref="xm" /> //儿组件
<Daughter ref="xh"/> //子组件
//爸爸找儿子借钱
JieQianFromXM(money) {
this.money += money;//爸爸组件的钱累加100
this.$refs.xm.money -= money; //小明的钱累减100
},
//找所有的孩子们借钱
JieQianAll(money){
this.money += 2*money;
this.$children.forEach(item=>item.money-=money);
//不建议用枚举获取子组件:因为没办法确定到底是那个子组件
// this.$children[0].money -=money;
},
-----此处省略某些代码
data() {
return {
money: 1000,
};
},
Vue3组件通信方式
一、props
- 使用场景:[父子通信]
父组件 Father.vue
<template>
<!--通过v-bind给子组件传值 -->
<Son :money="info.money" :car="info.car">
</Son>
</template>
<script setup>
import { reactive } from 'vue';
import Son from '@/components/Son.vue';
const info=reactive({
money: 10,
car: '兰博基尼'
});
</script>
子组件 Son.vue
<template>
<section>
<div>我是儿子,爸爸给了我{{money}}元钱,给我买了一辆{{car}}的车</div>
</section>
</template>
<script setup>
const props = defineProps({
money: Number,
car: String,
});
// 对象形式声明 props
// 等价于以字符串数组声明 props
//const props = defineProps(['title', 'info', 'author']);
...
// 在setup中使用时则直接 props.money
const myMoney= props.money;
</script>
<style></style>
二、pina
- 使用场景:[任意组件间通信]
- 安装: npm install pinpa
- 引入
import {createPinia} from 'pinia' //main.js导入
createApp(App).use(createPinia()).mount('#app') //createPinia()得加上括号
三:、$ref + defineExpose
- 使用场景:[父子组件]
- defineExpose : 组件向外暴露自身的属性和方法, 实现子向父传递
$refs
: 在 vue3 中,由于在 setup 中无法访问到 this, 不能通过this.$refs.xxx 获取, 那么为了能够使用 $refs,我们需要借助一个方法:getCurrentInstance()。该对象返回当前的实例对象,实现父向子传递
父组件 Father.vue
<template>
<div>
<Child ref="child"></Child>
<button @click="findMyChild">寻找我的孩子</button>
</div>
</template>
<script setup>
import Child from './components/Child.vue';
import { getCurrentInstance} from 'vue'
const currentInstance = getCurrentInstance()
console.log(currentInstance);
function findMyChild() {
// 拿到子组件的方法
currentInstance.ctx.$refs.child.tellFatherMyPositon()//两种写法都可以
// currentInstance.refs.child.tellFatherMyPositon()
// 拿到子组件的数据
console.log( currentInstance.ctx.$refs.child.position());
}
</script>
子组件 Son.vue
<template>
<div>
孩子的位置: {{position}}
</div>
</template>
<script setup>
import { ref , defineExpose } from 'vue'
let position= ref('我在北边的小卖铺里').value
let tellFatherMyPositon = function () {
alert(position)
}
//向外暴露指定属性
defineExpose({
position,
tellFatherMyPositon
})
</script>