深度解析Vue.js组件间的通信方式

Vue.js 组件通信主要通过以下几种方式来实现:

Props(属性)

  • 方向:父组件到子组件
  • 用途:父组件通过属性向子组件传递数据。
  • 特性:
    • 只读:默认情况下,子组件不能改变props的值。
    • 验证:可以通过props选项定义验证规则。
    • 动态:props的值可以随父组件状态的变化而变化。
父组件(Parent.vue)
<template>
  <div>
    <ChildComponent :message="parentMessage" />
  </div>
</template>

<script>
import ChildComponent from './ChildComponent.vue';

export default {
  components: {
    ChildComponent
  },
  data() {
    return {
      parentMessage: 'Hello from Parent'
    };
  }
};
</script>
子组件(ChildComponent.vue)
<template>
  <div>
    <p>{{ message }}</p>
  </div>
</template>

<script>
export default {
  props: {
    message: String
  }
};
</script>

$emit(事件)

  • 方向:子组件到父组件
  • 用途:子组件通过触发自定义事件来通知父组件。
  • 特性:
    • 传递数据:事件可以携带数据。
    • 多个事件:子组件可以触发多个不同的事件。
子组件(ChildComponent.vue)
<template>
  <button @click="notifyParent">Notify Parent</button>
</template>

<script>
export default {
  methods: {
    notifyParent() {
      this.$emit('child-event', 'Hello from Child');
    }
  }
};
</script>
父组件(Parent.vue)
<template>
  <ChildComponent @child-event="handleChildEvent" />
</template>

<script>
import ChildComponent from './ChildComponent.vue';

export default {
  components: {
    ChildComponent
  },
  methods: {
    handleChildEvent(data) {
      console.log('Received data from child:', data);
    }
  }
};
</script>

Vuex

  • 全局状态管理
  • 用途:用于管理整个应用的状态,任何组件都可以访问。
  • 特性:
    • State:存储全局状态。
    • Mutations:唯一改变state的方式,同步操作。
    • Actions:用于异步操作,可以派发mutations。
    • Getters:计算属性,基于state创建缓存的属性。
    • Modules:大型应用中可以分割状态管理模块。
首先,设置 Vuex Store:

store.js

import Vue from 'vue';
import Vuex from 'vuex';

Vue.use(Vuex);

export default new Vuex.Store({
  state: {
    sharedCounter: 0
  },
  mutations: {
    increment(state) {
      state.sharedCounter++;
    }
  },
  actions: {
    incrementAsync({ commit }) {
      setTimeout(() => {
        commit('increment');
      }, 1000);
    }
  },
  getters: {
    getCounter: state => state.sharedCounter
  }
});

主应用(main.js)

确保应用使用了 Vuex Store

import Vue from 'vue';
import App from './App.vue';
import store from './store';

new Vue({
  store,
  render: h => h(App)
}).$mount('#app');
父/子组件使用 Vuex

可以在任何组件中通过 this.$store 访问 Vuex Store

ComponentUsingVuex.vue

<template>
  <div>
    <p>Counter: {{ counter }}</p>
    <button @click="increment">Increment</button>
    <button @click="incrementAsync">Increment Async</button>
  </div>
</template>

<script>
export default {
  computed: {
    counter() {
      return this.$store.getters.getCounter;
    }
  },
  methods: {
    increment() {
      this.$store.commit('increment');
    },
    incrementAsync() {
      this.$store.dispatch('incrementAsync');
    }
  }
};
</script>

Provide/Inject

  • 跨级通信
  • 用途:允许祖先组件提供数据,后代组件注入数据,无需依赖父组件层级。
  • 特性:
    • 不受组件层次限制,但可能导致代码耦合度增加。
    • 不推荐在常规组件通信中广泛使用,更适合库或框架级别的数据传递。
祖先组件(AncestorComponent.vue)
<template>
  <div>
    <ChildComponent />
  </div>
</template>

<script>
export default {
  provide() {
    return {
      ancestorValue: 'Value from Ancestor'
    };
  }
};
</script>
后代组件(DescendantComponent.vue)
<template>
  <div>
    <p>Value from Ancestor: {{ injectedValue }}</p>
  </div>
</template>

<script>
export default {
  inject: ['ancestorValue'],
  mounted() {
    console.log('Injected value:', this.injectedValue);
  }
};
</script>

Ref 和 v-model

  • 直接引用
  • 用途:父组件直接引用子组件实例,或双向数据绑定。
  • 特性:
    • Refs:用于获取子组件实例或DOM元素,进行直接操作。
    • v-model:用于双向数据绑定,常见于表单元素,也可以应用于自定义组件。
父组件(ParentComponent.vue)
<template>
  <ChildComponent ref="childRef" v-model="parentValue" />
  <button @click="logChildRef">Log Child Ref</button>
</template>

<script>
import ChildComponent from './ChildComponent.vue';

export default {
  components: {
    ChildComponent
  },
  data() {
    return {
      parentValue: 'Initial Value'
    };
  },
  methods: {
    logChildRef() {
      console.log(this.$refs.childRef);
    }
  }
};
</script>
子组件(ChildComponent.vue)
<template>
  <input :value="value" @input="$emit('input', $event.target.value)" />
</template>

<script>
export default {
  props: ['value']
};
</script>

Custom Events(自定义事件)

  • 事件通信
  • 用途:自定义事件允许组件间非标准的通信。
  • 特性:
    • 可以在任何组件之间触发和监听。
    • 适用于特定的交互或组件间的复杂通信。
子组件(ChildComponent.vue)
<template>
  <button @click="customEvent">Send Custom Event</button>
</template>

<script>
export default {
  methods: {
    customEvent() {
      this.$emit('custom-event', 'Data to send');
    }
  }
};
</script>
父组件(ParentComponent.vue)
<template>
  <ChildComponent @custom-event="handleCustomEvent" />
</template>

<script>
import ChildComponent from './ChildComponent.vue';

export default {
  components: {
    ChildComponent
  },
  methods: {
    handleCustomEvent(data) {
      console.log('Received custom event data:', data);
    }
  }
};
</script>

Slots(插槽)

  • 内容分发
  • 用途:允许父组件的内容插入到子组件的特定位置。
  • 特性:
    • 默认插槽:子组件的默认内容区域。
    • 具名插槽:子组件可以定义多个插槽,父组件指定插入内容的位置。
    • 作用域插槽:父组件可以访问子组件的数据来决定插槽内容。
父组件(ParentComponent.vue)
<template>
  <WrapperComponent>
    <h1 slot="header">Custom Header</h1>
    <p slot="body">Custom Body Content</p>
  </WrapperComponent>
</template>

<script>
import WrapperComponent from './WrapperComponent.vue';

export default {
  components: {
    WrapperComponent
  }
};
</script>
WrapperComponent.vue
<template>
  <div>
    <slot name="header"></slot>
    <div class="content">
      <slot name="body"></slot>
    </div>
  </div>
</template>

Composition API(组合API)

  • 新功能
  • 用途:Vue 3引入的新特性,允许在组件内更好地组织逻辑和数据。
  • 特性:
    • setup() 函数:在组件生命周期开始时运行,可以访问props和触发生命周期钩子。
    • refreactive:用于响应式数据管理。
    • provideinject:在组合API中也有相应的实现,更灵活地进行跨组件数据传递。
父组件(ParentComponent.vue)
<template>
  <ChildComponent :count="count" @updateCount="updateCount" />
</template>

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

export default {
  components: {
    ChildComponent
  },
  setup() {
    const count = ref(0);
    
    function updateCount(newCount) {
      count.value = newCount;
    }

    onMounted(() => {
      console.log('Initial count:', count.value);
    });

    return {
      count,
      updateCount
    };
  }
};
</script>
子组件(ChildComponent.vue)
<template>
  <button @click="increment">Increment</button>
</template>

<script>
import { ref, emit } from 'vue';

export default {
  props: ['count'],
  setup(props) {
    const count = ref(props.count);

    function increment() {
      count.value++;
      emit('updateCount', count.value);
    }

    return {
      count,
      increment
    };
  }
};
</script>

2500G计算机入门到高级架构师开发资料超级大礼包免费送!

  • 35
    点赞
  • 28
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

天涯学馆

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值