ITPub博客

首页 > 移动开发 > HTML5 > Vue3中的组件通信方式

Vue3中的组件通信方式

原创 HTML5 作者:灬青芒灬 时间:2023-07-24 19:48:39 0 删除 编辑

各种Vue组件间通信/传值

  1. Props(父传子)

    使用 Props 将数据传递给子组件

    父组件:

    
    <
    template
    >
    
      < div class= "container" >
        < h1 >我是父组件props </ h1 >
        < Child msg= "喜欢雪" :money= "money" ></ Child >
      </ div >
    </ template >

    < script setup lang= "ts" >
    import { ref } from "vue";
    import Child from "./Child.vue";
    const money = ref( 100);
    </ script >

    < style scoped >
    .container {
      width: 100vw;
      height: 400px;
      background: skyblue;
    }
    </ style >

    子组件:

    
    <
    template
    >
    
      < div class= "son" >
        < h1 > {{ msg }} </ h1 >
        < h2 > {{ money }} </ h2 >
        < button @click= "update" >点击我修改props </ button >
      </ div >
    </ template >

    < script setup lang= "ts" >
    //采用defineProps方法接受父组件传递过来的props数据
    //此函数不需要引入直接使用
    //此函数执行返回一个代理对象,接受的是父组件传递过来的数据(模版使用可以省略代理对象)
    //props只读的
    let props = defineProps([ "msg", "money"]);
    </ script >

    < style scoped >
    .son {
      width: 600px;
      height: 200px;
      background: #ccc;
    }
    </ style >
  2. Emit(子传父)

    子组件1:

    
    <
    template
    >
    
      < div >
        < h1 >我是子组件:1 </ h1 >
        < button @click= "sendCar" >点击我给爸爸送一台法拉利 </ button >
        < button @click= "sendHouse" >点击我给爸爸送城堡 </ button >
      </ div >
    </ template >

    < script setup lang= "ts" >
    //按钮的回调触发自定义事件回调
    const sendCar = () => {
      //触发自定义事件
      $emit( "car", "法拉利");
    };
    const sendHouse = () => {
      $emit( "house", "成都的城堡");
    };
    //此方法不需要引入,直接使用
    //用于获取$emit方法用于触发自定义事件
    //方法内部需要传递一个数组,数组里面元素即为将来触发的自定义事件类型
    let $emit = defineEmits([ "car", "house"]);
    </ script >

    < style scoped ></ style >

    子组件2:

    
    <
    template
    >
    
      < div >
        < h1 @click= "$emit1('click','哈哈哈我变了')" >我是子组件:2 </ h1 >
        < h1 >我是子组件:2 </ h1 >
        < h1 >我是子组件:2 </ h1 >
        < h1 >我是子组件:2 </ h1 >
        < h1 >我是子组件:2 </ h1 >
        < h1 >我是子组件:2 </ h1 >
      </ div >
    </ template >

    < script setup lang= "ts" >
    let $emit1 = defineEmits([ 'click']);
    </ script >

    < style scoped ></ style >

    父组件:

    
    <
    template
    >
    
      < div class= "event" >
        <!-- 原生DOM事件 -->
        < h1 @click= "handler(1, 2, 3, $event)" >
         明天休息。真开心啊。
        </ h1 >
        < hr />
        <!-- 自定义事件 -->
        < Event1 @car= "handler1" @house= "handler2" ></ Event1 >
        < hr >
        <!-- @click|dblclick|change在标签|自定义标签上都是原生DOM事件  .native废弃了-->
        < Event2 @click= "handler3" ></ Event2 >
      </ div >
    </ template >

    < script setup lang= "ts" >
    //引入
    import Event1 from "./Event1.vue";
    import Event2 from './Event2.vue';
    //同名函数
    const handler = ( a, b, c, e) => {
      console. log( e);
    };
    const handler1 = ( car) => {
      console. log( car);
    };
    const handler2 = ( house) =>{
      console. log( house);
    }

    const handler3 = ( parmas) =>{
      alert( parmas);
    }
    </ script >

    < style scoped >
    .event {
      width: 100vw;
      height: 600px;
      background: hotpink;
    }
    </ style >
  3. Event bus(mitt插件)

    由于vue3没有构造函数Vue、也没有this,导致全局事件总线很难完成,但可以使用替代方案mitt.js,原理还是 EventBus。需要安装mitt.js

    封装mitt.js

    
    import 
    mitt 
    from 
    'mitt'
    
    const mitt = mitt()
    export default mitt

    组件一:

    
    <
    template
    >
    
      < div class= "son" >
        < h1 @click= "handler" >我是大儿子:孙策 </ h1 >
      </ div >
    </ template >

    < script setup lang= "ts" >
    import $bus from '../../bus'

    function handler(){
      $bus. emit( 'getYX', '玉玺')
    }
    </ script >

    < style scoped >
    .son {
      width: 400px;
      height: 200px;
      background: skyblue;
    }
    </ style >

    组件二:

    
    <
    template
    >
    
      < div class= "son1" >
        < h1 >我是小霸王的弟弟:孙权 </ h1 >
      </ div >
    </ template >

    < script setup lang= "ts" >
    import { onMounted} from 'vue';
    import $bus from '../../bus'

    //组件挂载完毕
    onMounted(() =>{
      $bus. on( 'getYX',( params) =>{
        console. log( params);
     })
    })

    </ script >

    < style scoped >
    .son1 {
      width: 400px;
      height: 200px;
      background: yellowgreen;
    }
    </ style >
  4. v-model(多个数据双向绑定)

    三种组件,不同方式

    组件一:

    
    <
    template
    >
    
      < div class= "box" >
        < button @click= "updateMoney" >子组件按钮 {{ value }} </ button >
      </ div >
    </ template >

    < script setup lang= "ts" >
    const updateMoney = () => {
      //触发自定义事件
      $emit( "input", props. value + 100);
    };
    //vue3接受父组件传递过来的props
    let props = defineProps([ "value"]);
    let $emit = defineEmits([ "input"]);

    </ script >
    < style scoped >
    .box {
      width: 400px;
      height: 200px;
      background: skyblue;
    }
    </ style >

    组件二:

    
    <
    template
    >
    
      < div class= "box" >
        < button @click= "handler" >子组件按钮(1) {{modelValue}} </ button >
      </ div >
    </ template >

    < script setup lang= "ts" >
    const handler = () =>{
      $emit( 'update:modelValue', props. modelValue + 100)
    }
    //接受父组件传递过来的props
    let props = defineProps([ 'modelValue']);
    let $emit = defineEmits([ 'update:modelValue'])
    </ script >
    < style scoped >
    .box {
      width: 400px;
      height: 200px;
      background: yellowgreen;
    }
    </ style >

    组件三:

    
    <
    template
    >
    
      < div >
        < h1 >我是子组件:与父组件的多个数据同步 </ h1 >
        < button @click= "handler" >中国 {{ car }} </ button >
        < button @click= "handler1" >美国 {{ house }} </ button >
      </ div >
    </ template >

    < script setup lang= "ts" >
    //第一个按钮的回调
    const handler = () => {
      $emit( 'update:car', props. car + '@')
    }
    const handler1 = () => {
      $emit( 'update:house', props. house + '!')
    }

    //接受父组件传递过来的props
    let props = defineProps([ 'car', 'house']);

    let $emit = defineEmits([ 'update:car', "update:house"]);


    </ script >

    < style scoped ></ style >

    父组件:

    
    <
    template
    >
    
      < div >
        < h1 >v-model:在vue3中使用 {{ car }}--- {{ house }} </ h1 >
        <!-- 收集表单数据 -->
        <!-- <input type="text" placeholder="请你输入账号" v-model="userName"> -->
        < hr >
        <!-- 子组件 -->
        <!-- <Child :value="money" @input="handler"></Child> -->
        <!-- 测试v-model在vue3中使用 -->
        <!-- 在vue3当中v-model='xxx',相当给子组件传递props[modelValue] 自定义事件[update:modelValue] -->
        <!-- <Child1 v-model="money"></Child1> -->
        <!-- <Child2 v-model:car="car" v-model:house="house"></Child2> -->
      </ div >
    </ template >

    < script setup lang= "ts" >
    import Child from './Child.vue';
    import Child1 from './Child1.vue';
    import Child2 from './Child2.vue';
    //引入组合式API函数ref
    import { ref } from 'vue';
    //收集账号的响应式数据
    const userName = ref( '');
    //vue3:v-model也可以实现组件通信,父子组件数据同步!!!
    //父亲的钱数
    const money = ref( 10000);

    const car = ref( '法拉利');
    const house = ref( '大别墅');

    //子组件自定义事件的回调
    // const handler = (val)=>{
    //    money.value = val;
    // }
    </ script >

    < style scoped ></ style >

  5. Attrs(获取父组件传递过来的属性与属性值 + 事件)

    父组件:传送给子组件

    
    <
    template
    >
    
      < div >
        < h1 >$attrs与$listeners使用 </ h1 >
        < hr >
        < el-button type= "success" size= "default" @click= "handler" circle >添加 </ el-button >
        < hr >
        < Buttons type= "warning" size= "large"   tip= "添加商品" @click= "handler" ></ Buttons >
      </ div >
    </ template >

    < script setup lang= "ts" >
    import Buttons from './Buttons.vue';
    const handler = () =>{
        alert( 123);
    }
    </ script >

    < style scoped ></ style >

    子组件:接收父组件 传递过来的属性与属性值 + 事件

    
    <
    template
    >
    
      < div :title= "tip" >
        < el-button := "$attrs" > {{ tip }} </ el-button >
      </ div >
    </ template >

    < script setup lang= "ts" >
    import { useAttrs } from "vue";
    //获取父组件传递过来的属性与属性值 + 事件
    const $attrs = useAttrs();
    let props = defineProps([ 'tip']);
    </ script >

    < style scoped ></ style >

  6. Provide / Inject(祖先传后代)

    可以实现隔辈组件通信,provide:提供数据,inject:后代注入数据

    爷爷组件:

    
    <
    template
    >
    
      < div >
        < h1 >我是爷爷 {{ car }} </ h1 >
        < hr />
        < Child ></ Child >
      </ div >
    </ template >

    < script setup lang= "ts" >
    import Child from "./Child.vue";
    import { ref, provide } from "vue";
    const car = ref( "蔚来");
    //对外提供数据,给后代子组件使用
    provide( "car", car);
    </ script >

    < style scoped ></ style >

    儿子组件:

    
    <
    template
    >
    
      < div >
        < h1 >我是儿子 </ h1 >
        < hr >
        < GrandChild ></ GrandChild >
      </ div >
    </ template >

    < script setup lang= "ts" >
    import GrandChild from "./GrandChild.vue";
    </ script >

    < style scoped >
    </ style >

    孙子组件:

    <template>   <div>     <h1 @click="car+='!'">我是孙子{{car}}</h1>   </div> </template> <script setup> import { inject } from "vue"; const car = inject("car"); </script> <style scoped></style>

  7. Refs(父访子)

    父组件获取子组件的属性或者调用子组件方法

    父组件:

    <template>   <div>      <h1>我是父组件:曹操{{money}}</h1>      <button @click="handler">点击我找儿子借用200</button>      <hr>      <Son ref="son"/>      <hr>      <Dau/>   </div> </template> <script setup> import {ref} from 'vue'; import Son from './Son.vue'; import Dau from './Daughter.vue'; //父组件的钱数 const money = ref(100000000); //获取子组件实例 const son = ref(); //vue3:没有$children function handler(){   //自身钱数+200   money.value+=200;   son.value.money-=200; } defineExpose({money}) </script> <style scoped></style>

    子组件一:

    <template>   <div>     <h1>我是曹植:{{ money }}</h1>   </div> </template> <script setup> import { ref } from "vue"; //儿子曹植的钱 const money = ref(200000); defineExpose({money}) </script> <style scoped></style>

    子组件二:

    <template>   <div>     <h1>我是曹节:{{ money }}</h1>     <button @click="handler($parent)">点击我给爸爸2000</button>   </div> </template> <script setup> import { ref } from "vue"; //儿子曹植的钱 const money = ref(4000); //按钮回调 function handler($parent:any) {   money.value -= 200;   $parent.money+=200; } </script> <style scoped></style>
  8. Vuex

    main.js

    // main.js import { createApp } from "vue" import App from "./App.vue" import store from "./store" createApp(App).use(store).mount("#app")

    store/index.js:

    // store/index.js import { createStore } from "vuex" export default createStore({     state:{ count: 1 },     getters:{         getCount: state => state.count     },     mutations:{         add(state){             state.count++         }     } })

    使用方式一(直接使用):

    <template>     <div>{{ $store.state.count }}</div>     <button @click="$store.commit('add')">按钮</button> </template> <script setup></script> <style scoped></style>

    使用方式二(获取):

    <template></template> <script setup>     import { useStore, computed } from "vuex"     const store = useStore()     console.log(store.state.count) // 1       const count = computed(()=>store.state.count) // 数据是响应式的,跟随vuex的数据     console.log(count) // 1  </script>
  9. Slot(插槽)

    插槽允许父组件向子组件传递任意内容,包括 HTML、组件或函数

    父组件:

    
    <
    template
    >
    
      < div >
        < h1 >作用域插槽 </ h1 >
        < TodoList :arr= "todoList" >
          <!-- vue2:v-slot|slot-scope -->
          < template #= "{ $row, index }" >
            <!-- 父组件给子组件提供结构 -->
            < pre :style= "{ color: $row.done ? 'green' : 'red' }" > {{ $row.title }}--- {{ index }} </ pre >
          </ template >
        </ TodoList >
      </ div >
    </ template >

    < script setup lang= "ts" >
    //作用域插槽
    //概念:数据是由父组件提供,但是子组件不能决定自身的结构与外观!!!
    import { ref } from "vue";
    import TodoList from './Todo.vue';
    //todoList数据
    const todoList = ref([
     { id: 1, title: "吃饭", done: true },
     { id: 2, title: "睡觉", done: true },
     { id: 3, title: "打豆豆", done: false },
    ]);
    </ script >

    < style scoped ></ style >

    子组件:

    
    <
    template
    >
    
      < div >
        < ul >
          < li v-for= "(item, index) in arr" :key= "item.id" >
            < slot :$row= "item" :index= "index" ></ slot >
          </ li >
        </ ul >
      </ div >
    </ template >

    < script setup lang= "ts" >
    //接受父组件传递过来的props
    defineProps([ "arr"]);
    </ script >

    < style scoped ></ style >

来自 “ ITPUB博客 ” ,链接:https://blog.itpub.net/69917895/viewspace-2966088/ ,如需转载,请注明出处,否则将追究法律责任。

请登录后发表评论 登录
全部评论

注册时间:2023-03-30

  • 博文量
    7
  • 访问量
    2856