一、Props/$emit(常用)
- 父组件向子组件传值
// 父组件
<template>
<div class="section">
<studentName :nameList="nameList"></studentName>
</div>
</template>
<script>
import studentName from './test/name.vue'
export default {
name: 'HelloWorld',
components: { studentName },
data() {
return {
nameList: ['猪八戒', '孙悟空', '沙和尚']
}
}
}
</script>
// 子组件
<template>
<div>
<span v-for="(item, index) in nameList" :key="index">{{item}}</span>
</div>
</template>
<script>
export default {
props: ['nameList']
}
</script>
注意:prop 只可以从上一级组件传递到下一级组件(父子组件)
- 子组件向父组件传值
// 父组件
<template>
<div class="section">
<studentName :nameList="nameList" @onGetIndex="onGetIndex"></studentName>
</div>
</template>
<script>
import studentName from './test/name.vue'
export default {
name: 'HelloWorld',
components: { studentName },
data() {
return {
nameList: ['猪八戒', '孙悟空', '沙和尚']
}
},
methods: {
onGetIndex(idx) {
this.currentIndex = idx
}
}
}
</script>
// 子组件
<template>
<div>
<span v-for="(item, index) in nameList" :key="index" @click="getIndex(index)">{{item}}</span>
</div>
</template>
<script>
export default {
props: ['nameList']
},
methods: {
getIndex(index) {
this.$emit('onGetIndex', index)
}
}
</script>
二、$parent/ $children(少使用)
注意:节制使用,他们主要目的是作为访问组件的应急方法,一般情况下推荐使用第一种通信
// 父组件中
<template>
<div class="hello_world">
<div>{{parentName}}</div>
<com-a></com-a>
<button @click="changeA">点击改变子组件值</button>
</div>
</template>
<script>
import ComA from './child.vue'
export default {
name: 'HelloWorld',
components: { ComA },
data() {
return {
parentName: '唐昊'
}
},
methods: {
changeA() {
// 获取到子组件A
this.$children[0].childName = '海神'
}
}
}
</script>
// 子组件中
<template>
<div >
<span>{{childName}} =》父亲: {{parentVal}}</span>
</div>
</template>
<script>
export default {
data() {
return {
childName: '唐三'
}
},
computed:{
parentVal(){
return this.$parent.parentName;
}
}
}
</script>
三、provide/inject
注意: 这里不论子组件嵌套有多深, 只要调用了inject 那么就可以注入provide中的数据,而不局限于只能从当前父组件的props属性中获得数据
//全局组件挂载刷新页面方法
<template>
<div id="app">
<router-view v-if="isRouterAlive" />
</div>
</template>
<script>
export default {
name: 'App',
provide(){
return {
reload:this.reload
}
},
data(){
return{
isRouterAlive:true
}
},
methods:{
reload(){
this.isRouterAlive=false
this.$nextTick(function(){
this.isRouterAlive=true
})
}
}
}
</script>
// 子组件中
<template>
<div >
<span @click='reloadPage'>{{childName}} =》父亲: {{parentVal}}</span>
</div>
</template>
<script>
export default {
data() {
return {
childName: '唐三'
}
},
inject:['reload'],
mounted() {
},
computed:{
parentVal(){
return this.$parent.parentName;
},
//调用刷新当前页面
reloadPage(){
this.reload()
}
}
}
</script>
四、ref/ refs
注意:ref如果在普通的 DOM 元素上使用,引用指向的就是 DOM 元素;如果用在子组件上,引用就指向组件实例,可以通过实例直接调用组件的方法或访问数据
<template>
<view>
<!-- <tom :name='childName' ref='com' @click='onGetCom'></tom> -->
<jack :name='childName' v-if="isRouterAlive" ref='com' ></jack>
<div ref='dom' @click='onGetDom'>元素</div>
</view>
</template>
<script>
import tom from '../../components/child.vue'
import jack from '../../components/parent.vue'
export default {
data() {
return {
childName: 'Jack',
isRouterAlive: true
}
},
provide(){
return {
reload:this.reload
}
},
components:{
tom,
jack
},
mounted () {
const parent = this.$refs.com
this.onGetDom()
console.log(parent.parentName)
},
methods: {
reload(){
this.isRouterAlive=false
console.log('刷新页面')
this.$nextTick(function(){
this.isRouterAlive=true
})
},
// 指向元素
onGetDom(){
console.log(this.$refs.dom)
}
}
}
</script>
// 子组件中
<template>
<div class="hello_world">
<div>{{parentName}}</div>
<!-- <com-a></com-a> -->
<button @click="changeA">点击改变子组件值</button>
</div>
</template>
<script>
// import ComA from './child.vue'
export default {
name: 'HelloWorld',
// components: { ComA },
data() {
return {
parentName: '唐昊'
}
},
methods: {
// changeA() {
// // 获取到子组件A
// this.$children[0].childName = '海神'
// }
}
}
</script>
打印结果:
五、eventBus
// event-bus.js
import Vue from 'vue'
export const EventBus = new Vue()
<template>
<div>
<show-num-com></show-num-com>
<addition-num-com></addition-num-com>
</div>
</template>
<script>
import showNumCom from './showNum.vue'
import additionNumCom from './additionNum.vue'
export default {
components: { showNumCom, additionNumCom }
}
</script>
// addtionNum.vue 中发送事件
<template>
<div>
<button @click="additionHandle">+加法器</button>
</div>
</template>
<script>
import {EventBus} from './event-bus.js'
console.log(EventBus)
export default {
data(){
return{
num:1
}
},
methods:{
additionHandle(){
EventBus.$emit('addition', {
num:this.num++
})
}
}
}
</script>
// showNum.vue 中接收事件
<template>
<div>计算和: {{count}}</div>
</template>
<script>
import { EventBus } from './event-bus.js'
export default {
data() {
return {
count: 0
}
},
mounted() {
EventBus.$on('addition', param => {
this.count = this.count + param.num;
})
}
}
</script>
六、$attrs
// app.vue
// index.vue
<template>
<div>
<child-com1
:name="name"
:age="age"
:gender="gender"
:height="height"
title="程序员成长指北"
></child-com1>
</div>
</template>
<script>
const childCom1 = () => import("./childCom1.vue");
export default {
components: { childCom1 },
data() {
return {
name: "zhang",
age: "18",
gender: "女",
height: "158"
};
}
};
</script>
// childCom1.vue
<template class="border">
<div>
<p>name: {{ name}}</p>
<p>childCom1的$attrs: {{ $attrs }}</p>
<child-com2 v-bind="$attrs"></child-com2>
</div>
</template>
<script>
const childCom2 = () => import("./childCom2.vue");
export default {
components: {
childCom2
},
inheritAttrs: false, // 可以关闭自动挂载到组件根元素上的没有在props声明的属性
props: {
name: String // name作为props属性绑定
},
created() {
console.log(this.$attrs);
// { "age": "18", "gender": "女", "height": "158", "title": "程序员成长指北" }
}
};
</script>
// childCom2.vue
<template>
<div class="border">
<p>age: {{ age}}</p>
<p>childCom2: {{ $attrs }}</p>
</div>
</template>
<script>
export default {
inheritAttrs: false,
props: {
age: String
},
created() {
console.log(this.$attrs);
// { "gender": "女", "height": "158", "title": "程序员成长指北" }
}
};
</script>
七、vuex
- Vuex介绍
Vuex 是一个专为 Vue.js 应用程序开发的状态管理模式。它采用集中式存储管理应用的所有组件的状态,并以相应的规则保证状态以一种可预测的方式发生变化.
Vuex 解决了多个视图依赖于同一状态和来自不同视图的行为需要变更同一状态的问题,将开发者的精力聚焦于数据的更新而不是数据在组件之间的传递上 - Vuex各个模块
state:用于数据的存储,是store中的唯一数据源
getters:如vue中的计算属性一样,基于state数据的二次包装,常用于数据的筛选和多个数据的相关性计算
mutations:类似函数,改变state数据的唯一途径,且不能用于处理异步事件
actions:类似于mutation,用于提交mutation来改变状态,而不直接变更状态,可以包含任意异步操作
modules:类似于命名空间,用于项目中将各个模块的状态分开定义和操作,便于维护
// 父组件
<template>
<div id="app">
<ChildA/>
<ChildB/>
</div>
</template>
<script>
import ChildA from './components/ChildA' // 导入A组件
import ChildB from './components/ChildB' // 导入B组件
export default {
name: 'App',
components: {ChildA, ChildB} // 注册A、B组件
}
</script>
// 子组件childA
<template>
<div id="childA">
<h1>我是A组件</h1>
<button @click="transform">点我让B组件接收到数据</button>
<p>因为你点了B,所以我的信息发生了变化:{{BMessage}}</p>
</div>
</template>
<script>
export default {
data() {
return {
AMessage: 'Hello,B组件,我是A组件'
}
},
computed: {
BMessage() {
// 这里存储从store里获取的B组件的数据
return this.$store.state.BMsg
}
},
methods: {
transform() {
// 触发receiveAMsg,将A组件的数据存放到store里去
this.$store.commit('receiveAMsg', {
AMsg: this.AMessage
})
}
}
}
</script
// 子组件 childB
<template>
<div id="childB">
<h1>我是B组件</h1>
<button @click="transform">点我让A组件接收到数据</button>
<p>因为你点了A,所以我的信息发生了变化:{{AMessage}}</p>
</div>
</template>
<script>
export default {
data() {
return {
BMessage: 'Hello,A组件,我是B组件'
}
},
computed: {
AMessage() {
// 这里存储从store里获取的A组件的数据
return this.$store.state.AMsg
}
},
methods: {
transform() {
// 触发receiveBMsg,将B组件的数据存放到store里去
this.$store.commit('receiveBMsg', {
BMsg: this.BMessage
})
}
}
}
</script>
import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex)
const state = {
// 初始化A和B组件的数据,等待获取
AMsg: '',
BMsg: ''
}
const mutations = {
receiveAMsg(state, payload) {
// 将A组件的数据存放于state
state.AMsg = payload.AMsg
},
receiveBMsg(state, payload) {
// 将B组件的数据存放于state
state.BMsg = payload.BMsg
}
}
export default new Vuex.Store({
state,
mutations
})
总结
- 父子组件通信: props; $parent / $children; provide / inject ; ref ; $attrs / $listeners
- 兄弟组件通信: eventBus ; vuex
- 跨级通信: eventBus;Vuex;provide / inject 、$attrs / $listeners