vue3之组件通信 (props父传子,子传孙)(ts定义数组类型)

vue3之组件通信

  • vue3之中的组件,再引入的时候,可直接使用,不用类似vue2时,还得再components 组成当前组件,才能使用

1 props父传子,子传孙

1-1 父组件

<NavList :navList="item.data"></NavList>

let navList = reactive([
  {
    tab: "天天神卷",
    data: [
      {
        pic: "https://img0.baidu.com/it/u=2735725699,3536201611&fm=253&fmt=auto&app=138&f=JPEG?w=499&h=330",
        title: "酸菜鱼1",
        sales: "2888",
        price: 10,
        label: ['门店上新','很下饭'],
      },
      {
        pic: "https://img0.baidu.com/it/u=3117431038,1238343094&fm=253&fmt=auto&app=138&f=JPEG?w=500&h=333",
        title: "猪脚饭1",
        sales: "3000",
        price: 10,
        label: ['门店上新','很下饭'],
      },
    ],
  },
  {
    tab: "减配送费",
    data: [
      {
        pic: "https://",
        title: "酸菜鱼2",
        sales: "2888",
        price: 20,
        label: ['门店上新','很下饭'],
      },
    ],
  }
]);

1-2 子组件

<template>
  <div class="nav-list">
    <div v-for="(item, idx) in navList" :key="idx">
      <NavListItem :navListItem="item"></NavListItem>
    </div>
  </div>
</template>

<script setup lang="ts" name="NavList">
import { toRefs, defineProps } from "vue";
import NavListItem from "./NavListItem.vue";
const props = defineProps<{
  navList: {
    pic: string;
    title: string;
    sales: string;
    price: number;
    label: string[]; // ['门店上新,"很下饭"']
  };
}>();
const { navList } = toRefs(props);
</script>

1-3 孙组件

<template>
  <div class="nav-list-item">
    <img :src="navListItem.pic" class="item-img" />
    <div class="item-right">
      <div class="title">
        {{ navListItem.title }}
      </div>
      <div class="sales">
        {{ navListItem.sales }}
      </div>
      <div class="price">
        {{ navListItem.price }}
      </div>
      <div class="label">
        <span v-for="(item, idx) in navListItem.label" :key="idx">
          {{  item  }}
        </span>
      </div>
    </div>
  </div>
</template>

<script setup lang="ts" name="NavListItem">
import { toRefs, defineProps } from "vue";

type NavListItem = {
  pic: string;
  title: string;
  sales: string;
  price: number;
  label: string[]; // ['门店上新,"很下饭"']
};
const props = defineProps<{
  navListItem: NavListItem;
}>();
const { navListItem } = toRefs(props);
</script>

2:父子传值

2:-1 父组件向子组件传值 Props

  • 不添加默认值时

    • defineProps<Props>()
  • 添加默认值

    withDefaults(defineProps<Props>(), {
      title: '默认值',
    })
    
  • layout.vue 父组件

    • 向子组件传递一个字符串的 title 和 一个number类型的数组
<template>
  <div class="layout">
    <div><Menu title="我是title" :list="list"></Menu></div>
  </div>
</template>

<script setup lang="ts">
import { reactive } from 'vue'
import Menu from './menu/Menu.vue'

const list = reactive<number[]>([1, 2, 3])
</script>
  • menu.vue 子组件
    • 使用defineProps() 去接受子组件的数据
    • 使用 type Props 来限制 子组件传递的数据的类型
<template>
  <div class="menu">
    menu
    {{ title }}
    <div>
      <div v-for="item in list" :key="item">{{ item }}</div>
    </div>
  </div>
</template>

<script setup lang="ts">
type Props = {
  title: String
  list: number[]
}

defineProps<Props>()
</script>
<style lang="scss" scoped>
.menu {
  width: 200px;
  height: 100%;
  border: 1px solid #ccc;
}
</style>

2-2 子组件向父组件传值 emit

  • 使用 defineEmits 来定义 需要发射的事件

    • 然后 通过 emit 来发射事件以及 携带参数,传递到父组件
  • 子组件

    • 向父组件 发射一个 change-menu事件,携带sonList, false两个参数
<template>
  <div class="menu">
    {{ title }}
    <div>
      <div v-for="item in list" :key="item">{{ item }}</div>
    </div>
    <button @click="sonClick">子组件传递数据</button>
  </div>
</template>

<script setup lang="ts">
import { reactive } from 'vue'

type Props = {
  title: String
  list: number[]
}
defineProps<Props>()
const sonList = reactive<number[]>([22, 33, 44])
// 若是有多个 emit事件 则写法 defineEmits(['change-menu','XXX'])
const emit = defineEmits(['change-menu'])
const sonClick = () => {
  emit('change-menu', sonList, false)
}
</script>
  • 父组件
<template>
  <div class="layout">
    <div><Menu @change-menu="fatherClick" title="我是title" :list="list"></Menu></div>
  </div>
</template>

<script setup lang="ts">
import { reactive } from 'vue'
import Menu from './menu/Menu.vue'

const list = reactive<number[]>([1, 2, 3])
// 父组件 接受子组件的事件
const fatherClick = (list: number[], flag) => {
  console.log('list', list, flag)
}
</script>

3:使用ref 拿到子组件的 数据

  • 父组件
<template>
  <div class="layout">
    <div><Menu ref="menuRef" @change-menu="fatherClick" title="我是title" :list="list"></Menu></div>
    <div class="layout-right">
      <Header></Header>
      <Main></Main>
    </div>
  </div>
</template>

<script setup lang="ts">
import { reactive, ref } from 'vue'
import Header from './header/Header.vue'
import Main from './main/Main.vue'
import Menu from './menu/Menu.vue'

const menuRef = ref(null)

const list = reactive<number[]>([1, 2, 3])
const fatherClick = (list: number[], flag) => {
  // console.log('list', list, flag)
  console.log('menuRef', menuRef.value, menuRef.value.sonList)
}
</script>
  • 子组件
<template>
  <div class="menu">
    menu

    {{ title }}
    <div>
      <div v-for="item in list" :key="item">{{ item }}</div>
    </div>
    <button @click="sonClick">子组件传递数据</button>
  </div>
</template>

<script setup lang="ts">
import { reactive } from 'vue'

type Props = {
  title: String
  list: number[]
}
defineProps<Props>()
const sonList = reactive<number[]>([22, 33, 44])
// 若是有多个 emit事件 则写法 defineEmits(['change-menu','XXX'])
const emit = defineEmits(['change-menu'])
const sonClick = () => {
  emit('change-menu', sonList, false)
}
// ref 派发数据
defineExpose({
  sonList,
})
</script>

4:父传子 props传递 function

4-1父组件

 <CartDeatia v-if="isShow" :changeShow="changeShow"></CartDeatia>
 const changeShow = () => {
  isShow.value = false;
};

4-2子组件

const props = defineProps<{
  changeShow: {
    // type: () => void;
    type:Function
    required: true;
  };
}>();

 props?.changeShow()
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值