Vue3 官方文档速通(中)

简介: Vue3 官方文档速通(中)

Vue3 官方文档速通(上)https://developer.aliyun.com/article/1511920?spm=a2c6h.13148508.setting.14.f8774f0euyBLtl

三 深入组件

1. 注册

1.1 全局注册

使用 .component() 方法,让组件在全局可用:

import { createApp } from "vue";
 
const app = createApp({});
 
app.component(
  // 注册的名字
  "MyComponent",
  // 组件的实现
  {
    /* ... */
  }
);

.component() 可以链式调用:

app
  .component("ComponentA", ComponentA)
  .component("ComponentB", ComponentB)
  .component("ComponentC", ComponentC);

注意:全局注册存在以下几个问题:1. 全局注册组件后,即使没有被实际使用,仍会被打包在 JS 文件中。2. 全局注册使依赖关系变得不那么明确。不容易定位子组件的实现。

1.2 局部注册

导入后可以直接使用:

<script setup>
import ComponentA from "./ComponentA.vue";
</script>
 
<template>
  <ComponentA />
</template>

1.3 组件名格式

官方推荐使用 PascalCase 作为组件名的注册格式。

2. Props

2.1 Props 声明

使用 defineProps() 宏来声明:

<script setup>
// defineProps传入字符串数组
const props = defineProps(["foo"]);
// 或 传入对象:可进行类型检测。
const props = defineProps({
  title: String,
  likes: Number,
});
 
console.log(props.foo);
</script>

2.2 传递 prop 的细节

如果 prop 的名字很长,官方建议使用 camelCase 形式:

defineProps({
  greetingMessage: String,
});

传递 props 时,官方推荐以 kebab-case 形式:

<MyComponent greeting-message="hello" />

传递不同类型的值:

<!-- 虽然 `42` 是个常量,我们还是需要使用 v-bind -->
<!-- 因为这是一个 JS 表达式而不是一个字符串 -->
<BlogPost :likes="42" />
 
<!-- 根据一个变量的值动态传入 -->
<BlogPost :likes="post.likes" />
 
<!-- 仅写上 prop 但不传值,会隐式转换为 `true` -->
<BlogPost is-published />
 
<!-- 虽然 `false` 是静态的值,我们还是需要使用 v-bind -->
<!-- 因为这是一个 JS 表达式而不是一个字符串 -->
<BlogPost :is-published="false" />
 
<!-- 根据一个变量的值动态传入 -->
<BlogPost :is-published="post.isPublished" />
 
<!-- 虽然这个数组是个常量,我们还是需要使用 v-bind -->
<!-- 因为这是一个 JS 表达式而不是一个字符串 -->
<BlogPost :comment-ids="[234, 266, 273]" />
 
<!-- 根据一个变量的值动态传入 -->
<BlogPost :comment-ids="post.commentIds" />
 
<!-- 虽然这个对象字面量是个常量,我们还是需要使用 v-bind -->
<!-- 因为这是一个 JS 表达式而不是一个字符串 -->
<!-- <BlogPost
  :author="{
    name: 'Veronica',
    company: 'Veridian Dynamics',
  }"
/> -->

一个对象绑定多个 prop:

const post = {
  id: 1,
  title: "My Journey with Vue",
};
<BlogPost v-bind="post" />
<!-- 等价于: -->
<BlogPost :id="post.id" :title="post.title" />

2.3 单向数据流

props 都遵循单向绑定原则,不允许在子组件中去更改一个 prop。但有两个场景可能想要修改 prop:1.prop 被用于传入初始值,之后想将其作为一个响应式属性。2. 需要对传入的 prop 值做进一步的转换。

2.4 Prop 校验

defineProps({
  // 基础类型检查
  // (给出 `null` 和 `undefined` 值则会跳过任何类型检查)
  propA: Number,
  // 多种可能的类型
  propB: [String, Number],
  // 必传,且为 String 类型
  propC: {
    type: String,
    required: true,
  },
  // Number 类型的默认值
  propD: {
    type: Number,
    default: 100,
  },
  // 对象类型的默认值
  propE: {
    type: Object,
    // 对象或数组的默认值
    // 必须从一个工厂函数返回。
    // 该函数接收组件所接收到的原始 prop 作为参数。
    default(rawProps) {
      return { message: "hello" };
    },
  },
  // 自定义类型校验函数
  propF: {
    validator(value) {
      // The value must match one of these strings
      return ["success", "warning", "danger"].includes(value);
    },
  },
  // 函数类型的默认值
  propG: {
    type: Function,
    // 不像对象或数组的默认,这不是一个
    // 工厂函数。这会是一个用来作为默认值的函数
    default() {
      return "Default function";
    },
  },
});

自定义类或构造函数去验证,校验是否 Person 类的实例:

class Person {
  constructor(firstName, lastName) {
    this.firstName = firstName;
    this.lastName = lastName;
  }
}
 
defineProps({
  author: Person,
});

2.5 Boolean 类型转换

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

3. 事件

3.1 触发与监听事件

模板表达式可以直接使用 $emit 触发自定义事件:

<!-- MyComponent -->
<button @click="$emit('someEvent')">click me</button>

父组件通过@来监听事件:

<MyComponent @some-event="callback" />

3.2 事件参数

<button @click="$emit('increaseBy', 1)">
  Increase by 1
</button>
<MyButton @increase-by="(n) => (count += n)" />

3.3 声明触发的事件

通过 defineEmits() 宏来声明要触发的事件:

<script setup>
const emit = defineEmits(["inFocus", "submit"]);
 
function buttonClick() {
  emit("submit");
}
</script>

3.4 事件校验

校验事件参数是否符合要求,返回布尔值表明事件是否符合:

<script setup>
const emit = defineEmits({
  // 没有校验
  click: null,
 
  // 校验 submit 事件
  submit: ({ email, password }) => {
    if (email && password) {
      return true;
    } else {
      console.warn("Invalid submit event payload!");
      return false;
    }
  },
});
 
function submitForm(email, password) {
  emit("submit", { email, password });
}
</script>

4. 组件 v-model

v-model 在 input 上的用法:

<input v-model="searchText" />
<!-- 展开 -->
<input :value="searchText" @input="searchText = $event.target.value" />

v-model 在组件上的用法,通过 modelValue,update:modelValue 设置:

<!-- CustomInput.vue -->
<script setup>
defineProps(["modelValue"]);
defineEmits(["update:modelValue"]);
</script>
 
<template>
  <input
    :value="modelValue"
    @input="$emit('update:modelValue', $event.target.value)"
  />
</template>
<CustomInput v-model="searchText" />
<!-- 展开 -->
<CustomInput
  :model-value="searchText"
  @update:model-value="newValue => searchText = newValue"
/>
<!-- CustomInput.vue -->
<script setup>
import { computed } from "vue";
 
const props = defineProps(["modelValue"]);
const emit = defineEmits(["update:modelValue"]);
 
const value = computed({
  get() {
    return props.modelValue;
  },
  set(value) {
    emit("update:modelValue", value);
  },
});
</script>
 
<template>
  <input v-model="value" />
</template>

4.1 v-model 的参数

<MyComponent v-model:title="bookTitle" />
<!-- MyComponent.vue -->
<script setup>
defineProps(["title"]);
defineEmits(["update:title"]);
</script>
 
<template>
  <input
    type="text"
    :value="title"
    @input="$emit('update:title', $event.target.value)"
  />
</template>

4.2 多个 v-model 的绑定

<UserName v-model:first-name="first" v-model:last-name="last" />
<script setup>
defineProps({
  firstName: String,
  lastName: String,
});
 
defineEmits(["update:firstName", "update:lastName"]);
</script>
 
<template>
  <input
    type="text"
    :value="firstName"
    @input="$emit('update:firstName', $event.target.value)"
  />
  <input
    type="text"
    :value="lastName"
    @input="$emit('update:lastName', $event.target.value)"
  />
</template>

4.3 处理 v-model 修饰符

<MyComponent v-model.capitalize="myText" />
<script setup>
const props = defineProps({
  modelValue: String,
  modelModifiers: { default: () => ({}) },
});
 
const emit = defineEmits(["update:modelValue"]);
 
function emitValue(e) {
  let value = e.target.value;
  if (props.modelModifiers.capitalize) {
    value = value.charAt(0).toUpperCase() + value.slice(1);
  }
  emit("update:modelValue", value);
}
</script>
 
<template>
  <input type="text" :value="modelValue" @input="emitValue" />
</template>

v-model 参数和修饰符一起绑定:

<MyComponent v-model:title.capitalize="myText"></MyComponent>
const props = defineProps(['title', 'titleModifiers'])
defineEmits(['update:title']) 
 
console.log(props.titleModifiers) // { capitalize: true }

5. 透传 Attributes

5.1 Attributes 继承

class、style、id 传递给组件,透传给组件的元素。如果只有一个根节点,默认透传给根节点上,如果有多个根节点,通过 v-bind='$attrs'来确定透传给哪个根节点。

5.2 禁用 Attributes 继承

应用场景:组件只有一个根节点,但透传的 attribute 需要传到其他元素上。通过设置 inheritAttrs 选项为 false,v-bind='$attrs',来完全控制透传:

<script setup>
defineOptions({
  inheritAttrs: false,
});
// ...setup 逻辑
</script>
 
<template>
  <div class="btn-wrapper">
    <button class="btn" v-bind="$attrs">click me</button>
  </div>
</template>

5.3 在 JS 中访问透传 Attributes

使用 useAttrs() API 来访问一个组件的所有透传 attribute:

<script setup>
import { useAttrs } from "vue";
 
const attrs = useAttrs();
</script>

6. 插槽

6.1 插槽内容与出口

通过  确定插槽插入的位置:

<!-- FancyButton.vue -->
<button class="fancy-btn">
  <!-- 插槽出口 -->
  <slot></slot>
</button>
<FancyButton>
  <!-- 插槽内容 -->
  Click me!
</FancyButton>

6.2 渲染作用域

插槽内容可以访问父组件的状态,无法访问子组件的状态:

<span>{{ message }}</span>
<FancyButton>{{ message }}</FancyButton>

6.3 默认内容

外部没有传递内容,展示默认内容:

<button type="submit">
  <slot>
    <!-- 默认内容 -->
    Submit
  </slot>
</button>

6.4 具名插槽

通过 来设定,name 默认值为 default:

<div class="container">
  <header>
    <slot name="header"></slot>
  </header>
  <main>
    <slot name="default"></slot>
  </main>
  <footer>
    <slot name="footer"></slot>
  </footer>
</div>

通过 v-slot 有对应的简写 # 来使用,因此

Vue3 官方文档速通(下)https://developer.aliyun.com/article/1511958?spm=a2c6h.13148508.setting.32.f8774f0euyBLtl

目录
相关文章
|
1天前
|
JavaScript Java 测试技术
基于ssm+vue.js+uniapp小程序的QQ村旅游网站附带文章和源代码设计说明文档ppt
基于ssm+vue.js+uniapp小程序的QQ村旅游网站附带文章和源代码设计说明文档ppt
12 5
|
1天前
|
JavaScript Java 测试技术
基于ssm+vue.js+uniapp小程序的大湾区旅游推荐系统附带文章和源代码设计说明文档ppt
基于ssm+vue.js+uniapp小程序的大湾区旅游推荐系统附带文章和源代码设计说明文档ppt
16 4
|
1天前
|
JavaScript Java 测试技术
基于ssm+vue.js+uniapp小程序的城投公司企业人事管理系统附带文章和源代码设计说明文档ppt
基于ssm+vue.js+uniapp小程序的城投公司企业人事管理系统附带文章和源代码设计说明文档ppt
14 3
|
1天前
|
JavaScript Java 测试技术
基于ssm+vue.js+uniapp小程序的物流配送人员车辆调度管理系统附带文章和源代码设计说明文档ppt
基于ssm+vue.js+uniapp小程序的物流配送人员车辆调度管理系统附带文章和源代码设计说明文档ppt
11 3
|
1天前
|
JavaScript Java 测试技术
基于ssm+vue.js+uniapp小程序的购物商场附带文章和源代码设计说明文档ppt
基于ssm+vue.js+uniapp小程序的购物商场附带文章和源代码设计说明文档ppt
8 2
|
1天前
|
JavaScript Java 测试技术
基于ssm+vue.js+uniapp小程序的房源管理系统附带文章和源代码设计说明文档ppt
基于ssm+vue.js+uniapp小程序的房源管理系统附带文章和源代码设计说明文档ppt
9 2
|
1天前
|
JavaScript Java 测试技术
基于ssm+vue.js+uniapp小程序的校内二手商城交易系统附带文章和源代码设计说明文档ppt
基于ssm+vue.js+uniapp小程序的校内二手商城交易系统附带文章和源代码设计说明文档ppt
10 3
|
1天前
|
JavaScript Java 测试技术
基于ssm+vue.js+uniapp小程序的图书馆书库管理系统附带文章和源代码设计说明文档ppt
基于ssm+vue.js+uniapp小程序的图书馆书库管理系统附带文章和源代码设计说明文档ppt
10 4
|
1天前
|
JavaScript Java 测试技术
基于ssm+vue.js+uniapp小程序的学生社团管理系统附带文章和源代码设计说明文档ppt
基于ssm+vue.js+uniapp小程序的学生社团管理系统附带文章和源代码设计说明文档ppt
12 1
|
1天前
|
JavaScript Java 测试技术
基于ssm+vue.js+uniapp小程序的快餐店点餐结算系统附带文章和源代码设计说明文档ppt
基于ssm+vue.js+uniapp小程序的快餐店点餐结算系统附带文章和源代码设计说明文档ppt
11 2