VUE总结
在面试中经常被问到,工作实际中也常常使用到,立马来篇博客总结记录
props和$emit
父组件向子组件传值
在父组件中通过props来把数据传入子组件
-
父组件中
在子组件标签中添加自定义属性,并通过
v-bind
动态赋值绑定要传给子组件的值
<template>
<div class="parent">
<child :message="childData"></child>
</div>
</template>
<script>
import Child from './child'
export default {
components: { Child },
data() {
return {
childData: "父传子"
}
}
}
</script>
复制代码
-
子组件中
通过props选项来拿到父组件传输过来的值,可对值的类型和初始值进行定义
<template>
<div>
<span>{{message}}</span>
</div>
</template>
<script>
export default {
props:{
message:{
type:String,
default: () => ''
}
}
}
</script>
复制代码
子组件向父组件传值
因为Vue是单向数据流,所以不能直接在子组件中修改父组件传输过来的值,而是子组件通过$emit
来触发事件告知父组件去修改值
-
子组件中
在相关事件触发的函数中,通过
$emit
来告知父组件更改数据,第一个参数是父组件中子组件标签上自定义事件的名字,第二个参数是传给父组件的值,也就是父组件中自定义事件触发函数的参数。
<template>
<div>
<span>{{message}}</span>
<button @click="sendMsgToParent">
子传父
</button>
</div>
</template>
<script>
export default {
props:{
message:{
type:String,
default: () => ''
}
},
methods:{
sendMsgToParent(){
this.$emit("listenChildEvent","this data is from child");
}
}
}
</script>
复制代码
-
父组件中
父组件中通过自定义事件绑定的函数来拿到子组件传递过来的data,进行相关值的操作
<template>
<div class="parent">
<child :message="childData" @listenChildEvent="acceptMsgFromChild"></child>
</div>
</template>
<script>
import child from './child.vue';
export default {
data() {
return {
childData: "父传子"
};
},
components: {
Child
},
methods:{
acceptMsgFromChild(data){
console.log(data);//或者将接受值处理
}
}
}
</script>
复制代码
v-model
v-model来做表单双向数据绑定,v-model=“msg"实则是 :value=“msg” @input=“msg = $event.target.value"的语法糖。所以v-model指令同时做了两件事:
1.监听input输入事件 2.将输入的值绑定到对应数据上
了解v-model的自带input事件 ,在父组件中通过v-model来绑定相关数据,子组件就可以通过$emit
来触发input事件,将值传递给父组件。
- 父组件中
<template>
<div class="parent">
<child v-model="data"></child>
</div>
</template>
<script>
import child from './child.vue';
export default {
data() {
return {
data: "父子间v-model通信"
};
},
components: {
Child
}
}
</script>
复制代码
- 子组件中
1.通过点击事件来触发父子组件数据同步
2.父组件中 v-model 绑定的值,只能通过value 这个属性名来传输
3.通过$emit来触发父组件v-model的input事件,第二个参数就是传给父组件将要更新的值
<template>
<div>
<span>{{value}}</span>
<button @click="shareMsgToParent">数据同步</button>
</div>
</template>
<script>
export default {
props:{
value:{
type:String,
default: () => ''
}
},
methods:{
shareMsgToParent(){
this.$emit("input","this data is from child");
}
}
}
</script>
复制代码
上面的操作限制了我们必须props接收的属性名为value和emit触发的必须为input,这样就容易有冲突,所以,为了更优雅的使用v-model通信而解决冲突的问题,我们可以通过在子组件中使用
model
选项,来定义属性名和要触发的事件名
- 子组件中使用v-model
<template>
<div>
<span>{{checked}}</span>
<button @click="shareMsgToParent">数据同步</button>
</div>
</template>
<script>
export default {
model: {
prop: 'checked',
event: 'change'
},
props:{
value:{
type:String,
default: () => ''
}
},
methods:{
shareMsgToParent(){
this.$emit("change","this data is from child");
}
}
}
</script>
复制代码
PS: 双向数据绑定的方法还有.sync
在另外一篇博客中有总结查看
$attrs
和 $listeners
可以将父组件的数据传递给子孙组件,适用于只传递数据不做中间件处理的时候,但在项目中很少用到,简单了解即可。
$attrs
包含了父作用域中不被认为 (且不预期为) props 的特性绑定 (class 和 style 除外),并且可以通过 v-bind=”$attrs” 传入内部组件。当一个组件没有声明任何 props 时,它包含所有父作用域的绑定 (class 和 style 除外)。
$listeners
包含了父作用域中的 (不含 .native 修饰符) v-on 事件监听器。它可以通过 v-on=”$listeners” 传入内部组件。它是一个对象,里面包含了作用在这个组件上的所有事件监听器,相当于子组件继承了父组件的事件。
简单来说,$attrs
是用来获取父组件中的属性数据的,$listeners
是用来获取父组件中的事件
- 父组件
<template>
<child :name="name" :message="message" @sayHello="sayHello"></child>
</template>
<script>
export default {
inheritAttrs: false,
data() {
return {
name: '通信',
message: 'Hi',
}
},
methods: {
sayHello(mes) {
console.log('mes', mes) // => "hello"
},
},
}
</script>
复制代码
- 子组件
<template>
<grandchild v-bind="$attrs" v-on="$listeners"></grandchild>
</template>
<script>
export default {
data() {
return {}
},
props: {
name,
},
created() {
console.log(this.$attrs);
// 结果: message, 因为父组件共传来name, message两个值,由于name被 props接收了,所以只有message属性
console.log(this.$listeners); // sayHello: f
}
}
</script>
复制代码
- 孙组件
<template>
</template>
<script>
export default {
created() {
console.log(this.$attrs); // name,message
console.log(this.$listeners) // sayHello: f
this.$emit('sayHello', 'hello')//可以触发 father 组件中的sayHello函数
},
}
</script>
复制代码
$parent
和 $children
子组件可以用 this.$parent
访问父组件,子组件被推入父组件的 $children
数组中。
官方提示:节制地使用
$parent
和$children
- 它们的主要目的是作为访问组件的应急方法。更推荐用 props 和 events 实现父子组件通信,并且$children
不保证顺序也不是响应式的。
- 父组件
<template>
<div class="father">
<child></child>
<button @click="name">点击改变子组件的值</button>
</div>
</template>
<script>
import child from './child'
export default {
components: { child },
data() {
return {
msg: '父组件message'
}
},
methods:{
name(){
this.$children[0].message = "hello"
}
}
}
</script>
复制代码
- 子组件
<template>
<div class="com_a">
<span>{{message}}</span>
<p>获取父组件的值:{{parentVal}}</p>
</div>
</template>
<script>
export default {
data(){
return {
message:'子组件message'
}
},
computed:{
parentVal(){
return this.$parent.msg;
}
}
}
</script>
复制代码
EventBus
在小型的项目中使用,
1.在入口函数中初始化evnetBus,将一个新的vue实例放在原型链上作为全局的$eventBus
Vue.prototype.$eventBus = new Vue()
复制代码
2.实例化的vue自带$on
、$emit
和$off
方法
his.$eventBus.$emit('nameOfEvent', { ... pass some event data ...});//创建发出的事件
this.$eventBus.$on('nameOfEvent',($event) => {
// ...
}) // 监听事件
this.$eventBus.$off('nameOfEvent') //移除事件监听
复制代码
provide和inject
父组件通过provide以对象的形式向子组件暴露一些属性,子组件通过inject注入相应属性。
-
祖先组件
provide选项:一个对象或返回一个对象的函数。该对象包含可注入其子孙的 property。
<template>
<div>
<child prop="data"></child>
</div>
</template>
<script>
export default {
provide: {
name: 'Tom'
}
}
复制代码
-
后代组件
inject选项:一个字符串数组或一个对象,对象的 key 是本地的绑定名,value是注入内容的key
<template>
<div>
{{name}}
</div>
</template>
<script>
export default {
name: 'child',
inject: [name]
}
</script>
复制代码
注意的点
provide
和inject
绑定并不是可响应的。这是刻意为之的。然而,如果你传入了一个可监听的对象,那么其对象的属性还是可响应的。
Vue 不会对 provide 中的变量进行响应式处理。所以,要想 inject 接受的变量是响应式的,provide 提供的变量本身就需要是响应式的。vue组件中的状态就是可响应的,直接在根组件中将组件本身注入 provide,就可以在后代组件中任意访问根组件中的所有状态,根组件就成为了全局状态的容器
provide
和inject
主要在开发高阶插件/组件库时使用。并不推荐用于普通应用程序代码中。
原因:provide/inject 中变量的修改是无法控制的,并且它破坏了vue的单向数据流,多个后代依赖了同一个祖先的状态,只要一个后代对状态进行了改变,则其他的组件都会受到影响,所以最好不要使用 provide/inject 做全局状态管理,而是使用可以追踪回溯的vuex。
vuex
Vuex是一个状态管理的插件,可以解决不同组件之间的数据共享和数据持久化,适用于大型项目。
- State:存储状态数据
- Getter:从状态数据派生数据,相当于State的计算属性。
- Mutation:存储用于同步更改状态数据的方法,默认传入的参数为state。
- Action:存储用于异步更改状态数据,但不是直接更改,而是通过触发Mutation方法实现,默认参数为context。
- Module:Vuex模块化。
vuex知识点较多,日后再学习总结~
总结
- 父子间通信最常用的就是props/$emit和v-model
- 如果是嵌套组件通信,开发组件库可以使用provide/inject,中小型项目可以使用EventBus
- 大型项目中使用vuex来进行兄弟之间和跨级之间通信
参考博客
作者:Blend 链接:https://juejin.cn/post/6950088782381056013 来源:掘金 著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。