没时间学 Vue (12) —— 组件(二):组件的创建、使用和数据传递

本文深入讲解Vue中组件的创建、使用及数据传递方法,包括如何定义props接收外部数据,以及如何在父组件中动态更新子组件的状态。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

前一篇我们简介了组件,并且以 “页面级” 的组件为中心演示了 “单文件组件” 的写法,算是开了个头。

本篇我们继续说组件,尤其是被其他组件使用的组件要怎么创建、使用,以及组件和使用者之间怎么传递数据。

我们仍然基于项目中实际会用到的 “单文件组件” 、而不是 Vue.component() 这种方式来创建组件,虽然本质上单文件组件会被转换成 Vue.component() 。

如果有兴趣了解以下 “真正的” 组件定义方式的话,可以抽时间看一下:

 

 

1、创建一个简单的组件


实际项目中,我们很少会自己造轮子,开发诸如 “日期选择组件”、“开关组件” 这些非常基础的组件。

Element VantAnt Design of Vue 等组件库已经够用了,而且很多人已经帮你踩过坑、代码的健壮性都比从从头自己写更好。

我们平常遇到的最多的是 “页面级的” 组件,然后就是一些项目内 “共通业务逻辑的” 组件。

比如说:顶部的导航区、右侧的菜单栏、用户展示(头像、名称)组件、单个商品展示组件、项目特有的数据字典选择组件等等。

接下来,让我们做一个简单的 “显示年龄” 的控件,并且在 App.vue 中使用它。

1)组件构成:

年龄组件 Age.vue 的功能很简单:

  • 接收 “生日” 数据 (String 类型)
  • 显示年龄字符串:如果大于 1 岁,显示 "XX 岁";否则显示 "不足一岁"

(计算年龄的时候,需要用到 JavaScript 原生的 Date 对象:https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Date

 

2)年龄组件 Age.vue

我们可以在 src\components 目录中,新建一个 Age.vue 文件。

输入 < 字符后,Vetur 插件会很耐斯地提示使用何种模板。

最后,我们完成的 Age.vue 大概是这样的:

<template>
  <span class="age">
    {{age}}
  </span>
</template>

<script>
export default {
  name: 'Age',
  props: {
    birthday: String
  },
  data: function() {
    return {
      age: this.computeAge()
    }
  },
  methods: {
    computeAge: function() {
      // 通过 this.birthday 计算年龄,省略计算逻辑 10000 字
      this.age = "正在计算中";
    }
  }
}
</script>

<style>
</style>

拆解一下,跟之前的组件(App.vue)不太一样的地方是:

其中比较重要的是用来接收数据的 props 属性,如果不写的话、组件的使用者就没法传递数据给组件了。

此外,Vue 官网也极力推荐,prop 的定义应该尽量详细,至少需要指定其类型,还给出了带参数校验的更好的例子。

 

3)深入了解 props 

props 属性中每个 prop 比较完整的定义规范的介绍在 https://cn.vuejs.org/v2/api/#props,简单归纳如下:

字段描述附加说明
type属性的数据类型

可以是下列原生构造函数中的一种:String、Number、Boolean、Array、Object、Date、Function、Symbol、任何自定义构造函数、或上述内容组成的数组。

如果使用者传递过来的值的类型不符合,Vue 会抛出一个警告。

我们上面的例子中 birthday: String 这种写法,其实就是:

birthday: {

   type: String

}

的简写。

default默认值

可以不设置,也可以设置为任意值。

如果使用者在传递的数据中没有指定本 prop,那么使用 default 中定义的默认值。

required本 prop 是否必须指定 
validator本 prop 的有效性校验函数 

如:

props: {
    // 简写方式,只指定类型
    height: Number,

    // 更加复杂和丰富的定义方式
    age: {
      type: Number, // 类型
      default: 0, // 默认值
      required: true, // 是否必须
      validator: function (value) { // 校验函数
        return value >= 0
      }
    }
  }

另外,props 是用来单向接收来自使用者指定的数据的(参见:单向数据流),有点儿像是 C/C++ 中的 “形参”。

因此,在组件里不要修改 props 中定义的数据,不然运行时会抛出一个警告异常。

当然,也不要在 data 属性中定义同名的数据,不然编译时就会报错

 

 

2、使用组件


现在我们已经写好 年龄组件 Age.vue 了,那么在 App.vue 中要怎么用起来呢?

最为精简的用法大概是这样的:

<template>
  <div id="app">
    <div>年龄:<Age birthday="2000-01-01"></Age></div>    
  </div>
</template>

<script>
import Age from './components/Age';

export default {
  name: "App",
  components: {
    Age
  }
};
</script>

<!-- 没有特殊的样式 -->
<style>
</style>

主要的修改点是:(注意按照下图中的序号来看,而不是从上往下地看)

上图中的步骤 1 和 2 其实是一体的,先导入后注册,都属于组件的 “局部注册”。

与之相对的还有 “全局注册”,全局注册的组件在所有的 vue 文件中都可以直接使用,就不用再挨个重复上面的步骤 1 和 2 了。

全局注册一般在 main.js 中进行,有些还相当不直观,在 import 的时候就直接调用全局注册函数、完成注册了。

另外,步骤 1 中的 import 语句,在项目中也会常伴我们左右。

除了导入 Vue 组件,能导入 CSS 文件,还能导入第三方的 JavaScript 库,比如说:Element 基础组件库、axios 网络请求库、lodash 实用工具库等。

import 导入和 export 导出本身也是比较复杂的 “模块管理” 的一部分,先记着怎么用就行,更多细节可以参照:https://zh.javascript.info/import-export

 

3、数据传递


有了上面的经验,好像组件的创建、使用和数据传递都 “尽在掌握之中” 了,一切也都非常简单。

不过,其实一切才刚刚开始,接下来才是有那么点儿绕、所以会分成多篇慢慢来说的 “数据传递”。

上面的例子中,我们在 App.vue 中直接使用了 <Age birthday="2000-01-01"></Age> 这样硬编码的方式,把数据传递给了 Age.vue  —— 实际项目中基本不可能有这种使用方式的。

现在,让我们稍微修改一下 App.vue,加入一个选择生日的 <input type="date"> 控件,把控件的日期传递给 Age.vue;当生日发生变化时,年龄显示也跟着变化。

根据之前《没时间学 Vue (4) —— 绑定(三):面向各种文本框的 v-model》的知识,我们很容易做出生日选择那部分。大概是这样的:

<template>
    <!-- 省略其他部分 -->
    <div>生日:<input type="date" v-model="birthDate"></div>
</template>


<script>
export default {
    // 也省略其他部分
    data: function() {
        return {
            birthDate: '2000-01-01'
        }
    }
}
</script>

那要怎么把生日选择控件的数据传递给 Age.vue 呢?之前的代码是这样的: <Age  birthday="2020-01-01"></Age>

如果你还记得《没时间学 Vue (3) —— 绑定(二):v-bind 和 v-model》这篇里提到过 “所有的 attribute 绑定,都得用 v-bind 的方式来做” 的这个原则,

你就很容易推测出来,数据得这么传递:

    <div>生日:<input type="date" v-model="birthDate"></div>
    <div>年龄:<Age v-bind:birthday="birthDate"></Age></div>

也可以把 v-bind:birthday 简写成 :birthday,但是你一定要能区分得出来,:birthday 和 birthday 这两种用法是完全不同的意思。

运行 npm run serve 命令,然后在浏览器中确认画面,貌似一切正常!

不过当我们试着修改生日选择组件的内容的时候 —— 比如说改成 1999 年 1 月 1 日 —— 你会发现,年龄控件的显示根本没有变化,自带冻龄效果。

为什么呢?为什么呢?等下篇我们说完 “计算属性和监听器”,你就知道了。

今天也不早了,就到此打住吧 —— 你要是实在很好奇的话,可以先看一下 Vue 的官网资料:计算属性和监听器,也可以折腾一下上面那个 “冻龄” 的问题。

 

4、思考题


今天的思考题,是实现下面这样的一个组件、并且在 App.vue 中使用(和测试)它。

友情提示:

  • 显示结果组件中,可以根据 “显示风格” 的值,使用 v-if / v-else-if 来控制显示内容
  • 显示内容可以使用函数来计算出来

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值