最新版vue3+TypeScript开发入门到实战教程之Vue3详解props

0 阅读4分钟

1、概述

上节讲解vue3中ts泛型的应用,这节内容依然会设计到泛型编程内容。props是Properties这个单词的缩写,可翻译为属性。它是父组件向子组件传递数据的桥梁,是子组件的属性。数据可包含以下内容:

  • 基础数据,如字符串、数字
  • 数组
  • 对象
  • 函数

2、如何区别标签属性常见的书写方式

如下设置标签属性,浏览器是如何执行的?

    <h1 a="1+1" :b="1+1" c="x" :d="fish">测试</h1>
  • 没有冒号,按照普通字符串处理
  • 含有冒号,按照j表达式处理,执行js代码

2.1查看浏览器如何显示结果

<template>
  <div class="app">
    <h1 a="1+1" :b="1+1" c="x" :d="fish">测试</h1>
  </div>
</template>
<script setup lang="ts">
import { ref } from 'vue'
let fish = ref('鲫鱼');
</script>

查看调试信息,h1标签处理如下图: 在这里插入图片描述

3、通过props传递基本属性数据

  • App为父组件,创建数据fish、price
  • 引用子组件Fish,设置Fish props属性
  • Fish接收props属性,模版中直接使用
父组件App
<template>
  <div class="app">
    <h2>父组件:{{ fish }}</h2>
    <button @click="ChangeFish()">改变鱼与价格</button>
    <Fish :name="fish" :price="price"/>
  </div>
</template>
<script setup lang="ts">
import { ref } from 'vue'
import Fish from './components/Fish.vue';
let fish = ref('鲫鱼');
let price = ref(10);
function ChangeFish() {
  fish.value += '~';
  price.value += 1;
}
</script>

子组件Fish

<template>
  <h2>我是子组件</h2>
  <h3>{{ name }}</h3>
  <h3>{{ price }}</h3>
</template>
<script setup lang="ts">
let propsData=defineProps(['name', 'price']);
console.log(propsData);
</script>

运行如下图: 在这里插入图片描述 注意,在模版中,可直接使用name、price渲染数据,也可使用propsData数据渲染

<template>
  <h2>我是子组件</h2>
  <h3>{{ propsData.name }}</h3>
  <h3>{{ propsData.price }}</h3>
</template>

3.1子组件不能改变父组件传统props数据

子组件接收props,是只读的,它无法被更改。所有props数据是单向的。尝试在Fish组件中更改props数据,会发生什么? 在这里插入图片描述 首先,代码提示飘红。执行代码,查看效果如下: 在这里插入图片描述 当点击按钮时,提示name、price" failed: target is readonly。name与price是只读。

4、props传递数组、对象数据

传递数组与对象数据,与基本类型数据相同。 父组件App代码

<template>
  <div class="app">
    <h2>父组件:{{ fish.name }}</h2>
    <h2>父组件:{{ fish.price }}</h2>
    <button @click="ChangeFishAndCat()">改变鱼与价格</button>
    <Fish :fish="fish" :list="cat"/>
  </div>
</template>
<script setup >
import { reactive } from 'vue'
import Fish from './components/Fish.vue';
let fish = reactive({
  name: '鲫鱼',
  price: 100
});
let cat = reactive([
  {
    id:'01',
    name: '波斯猫',
    price:10
  },
  {
    id:'02',
    name: '狸花猫',
    price:20
  },
  {
    id:'03',
    name: '布偶猫',
    price:30
  },
])
function ChangeFishAndCat() {
  fish.name += '~';
  fish.price += 1;
  cat[0].price += 1;
}
</script>

子组件代码

<template>
  <div>
    <h2>我是子组件</h2>
    <h3>{{ fish.name }}</h3>
    <h3>{{ fish.price }}</h3>
    <ul>
      <li v-for="item in list" :key="item.id">猫:{{ item.name }}--价格:{{ item.price }}</li>
    </ul>
  </div>
</template>
<script setup lang="ts">
defineProps(['fish','list']);
</script>

查看运行效果如下图: 在这里插入图片描述 代码可看出,父组件App给子组件传递两个数据fish与cat,。子组件默认接受defineProps(['fish','list'])。注意list与cat对应关系。 这样的传递方式,子组件若接收不到数据或者数据类型不正确,如何处理?

4.1props接收限制类型

props含有四种限制类型

  • 不限制,父组件传递任意数据
  • 限制指定类型数据且必须传递数据
  • 限制指定类型数据且可传可不传递数据
  • 当接收数据为空,设置默认类型数据

4.1.1不限制父组件任意传递类型输入

如上文内容父组件传递:,子组件接收defineProps(['fish','list'])。

4.1.2限制指定类型数据且必须传递数据

子组件限制接收类型,需要用到ts泛型。以接收数组数据为例,说明泛型如何使用。

  • 创建数组泛型FishList,Fish组件引入泛型
  • defineProps接受数据时,设置泛型 查看泛型数据的定义:
export interface FishInter{
  id: string,
  name: string,
  price: number,
  num:number
}
export type FishList=Array<FishInter>

定义泛型鱼的基本结构FishInter。定义鱼数组FishList,数组内容结构是FishInter。 在Fish组件中引用FishList

<template>
  <div>
    <h2>我是子组件</h2>
    <ul>
      <li v-for="item in list" :key="item.id">猫:{{ item.name }}--价格:{{ item.price }}</li>
    </ul>
  </div>
</template>
<script setup lang="ts">
import {type FishList} from '@/types'
defineProps<{ list: FishList }>();
</script>

若此时父组件App传递list数据或者数据类型不对,就会出错。具体代码查看图片 在这里插入图片描述

4.1.3限制指定类型数据且可传可不传递数据

子组件接收数据时,defineProps设置list是否为空,代码如下:

<template>
  <div>
    <h2>我是子组件</h2>
    <ul>
      <li v-for="item in list" :key="item.id">猫:{{ item.name }}--价格:{{ item.price }}</li>
    </ul>
  </div>
</template>
<script setup lang="ts">
import {type FishList} from '@/types'
defineProps<{ list?: FishList }>();
</script>

关键代码:defineProps<{ list?: FishList }>(); ###4.1.4当接收数据为空,设置默认类型数据 当父组件数据为空,defineProps接收到的数据为空。用withDefaults函数,设置默认值。

<template>
  <div>
    <h2>我是子组件</h2>
    <ul>
      <li v-for="item in list" :key="item.id">猫:{{ item.name }}--价格:{{ item.price }}</li>
    </ul>
  </div>
</template>
<script setup lang="ts">
import {type FishList} from '@/types'
// defineProps<{ list?: FishList }>();
withDefaults(defineProps<{ list?: FishList }>(), {
  list:()=> [
     {
    id:'01',
    name: '默认值',
    price: 10
  }
  ]

})
</script>

注意list接收到是一个箭头函数的返回值,否则报错。

props传递函数

父组件传递函数给子组件,由于props传递数据是单向的,但有时存在子组件需要更改props数据。可通过传递函数让父组件更改。传递函数,它也是子组件给父组件发送消息的方式之一。 子组件Fish

<template>
  <div>
    <h2>我是子组件</h2>
    <button @click="changeFish('~')">改变鱼</button>
  </div>
</template>
<script setup lang="ts">
defineProps(['changeFish']);
</script>

父组件App

<template>
  <div class="app">
    <h2>{{ fish }}</h2>
    <Fish :changeFish="changeFish" />
  </div>
</template>
<script setup lang="ts">
import { ref } from 'vue'
import Fish from './components/Fish.vue';
let fish = ref('鲫鱼');
function changeFish(val:any) {
  fish.value+=val
}
</scrip

运行效果如下: 在这里插入图片描述

5、总结

props数据是单向的,其内容包含以下:

  • 基础数据,如字符串、数字
  • 数组
  • 对象
  • 函数