解锁前端Vue3宝藏级资料 第五章 Vue 组件应用 1( Props )

  本章带领大家理解组件、props、emits、slots、providers/injects,Vue 插件 等Vue组件使用的基础知识。

  • 5.1 组件注册
  • 5.2 Props
    • 5.2.1 组件之间如何传值
    • 5.2.2 参数绑定 v-bind
    • 5.2.3 参数类型
    • 5.2.4 props 默认与必填
    • 5.2.5 验证设置
    • 5.2.6 useAttrs 属性设置

第一章 Vue3项目创建 1 Vue CLI 创建vue项目
第一章 Vue3项目创建 2 使用 Webpack 5 搭建 vue项目
第一章 Vue3项目创建 3 Vite 创建 vue项目
第二章 Vue3 基础语法指令
第三章 Vue Router路由器的使用
第四章 VUE常用 UI 库 1 ( element-plus,Ant ,naiveui,ArcoDesign)
第四章 VUE常用 UI 库 2 ( ailwind 后台框架)
第五章 Vue 组件应用 1( Props )
第五章 Vue 组件应用 2 ( Emit )
第五章 Vue 组件应用 3( Slots )
第五章 Vue 组件应用 4 ( provide 和 inject )
第五章 Vue 组件应用 5 (Vue 插件)

5.1 组件注册

  Vue 3中有一个非常重要的概念是组件注册,一个 Vue 文件可以被引用到别外一个Vue 文件中,在引用的Vue文件模板中可以使用到被引用到Vue 文件。Vue 文件会被“注册”别外的Vue文件中成为它的子组件,这些子组件会被 父 Vue文件中的模板渲染时找到其对应的实现。组件注册有两种方式:全局注册和局部注册。

1 全局注册

使用 vue 根实例进行注册的组件为全局注册。使用的方法app.component() ,简单的理解就是注册给createApp()的组件都是全局组件,它可以在 Vue 应用中全局可用。

import { createApp } from 'vue'
import App from './App.vue'
import index from './components/index.vue';//导入组件index.vue
const app = createApp(App)
app.component('index',index);//注册全局组件
app.mount('#app')

components目录中创建一个index.vue文件。



App.vue中模板中可以使用这个全局组件功能。



2 局部组件

全局注册虽然很方便,但有使用起来会有几个问题:

  1. 全局注册在打包的时候都会被打在一个包中(这种情况叫“tree-shaking”),如果你注册了很多的全局组,即使它并没有被实际使用到,但是仍然会被打包在一个 JS 文件中,浏览器使用的时候一次全部加载进入缓存中来。
  2. 全局注册在大型项目中使项目的依赖关系变得复杂。在父组件中使用子组件时,不太容易定位到子组件的实现。和程序中使用过多的全局变量一样,这会影响整个项目代码的可维护性。

相比之下,局部注册的组件是在使用它的父组件中显式导入,并且只能在该父组件中使用。它的优点是使组件之间的依赖关系更加明确,并且对 tree-shaking 更加友好。

App.vue中模板可以直接导入index.vue,将index.vue注册为它的子组件。



5.2 Props

  Props作用是将字符串、数字、数组和对象等值从父组件传递给子组件。当你想到在 JavaScript 中传递参数的时候,首先想到的可能是使用函数传递参数,就像函数中使用arguments一样处理参数。在vue中Props也可以像arguments一样在组件间传值,两个父子组件通过 Props 传递参数。在 Props 传递参数的时候可以在组件内部设定一个初始化函数,对 Props中的参数进行一个初始化的预定处理。

  Vue.js 有一种机制,通过设置要传递的值的数据类型和默认值,使用 Props 将正确的数据传递给组件,以免导致错误。必须将正确的数据传递给组件,才能使组件正常工作。在路由的使用中就介绍过路由之间用Props如何传递参数,现在要介绍的组件之间如何使用Props。

解锁前端Vue3宝藏级资料 第五章 Vue 组件应用 1( Props )_第1张图片

5.2.1 组件之间如何传值

  让我们创建一个简单的例子,看看如何使用 props传递参数。首先在index.vue文件中进行修改,使用defineProps函数获得props中的参数用于接收和显示名称,defineProps函数中的参数类型为数组。

index.vue

在components目录中创建一个index.vue文件。

<script setup>
defineProps(['name']);
script>
<template>
  <h1>{{ name }}h1>
template>
<style>style>

App.vue

在index组件中使用name属性设置一个字符串参数,将这个字符串传递给index.vue文件中的defineProps([‘name’]);函数,在模板将这个参数字符串显示出来。

<script setup>
import index from './components/index.vue';
script>
<template>
<index name="我是一个Props 参数" />
template>

在这里插入图片描述
组件可以重复使用传递不同的参数字符串。

<script setup>
import index from './components/index.vue';
script>
<template>
<index name="我是一个Props 参数" />
<index name="我是二" />
<index name="我是三" />
template>

5.2.2 参数绑定 v-bind

  很多情况下我们需要在script标签中定义参数,而这些script标签中的参数需要进行值传递。这种情况下会使用到v-bind 指令进行参数名称绑定。如果不使用v-bind 设置绑定,name属性中设置的字符串(“productName”)将原样传递这个字符串(“productName”)给子组件,而不是script中的productName对象。

App.vue

<script setup>
import index from './components/index.vue';
const productName="const传值";//传递的参数
script>
<template>
//通过v-bind 指令绑定productName参数与name关系
<index v-bind:name="productName" />
<index name="我是一个Props 参数" />
<index name="我是二" />
<index name="我是三" />
template>

ref 函数绑定

如果在 props 中传递的数据需要用户交互而发生变化,可以使用 ref 函数定义一个反应变量,并使用 v-bind 设置该变量。

<script setup>
import index from './components/index.vue';
import { ref } from 'vue';
const productName = ref('const 参数');
script>
<template>
<index v-bind:name="productName" />
<index name="我是一个Props 参数" />
<index name="我是二" />
<index name="我是三" />
template>

描述指令 v-bind:name,也可以使用缩写形式(语法糖):name来绑定。

5.2.3 参数类型

  上面的示例中对Props 参数使用的非常简单就是以字符串为参数进行值传递。Props也可以将字符串以外的任何内容作为要传递的值进行参数传递。但是,随着代码变得越来越复杂,很多时候我们可能会传递一个数字而不是字符串,或者传递一个Json对象。Props 中传入的这些不同类型的数据都会被defineProps函数接收与处理。

  在vue.js中为了定义不同类型的参数,可以通过defineProps函数中的type属性来设置props中输入了什么类型的值。例如下面中 index 组件的 props 名称中包含字符串,因此首先将类型设置为 String。String的首字母大写,小写会报错。这声明该name属性将包含一个 String(字符串)。id属性类型被定义为数字类型,type设置为 Number,这样代表id获得值为数字类型。

index.vue

  在index.vue组件中,获得来在父组件传递过来的参数,使用defineProps函数获得并且设置出这三个参数的数据类型。之前,我们只是用 props 设置数组并设置获得name属性。当我们需要设置不同属性的类型时候,可以参照下面的写法进行设置。

<script setup>
 //defineProps 接收父组件Props中的参数
 //设置name     字符串类型 type: String
 //设置id       数字类型   type: Number     
 //设置dept     对象类型   type: Object
const props =defineProps({
  name: {
    type: String,
  },
  id: {
    type: Number,
  },
  dept: {
    type: Object,
  },
});
script>
<template>
  <h1>id:{{ id }}h1>
  <h1>名称:{{ name }}h1>
  <h1>部门:{{ dept.name }} 部门id:{{ dept.id }}h1>
template>
<style>style>

App.vue

  App.vue中的index组件绑定三个参数name,id,dept到props中。注意这里的dept属性实际上是一个对象类型。

<script setup>
import index from './components/index.vue';
import { ref } from 'vue';
const productName = ref('const 参数');
const dpet = ref({name:"部门一",id:"10"});
</script>
<template>
<index v-bind:name="productName" id="我不是数字" :dept="dpet"/>
<index name="我是一个Props 参数" />
</template>

在这里插入图片描述

参数类型一览

  • String

  • Number

  • Boolean

  • Array

  • Object

  • Date

  • Function

  • Symbol

类型不对发出警告

  让我们来看看如果props中定义的属性类型与传入的参数类型不对会发生什么?测试一下我们定义一个数子类型的参数,给它值传入一个字符类型,看看会有什么变化。

--------------------- index.vue ---------------------
<script setup>
 //defineProps 接收父组件Props中的参数
 //设置name     字符串类型 type: String
 //设置id       数字类型   type: Number     
 //设置dept     对象类型   type: Object
const props =defineProps({
  name: {
    type: String,
  },
  id: {
    type: Number,
  },
});
script>
<template>
  <h1>id:{{ id }}h1>
  <h1>名称:{{ name }}h1>
template>
<style>style>
--------------------- App.vue ---------------------
<script setup>
import index from './components/index.vue';
import { ref } from 'vue';
const productName = ref('const 参数');
script>
<template>
<index v-bind:name="productName" id=“我不是数字”/>
<index name="我是一个Props 参数" />
template>

在浏览器中会看到这个参数正常显示出来了,但是在控制台中会出现警告,我们会看到下面的警告内容。

在这里插入图片描述

控制台警告显示

  类型不对的时候会在控制台会出现一条警告,执行了类型检查并传递了一个数字而不是字符串。我们可以通过这条警告,来检查自己的代码中是否存在参数类型与参数不一致的情况。

5.2.4 props 默认与必填

在props对象的属性中可以设置这默认值,必添项。

1 默认值 default

  如果在子组件中调用的时候没有给props属性中的值传递任何参数的时候,这个时候props就会在配置中找到这个属性的默认值进行赋值。例如下面,默认值设置为“默认名字”。

defineProps({
  name: {
    type: String,
    default: '默认名字',
  },
});

index.vue组件中中如果设置了name属性的默认值,App.vue中如果没有为index组件设置name属性,将使用默认值。


------------没有设置属性值,子组件中将显示默认值

组件部分将显示name属性的默认值“默认名字”。

在这里插入图片描述

如果我们在组件props的参数中没也有设置默认值会反生什么?

defineProps({
  name: {
    type: String,
  },
});

如果未设置默认值,控制台不会显示警告等消息。浏览器上没有显示任何内容,因为没有值通过 props 传递index 组件不会收到name参数的值。
解锁前端Vue3宝藏级资料 第五章 Vue 组件应用 1( Props )_第2张图片
2 设置必填项 Required

  required 属性来设置是否需是必填项。继续前面的内容,下面的例子让我们设置props属性内容为 required 而不设置 default 并且不在 component 标签中设置 props内容。required 的值可以是 true 或 false,我们将 prop 的中name属性设置为 required :true。

defineProps({
  name: {
    type: String,
    required: true,---必填项
  },
});

在浏览器控制台,将看到一条警告,指出即使这次需要该名称,也未提供该名称。警告说缺少道具“名称”
解锁前端Vue3宝藏级资料 第五章 Vue 组件应用 1( Props )_第3张图片
将 required 设置为 true 会导致显示警告, required 的默认情况为 false。

3 设置默认和必填项

  在项目开发中设置了default默认值,在组件中如果没有给props属性值,将会使用到默认值,所以不需要设置reuqired这个属性。换句话说,不需要像下面这样写 default 和 required 。

defineProps({
  name: {
    type: String,
    default: '默认名字',
    required: true,
  },
});

虽然此处设置了String的初始值,但设置数组或对象时可能会出现以下信息。

[Vue warn]: Invalid default value for prop "[props name]": Props with type Object/Array   must use a factory function to return the default value.

在这种情况下,您应该使用一个函数

defineProps({
  name: {
    type: String,
      default: () => [],
      default:[] //设置默认数组与对象
  },
});

5.2.5 验证设置

  现在我们轻松的理解了props中的类型、默认和必需的设置。但是我们还有一个重要的 Validation 功能没有介绍,下面让我们一起来深理解Validation使用。Validation主要的功能是验证和检查输入的值是否正确。在下面的例子中,来验证index组件name属性的值是否包含"默认名字", “zht”, "zhtbs"这几个字符串。如果不包含这些字符串,控制台发出警告。

index.vue

<script setup>
const props =defineProps({
  name: {
    type: String,
    default: '默认名字',
    //验证函数
    validator: (value) => {
        return ["默认名字", "zht", "zhtbs"].indexOf(value) !== -1;
      },
  }
});
script>
<template>
  <h1>名称:{{ name }}h1>
template>
<style>style>

App.vue

<script setup>
import index from './components/index.vue';
script>
<template>
<index name="我是一个参数" />
<index name="zhtbs" />
<index />
template>

  由于验证器中指定的数组元素中不包含"我是一个参数",因此控制台日志中的消息将显示自定义验证器失败的警告。

解锁前端Vue3宝藏级资料 第五章 Vue 组件应用 1( Props )_第4张图片

  validator 我们来详细解释一下验证函数返回值,validator可以通过返回true或者false来判断成功或者失败,所以return true就一定会成功,当返回值被设置为 false 时,就会在控制台日志中收到警告。

<script setup>
const props =defineProps({
  name: {
    type: String,
    default: '默认名字',
    validator: (value) => {
        return false;//不管值是什么都会收到验证警告
      },
  }
});

  例如 对Props中接收到的值的字符串长度进行校验,可以这样写设置校验。如果字符数大于 6,此验证将为 true,因此如果您输入 3 个字符的包,它将为 false 并显示警告。

defineProps({
  name: {
    type: String,
    default: '默认名字',
    validator: (value) => {
	//验证name是否大于6个字符
      return value.length > 6;
    },
  },
});

  Slots也可以用在父组件与子组件的传值方面。Props 允许传递字符串、数字、数组和对象等参数,而 Slots 允许您传递 HTML 标签。为了更好的加深了对 Props 的理解,请在 Props 之后学习了解Slots 的使用。

5.2.6 useAttrs 属性设置

  在script setup中useAttrs 函数返回了 a t t r s 对象的引用。 attrs对象的引用。 attrs对象的引用。attrs对象保存了父组件模板中引用的子组件设置的class和style样式值,在把它们传回给子组件使用的一个通信工具类。在vue程序中会自动将组件中引用的子组件设置的class和style属性的值装入到 a t t r s 对象。 attrs对象。 attrs对象。attrs也会像props一样装入其他的参数属性,在子组件中这些被装入的其他参数也会被$attrs对象引用到。
解锁前端Vue3宝藏级资料 第五章 Vue 组件应用 1( Props )_第5张图片

App.vue

在使用到的子组件中,设置class属性和,id 和 style 参数值,它将会传递给子组件。

<script setup>
import index from './components/index.vue';
script>
<template>
 <index id="main" style="color:red" class="active" />
template>

index.vue

在子组件中通过useAttrs()获得attrs对象,将attrs对象中的class样式绑定到p标签中的class。

<script setup>
import { useAttrs } from 'vue';
const attrs = useAttrs();
console.log(attrs);
script>
<template>
<p :class="attrs.class">class属性确认中p>
template>
<style>style>

浏览其中会看到字体变红,和attrs对象中的内容。

解锁前端Vue3宝藏级资料 第五章 Vue 组件应用 1( Props )_第6张图片

  但是我们会发现一个问题,就是attrs中的其他参数没有被绑定到模板元素上,这个时候它们都都会变成p标签中属性。

解锁前端Vue3宝藏级资料 第五章 Vue 组件应用 1( Props )_第7张图片

  我们来看修改一下index.vue中的代码,增加几个html标签在这些标签中使用useAttr对象中的属性。

<script setup>
import { useAttrs } from 'vue';
const attrs = useAttrs();
console.log(attrs);
script>
<template>
  <p :class="attrs.class">class属性确认中p>
  <h2 class="info">子页面h2>
  <p :style="attrs.style">style属性确认中p>
template>
<style>style>

浏览器中显示结果。
解锁前端Vue3宝藏级资料 第五章 Vue 组件应用 1( Props )_第8张图片

我们会看到在多个html标签中useAttr对象中的值没有变成为这些html标签中的属性。

  • 当模板中只有一个html标签绑定attrs对象时候,attrs中所有的值都会成为这个html元素中的属性。
  • 当模板中多个htm标签绑定attrs对象,attrs对象中的值不会成为它们元素属性

你可能感兴趣的:(vue,前端,vue.js,javascript)