组件多层嵌套传递数据

79 阅读2分钟

1. 逐层传递(props 和 $emit)

props 从父组件传递到子组件,子组件可通过 $emit 触发自定义事件将数据传递给父组件

props

<!-- 父组件 -->
<template>
  <Child :msg="data" />
</template>
<script>
import Child from './Child.vue';
export default {
  components: { Child },
  data() {
    return { data: '顶层数据' }
  }
}
</script>

<!-- 子组件 -->
<template>
  <GrandChild :message="msg" />
</template>
<script>
import GrandChild from './GrandChild.vue';
export default {
  components: { GrandChild },
  props: ['msg']
}
</script>

<!-- 孙组件 -->
<template>
  <p>{{ message }}</p>
</template>
<script>
export default {
  props: ['message']
}
</script>

$emit

<!-- 父组件 -->
<template>
  <Child @update="data = $event" />
  <p>{{ data }}</p>
</template>
<script>
import Child from './Child.vue';
export default {
  components: { Child },
  data() {
    return { data: '初始值' }
  }
}
</script>

<!-- 子组件 -->
<template>
  <GrandChild @change="handleChange" />
</template>
<script>
import GrandChild from './GrandChild.vue';
export default {
  components: { GrandChild },
  methods: {
    handleChange(value) {
      this.$emit('update', value);
    }
  }
}
</script>

<!-- 孙组件 -->
<template>
  <button @click="sendData">点击</button>
</template>
<script>
export default {
  methods: {
    sendData() {
      this.$emit('change', '来自底层的数据');
    }
  }
}
</script>

2. 事件总线(Event Bus)

事件总线是一个全局的事件发射器,可用于在不同组件间传递数据,无需考虑组件的嵌套关系

<!-- 顶层组件:App.vue -->
<template>
  <div>
    <DeepChildComponent />
    <p>接收到的数据: {{ receivedData }}</p>
  </div>
</template>

<script>
import { eventBus } from './EventBus.js';
import DeepChildComponent from './DeepChildComponent.vue';

export default {
  components: { DeepChildComponent },
  data() {
    return {
      receivedData: ''
    };
  },
  created() {
    eventBus.$on('data-updated', (data) => {
      this.receivedData = data;
    });
  },
  beforeDestroy() {
    eventBus.$off('data-updated');
  }
};
</script>

<!-- 深层子组件:DeepChildComponent.vue -->
<template>
  <button @click="sendData">发送数据</button>
</template>

<script>
import { eventBus } from './EventBus.js';

export default {
  methods: {
    sendData() {
      eventBus.$emit('data-updated', '深层数据');
    }
  }
};
</script>

3. Vuex 状态管理

// store.js
import { createStore } from 'vuex';

export default createStore({
  state: {
    message: '初始消息'
  },
  mutations: {
    SET_MESSAGE(state, payload) {
      state.message = payload;
    }
  },
  actions: {
    updateMessage({ commit }, payload) {
      commit('SET_MESSAGE', payload);
    }
  },
  getters: {
    getMessage: (state) => state.message
  }
});

//App.vue
<template>
  <div>
    <h1>父组件</h1>
    <p>消息: {{ message }}</p>
    <ChildComponent />
  </div>
</template>

<script>
import ChildComponent from './ChildComponent.vue';
import { mapGetters } from 'vuex';

export default {
  components: { ChildComponent },
  computed: {
    ...mapGetters(['getMessage']),
    message() {
      return this.getMessage;
    }
  }
};
</script>

//ChildComponent.vue
<template>
  <div>
    <h2>深层子组件</h2>
    <button @click="updateMessage('来自深层组件的消息')">
      更新消息
    </button>
  </div>
</template>

<script>
import { mapActions } from 'vuex';

export default {
  methods: {
    ...mapActions(['updateMessage'])
  }
};
</script>
  1. 定义状态:在 store 中定义 message
  2. 读取状态:父组件通过 mapGetters 获取 message
  3. 修改状态:子组件通过 mapActions 触发 updateMessage
  4. 自动更新:所有使用 message 的组件会自动更新

4. provide 和 inject

provideinject 是 Vue 提供的一对用于实现跨级组件数据传递的选项provide 选项允许一个组件向其所有子孙组件注入一个依赖,不论组件嵌套有多深,都能在其子孙组件中通过 inject 选项来使用这个依赖。不过这种方式是单向的,由父组件流向子组件,且一旦注入就不能在子组件中修改父组件提供的数据。

//父组件(提供数据)
<template>
  <ChildComponent />
</template>

<script>
import { provide, ref } from 'vue';
import ChildComponent from './ChildComponent.vue';

export default {
  components: { ChildComponent },
  setup() {
    const message = ref('顶层数据');
    
    // 提供数据
    provide('message', message);
    
    return {};
  }
};
</script>


//深层子组件(注入数据)
<template>
  <p>{{ message.value }}</p>
</template>

<script>
import { inject } from 'vue';

export default {
  setup() {
    // 注入数据
    const message = inject('message');
    
    return { message };
  }
};
</script>
  1. provide:父组件通过 provide('key', value) 提供数据
  2. inject:任意后代组件通过 inject('key') 获取数据
  3. 响应式:使用 ref 包裹的数据会自动响应更新