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

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

文章目录

十三. Props传参

Props 声明

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

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

js 复制代码
// 在子组件中
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 形式。

html 复制代码
<script>
export default {
  props: {
    greetingMessage: String
  }
}
</script>
<template>
  <MyComponent greeting-message="hello" />
</template>

静态 vs. 动态 Props

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

html 复制代码
// 在父组件中
<ChildComp msg="Hello World" :type="myObj.type" />

传递不同的值类型

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

更改对象 / 数组类型的 props

虽然在子组件里修改父组件传下来的对象 / 数组类型的 props内部的值,但在大多数情况下是一种不好的实践,最好不要这样。

代替的方法是子组件抛出一个事件来通知父组件做出改变。

Prop 校验

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

js 复制代码
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 来检查类型是否匹配:
js 复制代码
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 转换规则才适用:

js 复制代码
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,还可以传递事件,子组件收到事件后可以在需要的时候触发,并向方法中传递参数,实现子组件向父组件传值。

html 复制代码
// ChildComp.vue
<script>
export default {
	data() {
		msg: '321'
	},
	emits: ['setMsg'], // 注册事件
	created() {
		this.$emit('setMsg', this.msg); // 调用事件1
	}
}
</script>
<template>
	<div @click="$emit('setMsg', msg)">向父组件传值<div> <!-- 调用事件2 -->
</template>
html 复制代码
<script>
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>

事件参数

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

声明触发的事件

js 复制代码
export default {
  emits: ['inFocus', 'submit']
}

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

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

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

事件校验

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

js 复制代码
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 })
    }
  }
}
相关推荐
Excel_VBA表格จุ๊บ1 小时前
wps宏js接入AI功能和接入翻译功能
javascript·wps·js宏
豪宇刘2 小时前
JavaScript 延迟加载的方法
开发语言·javascript
顾尘眠2 小时前
http常用状态码(204,304, 404, 504,502)含义
前端
摇光933 小时前
js迭代器模式
开发语言·javascript·迭代器模式
王先生技术栈4 小时前
思维导图,Android版本实现
java·前端
悠悠:)4 小时前
前端 动图方案
前端
anyup_前端梦工厂4 小时前
了解 ES6 的变量特性:Var、Let、Const
开发语言·javascript·ecmascript
星陈~4 小时前
检测electron打包文件 app.asar
前端·vue.js·electron
Aatroox5 小时前
基于 Nuxt3 + Obsidian 搭建个人博客
前端·node.js
每天都要进步哦5 小时前
Node.js中的fs模块:文件与目录操作(写入、读取、复制、移动、删除、重命名等)
前端·javascript·node.js