本文目录:
- 1.父组件向子组件传值及优化
- 2.子组件向父组件传数据
- 3.prop单向数据流
- 4.Prop / $emit
- 5.
on`
- 6.Vuex
- 7.其他常见方法
- 8.总结
1.父组件向子组件传值及优化
父组件向子组件传数据口诀:冒号传,props收,子组件内部就可以重新使用了
子组件top组件结构代码
<div class="header">
<div class="personal" @click="goToUsercenter">我 的</div>
<div>MIKO</div>
<i class="iconfont icon-chaxun" @click="goToSearch"></i>
</div>
这个top组件的标题,图片地址,和总计歌曲数量都是由使用它的父组件传递进来的
其props代码如下
props: {
title: {
type: String,
default: ""
},
img: {
type: String,
default: ""
},
count: {
type: Number,
default: 0
}
}
不设定默认值的写法:
props: {
title: String,
img: String,
count: Number
}
引用它的父组件标签代码
<top :title="title" :img="img" :count="formatData.length"></top>
title和img可以直接是data中的变量,但是这样写不是很完善,如:
<top :title="formatData[0].name" :img="formatData[0].al.picUrl" :count="formatData.length"></top>
为了优化体验,也可以设定在computed中:
computed: {
title() {
if (this.formatData.length > 0) {
return this.formatData[0].name;
} else {
return "暂无数据";
}
}
}
如果既想优化代码,又不想使用computed,也可以用v-if
<top v-if="formatData.length" :title="formatData[0].name" :img="formatData[0].al.picUrl" :count="formatData.length"></top>
2.子组件向父组件传数据
子组件向父组件传递消息,是通过子组件调用父组件的事件,然后用参数的形式传递的
需求:子组件的按钮点击触发自定义事件_event,同时把自身的数据“xiaohong”传递出去,父组件接收这个数据并且进行使用
子组件代码
<button @click="$emit('_myevent', 'nodeing')">点击</button>
父组件代码在调用子组件的标签中通过自定义事件触发自身的事件:
<children-component @_myevent="sayhi"></children-component>
触发了自身的的sayhi事件:
methods: {
sayhi(name){
alert('hi,' + name)
}
}
3.prop单向数据流
所有的 prop 都使得其父子 prop 之间形成了一个单向下行绑定:父级 prop 的更新会向下流动到子组件中,但是反过来则不行。
这样会防止从子组件意外改变父级组件的状态,从而导致你的应用的数据流向难以理解。
额外的,每次父级组件发生更新时,子组件中所有的 prop 都将会刷新为最新的值。
这意味着你不应该在一个子组件内部改变 prop。如果你这样做了,Vue 会在浏览器的控制台中发出警告。
子组件想修改时,只能通过 $emit 派发一个自定义事件,父组件接收到后,由父组件修改。
有两种常见的试图改变一个 prop 的情形 :
1.这个 prop 用来传递一个初始值;这个子组件接下来希望将其作为一个本地的 prop 数据来使用。 在这种情况下,最好定义一个本地的 data 属性并将这个 prop 用作其初始值:
props: ['initialCounter'],
data: function () {
return {
counter: this.initialCounter
}
}
2.这个 prop 以一种原始的值传入且需要进行转换。 在这种情况下,最好使用这个 prop 的值来定义一个计算属性
props: ['size'],
computed: {
normalizedSize: function () {
return this.size.trim().toLowerCase()
}
}
以上的是最常用的两种父子组件传值的方法,实际项目中的组件关系不止是父子关系,还有其他更复杂的关系,下面是对常见的组件通信方案的总结:
4.Prop / $emit
1、 Prop 是你可以在组件上注册的一些自定义特性。当一个值传递给一个 Prop 特性的时候,它就变成了那个组件实例的一个属性 。父组件向子组件传值,通过绑定属性来向子组件传入数据,子组件通过 props 属性获取对应数据。
父组件代码:
<child :title="title"></child>
子组件代码:
props: {
title: {
type: String
}
}
2、emit 事件向父组件发送消息,将自己的数据传递给父组件。
父组件代码
<child @changeTitle="parentTitle"></child>
......
parentTitle(e) {
this.title = e;
}
子组件代码
<button @click="childTitle">我给父组件赋值</button>
childTitle(){
this.$emit('changeTitle', 'new-title')
}
5.$emit / $on
这个方法是通过创建了一个空的 vue 实例,当做 $emit 事件的处理中心(事件总线),通过他来触发以及监听事件,方便的实现了任意组件间的通信,包含父子,兄弟,隔代组件。
父组件代码
<template>
<div class="container">
<child1 :Event="Event"></child1>
<child2 :Event="Event"></child2>
<child3 :Event="Event"></child3>
</div>
</template>
<script>
import Vue from "vue";
import Child1 from "./component/child1.vue";
import Child2 from "./component/child2.vue";
import Child3 from "./component/child3.vue";
const Event = new Vue();
export default {
name: "demo",
data: function() {
return {
Event: Event
};
},
components: {
Child1,
Child2,
Child3
},
};
</script>
子组件child1.vue代码
<template>
<div class="center">
1.我的名字是:{{name}}
<button @click="send">我给3组件赋值</button>
</div>
</template>
<script>
export default{
name: "demo1",
data() {
return {
name: "大卫"
};
},
props: {
Event
},
methods: {
send() {
this.Event.$emit("message-a", this.name);
}
}
};
</script>
子组件child2.vue代码
<template>
<div class="center">
2.我的年龄是:{{age}}岁
<button @click="send">我给组件3赋值</button>
</div>
</template>
<script>
/* eslint-disable */
export default {
name: "demo2",
data() {
return {
age: "3"
};
},
props: {
Event
},
methods: {
send() {
this.Event.$emit("message-b", this.age);
}
}
};
</script>
子组件child3.vue代码
<template>
<div class="center">我的名字是{{name}},今年{{age}}岁</div>
</template>
<script>
export default{
name: 'demo3',
data() {
return {
name: '',
age: ''
};
},
props: {
Event
},
mounted() {
this.Event.$on('message-a', name => {
this.name = name;
});
this.Event.$on('message-b', age => {
this.age = age;
});
},
};
</script>
总结:巧妙的在父子,兄弟,隔代组件中都可以互相数据通信。
6.Vuex
Vuex是一个专为 Vue.js 应用程序开发的状态管理模式。它采用集中式存储管理应用的所有组件的状态,并以相应的规则保证状态以一种可预测的方式发生变化。
Vuex 实现了一个单项数据流,通过创建一个全局的 State 数据,组件想要修改 State 数据只能通过 Mutation 来进行,例如页面上的操作想要修改 State 数据时,需要通过 Dispatch (触发 Action ),而 Action 也不能直接操作数据,还需要通过 Mutation 来修改 State 中数据,最后根据 State 中数据的变化,来渲染页面。
Vuex的详细用法见文集《Vue全家桶》中的文章《详解Vuex》。
7.其他常见方法
-
$attrs/$listeners - Provider / Inject
-
$parent/$children&$refs
$parent / $children: 指定已创建的实例之父实例,在两者之间建立父子关系。子实例可以用 this.$parent 访问父实例,子实例被推入父实例的 $children 数组中。
$refs: 一个对象,持有注册过 ref 特性的所有 DOM 元素和组件实例。ref 被用来给元素或子组件注册引用信息。引用信息将会注册在父组件的 $refs 对象上。如果在普通的 DOM 元素上使用,引用指向的就是 DOM 元素;如果用在子组件上,引用就指向组件。
父组件代码
<template>
<div class="container">
<p>我的title:{{title}}</p>
<p>我的name:{{name}}</p>
<child1 ref="comp1"></child1>
<child2 ref="comp2"></child2>
</div>
</template>
<script>
import Child1 from './component/child1.vue';
import Child2 from './component/child2.vue';
export default {
name: 'demo',
data: function() {
return {
title: null,
name: null,
content: '就是我'
};
},
components: {
Child1,
Child2
},
mounted() {
const comp1 = this.$refs.comp1;
this.title = comp1.title;
comp1.sayHello();
this.name = this.$children[1].title;
},
};
</script>
子组件1:ref方式
<template>
<div>
<div class="center">我的父组件是谁:{{content}}</div>
</div>
</template>
<script>
export default {
name: 'demo1',
data() {
return {
title: '我是子组件',
content: null
};
},
mounted() {
this.content = this.$parent.content;
},
methods: {
sayHello() {
window.alert('Hello');
}
}
};
</script>
子组件2:children方式
<template>
<div>
<div class="center"></div>
</div>
</template>
<script>
export default{
name: 'demo2',
data() {
return {
title: '我是子组件2'
};
},
};
</script>
通过例子可以看到这两种方式都可以父子间通信,而缺点也很统一,就是都不能跨级以及兄弟间通信。
小总结:父子组件间共享数据以及方法的便捷实践之一。
8.总结
组件间不同的使用场景可以分为 3 类,对应的通信方式如下:
• 父子通信:Props / $emit,$emit / $on,Vuex,$attrs / $listeners,provide/inject,$parent / $children&$refs
• 兄弟通信:$emit / $on,Vuex
• 隔代(跨级)通信:$emit / $on,Vuex,provide / inject,$attrs / $listeners
大家可以根据自己的使用场景选择不同的通信方式,当然还是要自己写写代码,试验一把来的印象深刻。