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

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>


    父组件:{{ fish }}


    <button @click="ChangeFish()">改变鱼与价格</button>
    <Fish :name="fish" :price="price"/>

    </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数据是单向的,其内容包含以下:

  • 基础数据,如字符串、数字
  • 数组
  • 对象
  • 函数
相关推荐
孟陬2 小时前
为什么国外技术大神都爱自己搭博客,而国内程序员却挤在微信公众号或掘金?
java·typescript·前端框架
树上有只程序猿2 小时前
这波低代码热,能维持多久
前端
姓王名礼2 小时前
这是一个完整的全栈交付包,包含Vue3 前端交互界面(集成数字人视频流、ECharts 图表、语音对话)和Docker Compose 一键部署脚本。
前端·docker·echarts
嵌入式-老费2 小时前
vivado hls的应用(axis接口)
前端·webpack·node.js
孟陬2 小时前
国外技术周刊第 2 期 — 本周热门 🔥 YouTube 视频 TED 演讲 AI 如何能够拯救(而非摧毁)教育
前端·后端·程序员
小飞大王6662 小时前
从零手写 React:深度解析 Fiber 架构与 Hooks 实现
前端·react.js·架构
不甜情歌2 小时前
JS 异步:Event-Loop+async/await
前端
程序员库里2 小时前
AI协同写作应用-TipTap基础功能
前端·javascript·面试
程序员阿峰2 小时前
【JavaScript面试题-算法与数据结构】手写一个 LRU(最近最少使用)缓存类,支持 `get` 和 `put` 操作,要求时间复杂度 O(1)
前端·javascript·面试