Vue演练场基础知识(六)Props传参+Emits事件

news/2025/1/9 15:55:28 标签: vue.js, javascript, 前端

为学习Vue基础知识,我动手操作通关了Vue演练场,该演练场教程的目标是快速体验使用 Vue 是什么感受,设置偏好时我选的是选项式 + 单文件组件。以下是我结合深入指南写的总结笔记,希望对Vue初学者有所帮助。

文章目录

  • 十三. Props传参
    • Props 声明
    • 传递 prop 的细节
      • Prop 名字格式
      • 静态 vs. 动态 Props
      • 传递不同的值类型
    • 单向数据流
      • 更改对象 / 数组类型的 props
    • Prop 校验
      • 运行时类型检查​
      • 可为 null 的类型
    • Boolean 类型转换
  • 十四. Emits事件
    • 触发与监听事件
    • 事件参数
    • 声明触发的事件
    • 事件校验

十三. Props传参

Props 声明

子组件可以通过 props 从父组件接受动态数据,同时它需要显式声明它所接受的 props,这样 Vue 才能知道外部传入的哪些是 props,哪些是透传 attribute。

“透传 attribute”指的是传递给一个组件,却没有被该组件声明为 props 或 emits 的 attribute 或者 v-on 事件监听器。最常见的例子就是 class、style 和 id。“透传 attribute”会被自动原封不动透传到收到它的组件的根元素上。

// 在子组件中
export default {
  props: {
    msg: String
  }
  created() {
  	console.log(this.msg);
  }
}
// 或
export default {
  props: ['msg']
}

对于以对象形式声明的每个属性,key 是 prop 的名称,而值则是该 prop 预期类型的构造函数。比如,如果要求一个 prop 的值是 number 类型,则可使用 Number 构造函数作为其声明的值。
props声明的作用不只是声明props类型,一定程度上作为组件的文档,它还可以:

  1. 其他开发者在使用你的组件时传递了错误的类型,在浏览器控制台中抛出警告。
  2. 显式或隐式地设置默认值
  3. Boolean 类型的 props 有特别的类型转换规则

传递 prop 的细节

Prop 名字格式

推荐的命名形式:
props 声明用camelCase 形式;
props 传递用kebab-case 形式;
组件名用PascalCase 形式。

<script>javascript">
export default {
  props: {
    greetingMessage: String
  }
}
</script>
<template>
  <MyComponent greeting-message="hello" />
</template>

静态 vs. 动态 Props

父组件可以通过 props 向子组件传递固定值,或使用 v-bind 语法传递动态值。

// 在父组件中
<ChildComp msg="Hello World" :type="myObj.type" />

传递不同的值类型

<ChildComp 
   :likes="42"
   :comment-ids="[234, 266, 273]"
   :author="{
     name: 'Veronica',
     company: 'Veridian Dynamics'
   }"
   v-model="obj"
   is-flag
/>

v-model="obj"等同于逐个绑定obj中的所有属性。
若已声明is-flag类型为Boolean,则只传is-flag不传值等同于:is-flag="true",不传is-flag等同于:is-flag="false"

单向数据流

所有的 props 都遵循着单向绑定原则,props 因父组件的更新而变化,自然地将新的状态向下流往子组件,而不会逆向传递,也不允许修改props。
一般来说,我们修改props的需求可以根据需求场景不同用以下两种方法代替:

  1. 场景1: prop 被用于传入初始值;而子组件想在之后将其作为一个局部数据属性。
export default {
  props: ['initialCounter'],
  data() {
    return {
 	  // this.initialCounter仅用于为counter赋初始值,与counter后续更新无关
      counter: this.initialCounter
    }
  }
}
  1. 场景2:需要对传入的 prop 值做进一步的转换。
export default {
  props: ['size'],
  computed: {
    // 该 prop 变更时计算属性也会自动更新
    normalizedSize() {
      return this.size.trim().toLowerCase()
    }
  }
}

更改对象 / 数组类型的 props

虽然在子组件里修改父组件传下来的对象 / 数组类型的 props内部的值,但在大多数情况下是一种不好的实践,最好不要这样。
代替的方法是子组件抛出一个事件来通知父组件做出改变。

Prop 校验

你可以向 props 选项提供一个带有 props 校验选项的对象,更细致地声明对传入的 props 的校验要求:

export default {
  props: {
    // 基础类型检查
    //(给出 `null` 和 `undefined` 值则会跳过任何类型检查)
    propA: Number,
    // 多种可能的类型
    propB: [String, Number],
    // 必传,且为 String 类型
    propC: {
      type: String,
      required: true
    },
    // 必传但可为 null 的字符串
    propD: {
      type: [String, null],
      required: true
    },
    // Number 类型的默认值
    propE: {
      type: Number,
      default: 100
    },
    // 对象类型的默认值
    propF: {
      type: Object,
      // 对象或者数组应当用工厂函数返回。
      // 工厂函数会收到组件所接收的原始 props(即父组件传入propF的值)
      // 作为参数
      default(rawProps) {
        return { message: 'hello' }
      }
    },
    // 自定义类型校验函数
    // 在 3.4+ 中完整的 props 作为第二个参数传入
    propG: {
      validator(value, props) {
        // The value must match one of these strings
        return ['success', 'warning', 'danger'].includes(value)
      }
    },
    // 函数类型的默认值
    propH: {
      type: Function,
      // 不像对象或数组的默认,这不是一个
      // 工厂函数。这会是一个用来作为默认值的函数
      default() {
        return 'Default function'
      }
    }
  }
}

一些补充细节:

  1. 所有 prop 默认都是可选的,除非声明了 required: true。
  2. 除 Boolean 外的未传递的可选 prop 将会有一个默认值 undefined。
  3. Boolean 类型的未传递 prop 将被转换为 false。这可以通过为它设置 default 来更改——例如:设置为 default: undefined 将与非布尔类型的 prop 的行为保持一致。
  4. 如果声明了 default 值,那么在 prop 的值被解析为 undefined 时,无论 prop 是未被传递还是显式指明的 undefined,都会改为 default 值。

注意 prop 的校验是在组件实例被创建之前,所以实例的属性 (比如 data、computed 等) 将在 default 或 validator 函数中不可用。

运行时类型检查​

校验选项中的 type 可以是下列这些原生构造函数:

  • String
  • Number
  • Boolean
  • Array
  • Object
  • Date
  • Function
  • Symbol
  • Error
    也可以自定义类或构造函数,Vue 将会通过 instanceof 来检查类型是否匹配:
class Student {
	firstName: string;
	lastName: string;
}
class Person {
  constructor(firstName, lastName) {
    this.firstName = firstName
    this.lastName = lastName
  }
}

可为 null 的类型

注意如果type仅为null而非使用数组语法,它将允许任何类型。

Boolean 类型转换

为了更贴近原生 boolean attributes 的行为,声明为 Boolean 类型的 props 有特别的类型转换规则。

<!-- 等同于传入 :disabled="true" -->
<MyComponent disabled />

<!-- 等同于传入 :disabled="false" -->
<MyComponent />

当一个 prop 被声明为允许多种类型时,Boolean 的转换规则也将被应用。然而,当同时允许 String 和 Boolean 时,有一种边缘情况——只有当 Boolean 出现在 String 之前时,Boolean 转换规则才适用:

export default {
  props: {
    disabled1: [Boolean, Number], // <MyCompo disabled />将被解析为 disabled=true
    disabled2: [Boolean, String], // disabled=true
    disabled3: [Number, Boolean], // disabled=true
    disabled4: [String, Boolean], // disabled=""(空字符串)
  }
}

十四. Emits事件

触发与监听事件

父组件除了向子组件传递props、attribute,还可以传递事件,子组件收到事件后可以在需要的时候触发,并向方法中传递参数,实现子组件向父组件传值。

// ChildComp.vue
<script>javascript">
export default {
	data() {
		msg: '321'
	},
	emits: ['setMsg'], // 注册事件
	created() {
		this.$emit('setMsg', this.msg); // 调用事件1
	}
}
</script>
<template>
	<div @click="$emit('setMsg', msg)">向父组件传值<div> <!-- 调用事件2 -->
</template>
<script>javascript">
export default {
	data() {
		return {msg: '123'};
	},
	components: {ChildComp},
	methods: {
		func1(parameter) {...}
	}		
}
</script>
<template>
	<ChildComp @set-msg="newMsg => msg = newMsg" /> <!-- 传入事件1 -->
	<ChildComp @set-msg.once="newMsg => msg = newMsg" /> <!-- 传入事件2 -->
	<ChildComp @set-msg.once="func1" /> <!-- 传入事件3 -->
	{{msg}}
</template>

事件参数

// 第2~n个参数会成为传入setMsg函数的第1~(n-1)个参数
this.$emit('setMsg', 参数1, 参数2, 参数3);

声明触发的事件

export default {
  emits: ['inFocus', 'submit']
}

emits还支持对象语法,并能在执行事件前对传入的参数进行校验。

export default {
  emits: {
    submit(payload: { email: string, password: string }) {
      // 通过返回值为 `true` 还是为 `false` 来判断
      // 验证是否通过
    }
  }
}

推荐完整地声明所有要触发的事件,作为文档记录组件的用法,又能让 Vue 更好地将事件和透传 attribute 作出区分:如果一个原生事件的名字 (例如 click) 被定义在 emits 选项中,则监听器只会监听组件触发的 click 事件而不会再响应原生的 click 事件。

事件校验

使用对象语法就能对emit事件进行校验,但不能校验DOM原生事件。

export default {
  emits: {
    // 没有校验
    click: null,

    // 校验 submit 事件
    submit: ({ email, password }) => {
      if (email && password) {
        return true
      } else {
        console.warn('Invalid submit event payload!')
        return false
      }
    }
  },
  methods: {
    submitForm(email, password) {
      this.$emit('submit', { email, password })
    }
  }
}

http://www.niftyadmin.cn/n/5817695.html

相关文章

设计模式-结构型-桥接模式

1. 什么是桥接模式&#xff1f; 桥接模式&#xff08;Bridge Pattern&#xff09; 是一种结构型设计模式&#xff0c;它旨在将抽象部分与实现部分分离&#xff0c;使它们可以独立变化。通过这种方式&#xff0c;系统可以在抽象和实现两方面进行扩展&#xff0c;而无需相互影响…

vite5.x配置https

旧版的vite直接在config里面配置https&#xff1a;true即可&#xff0c;新版的麻烦一些。 1.准备工作 需要安装openssl 下载地址&#xff1a;Win32/Win64 OpenSSL Installer for Windows - Shining Light Productions 找到合适的版本安装&#xff0c;配置好环境变量&#x…

Internet协议原理

文章目录 考试说明Chapter 0: 本书介绍Chapter 1: Introduction And Overview 【第1章&#xff1a;引言与概述】Chapter 2: Overview Of Underlying Network Technologies 【第2章&#xff1a;底层网络技术的回顾】Chapter 3: Internetworking Concept And Architectural Model…

【单片机】实现一个简单的ADC滤波器

实现一个 ADC的滤波器&#xff0c;PT1 滤波器&#xff08;也称为一阶低通滤波器&#xff09;&#xff0c;用于对输入信号进行滤波处理。 typedef struct PT1FilterSettings PT1FilterSettings; struct PT1FilterSettings {//! last Filter output valueuint32_t filtValOld;//…

Linux下文件操作相关接口

文章目录 一 文件是什么普通数据文件 二 文件是谁打开的进程用户 三 进程打开文件的相关的接口c语言标准库相关文件接口1. fopen 函数2. fread 函数3. fwrite 函数4. fclose 函数5. fseek 函数 linux系统调用接口1. open 系统调用2. creat 系统调用3. read 系统调用4. write 系…

汽车免拆诊断 | 2017 款东风风神 AX7 车热机后怠速不稳

故障现象 一辆2017款东风风神AX7车&#xff0c;搭载DFMA14T发动机&#xff0c;累计行驶里程约为13.7万km。该车冷起动后怠速运转正常&#xff0c;热机后怠速运转不稳&#xff0c;组合仪表上的发动机转速表指针上下轻微抖动。 故障诊断  用故障检测仪检测&#xff0c;发动机控…

Windows使用AutoHotKey解决鼠标键连击现象(解决鼠标连击、单击变双击的故障)

注&#xff1a;罗技鼠标&#xff0c;使用久了之后会出现连击现象&#xff0c;如果刚好过保了&#xff0c;可以考虑使用软件方案解决连击现象&#xff1a; 以下是示例AutoHotKey脚本&#xff0c;实现了调用XButton1用于关闭窗口&#xff08;以及WinW&#xff0c;XButton2也导向…

前端金额运算精度丢失问题及解决方案

前言 前端开发中难免会遇到价格和金额计算的需求&#xff0c;这类需求所要计算的数值大多数情况下是要求精确到小数点后的多少位。但是因为JS语言本身的缺陷&#xff0c;在处理浮点数的运算时会出现一些奇怪的问题&#xff0c;导致计算不精确。 本文尝试从现象入手&#xff0…