VUE2进阶至VUE3四 (组件通信)

1,992 阅读1分钟

一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第4天,点击查看活动详情

父组件向子组件传值

子组件接收值时使用defineProps进行接收

  • 字符串类型传值

    当传值类型为基本数据类型时不需要使用v-bind进行绑定。

  • 数组等复杂数据类型类型传值

    当传值类型为复杂数据类型时,这时时需要使用v-bind进行绑定的。 父组件

<template>
  <div>
    <Main title="jxx" :data="list"></Main>
  </div>
</template>
<script setup lang="ts">
    // vue3只需要引用,不需要注册
   import Main from './main.vue'
   const list = reactive<number[]>([1,2,3,4])
</script>

子组件

<template>
  <div>{{title}}</div>
  <div>{{data}}</div>
</template>
<script setup lang="ts">
type Tit = {
  title: string,
  data: number[]
}
defineProps<Tit> ()

</script>

子组件通过事件向父组件进行传值

子组件向父组件传值使用defineEmits方法,这个函数里面接收一个数组,数组里面是需要传到外面的事件名称,可以有多个事件名称。

子组件向父组件可以传递多个值,只要在子组件接收时定义好相应的接收参数即可。

父组件

<template>
  <div>
    <Main title="jxx" :data="list" @click-data="getData"></Main>
  </div>
</template>
<script setup lang="ts">
  import {  reactive } from 'vue'
  import Main from './main.vue'
  const list = reactive<number[]>([1,2,3,4])
  const getData = (e:number[]) => {
    console.log(e)
  }
</script>

子组件

<template>
  <button @click="handleClick"></button>
</template

<script setup lang="ts">
    import { reactive } from 'vue'
    const list = reactive<number[]>([2,3,4,5]);
    type Tit = {
      title: string,
      data: number[]
    }
    defineProps<Tit> ()
    // 子组件向父组件传递参数
    const emit = defineEmits(['click-data']);
    const handleClick = () => {
    // 此处数据可以传多个参数
      emit('click-data', list)
    }
</script>

获取子组件的实例

通过ref的value值去获取子组件的实例,但是子组件什么也不会暴露出来,所以我们这时候需要在子组件中使用一个参数defineExpose将数据进行派发暴露,这样父组件就可以拿到子组件中的数据,至于vue3为什么要这样做呢,当然也是为了更加安全,父组件也就不能直接修改子组件的值,在vue2中父组件是可以直接修改子组件的值的。

父组件

<template>
  <div>
    <Main ref="jxx" title="jxx" :data="list" @click-data="getData"></Main>
  </div>
</template>
<script setup lang="ts">
  import {  reactive, ref } from 'vue'
  import Main from './main.vue'
  const list = reactive<number[]>([1,2,3,4]);
  // 此处定义的值需要与标签中的ref的值保持一致
  const jxx = ref(null);
  const getData = (e:number[]) => {
    console.log(jxx.value);
  }
</script>

子组件

<template>
  <div>{{title}}</div>
  <div>{{data}}</div>
  <button @click="handleClick"></button>
</template 
<script setup lang="ts">
    import { reactive } from 'vue'
    const list = reactive<number[]>([2,3,4,5]);
    type Tit = {
      title: string,
      data: number[]
    }
    defineProps<Tit> ()
    const emit = defineEmits(['click-data']);
    const handleClick = () => {
      emit('click-data', list)
    }
    // 父组件需要获取的数据
    defineExpose({
      list
    })
</script>

子组件默认值

子组件中通过withDefaults来定义默认值,此参数只支持ts

父组件

<template>
  <div>
    <Main></Main>
  </div>
</template>
<script setup lang="ts">
  import Main from './main.vue'  
</script>

子组件

<template>
  <div>{{title}}</div>
  <div>{{data}}</div>
</template>
<script setup lang="ts">
type Tit = {
  title?: string,
  data?: number[]
}
withDefaults(defineProps<Tit> (), {
  title: '默认值',
  // data是一个复杂数据类型,需要通过一个函数来定义默认值
  data:() => [1,2,3]
})
</script>

定义全局组件

如果需要定义全局组件,需要在main.ts中引用并注册该组件。

import Modal from './components/Modal/modal.vue'
creatApp(App).component('Modal', Modal).mount('#app');

简单的递归组件

使用场景:不确定的层级的树形结构。其主要原理就是子组件中调用自身组件

父组件

<template>
  <div>
    <Tree :data="data"></Tree>
  </div>
</template>
<script setup lang="ts">
  import {  reactive, ref } from 'vue'
  import Tree from './main.vue'
  type TreeList = {
  name: string;
  icon?: string;
  children?: TreeList[] | [];
};
const data = reactive<TreeList[]>([
  {
    name: "no.1",
    children: [
      {
        name: "no.1-1",
        children: [
          {
            name: "no.1-1-1",
          },
        ],
      },
    ],
  },
  {
    name: "no.2",
    children: [
      {
        name: "no.2-1",
      },
    ],
  },
  {
    name: "no.3",
  },
]);
</script>

子组件

<template>
   <div style="margin-left:10px;" class="tree">
      <div :key="index" v-for="(item,index) in data">
        <div>{{item.name}}
        </div>
        // 这里调用的组件就是此子组件本身
        <TreeItem v-if='item?.children?.length' :data="item.children"></TreeItem>
      </div>
    </div>
</template>
<script setup lang="ts">
    type TreeList = {
      name: string;
      icon?: string;
      children?: TreeList[] | [];
    };

    type Props<T> = {
      data?: T[] | [];
    };

    defineProps<Props<TreeList>>();
</script>
// 因为是子组件本身调用自己,所以需要给改文件定义一个名字
<script lang="ts">
    export default {
      name: "TreeItem"
    }
</script>