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

目录
相关文章
|
2天前
|
JavaScript
Vue3搜索框(InputSearch)
这篇文章介绍了如何在Vue 3中创建一个具有搜索、清除、加载状态等多功能的搜索框组件(InputSearch),并提供了组件的配置选项、事件处理和使用示例。
Vue3搜索框(InputSearch)
|
2天前
|
JavaScript API 容器
Vue3加载条(LoadingBar)
这是一个基于 Vue 的加载条组件,提供了丰富的自定义选项和方法。通过简单的 API,可以控制加载条的开始、结束及错误状态。支持设置容器类名、样式、颜色等属性,并可通过 `start`、`finish` 和 `error` 方法来触发不同状态。
Vue3加载条(LoadingBar)
|
2天前
|
JavaScript
Vue3滚动条(Scrollbar)
这是一个基于 Vue 的自定义滚动条组件 Scrollbar.vue,提供了丰富的配置选项和方法。通过参数如 `contentClass`、`size` 和 `trigger` 等,可以灵活控制滚动条的样式和行为。
Vue3滚动条(Scrollbar)
|
2天前
|
JavaScript
Vue3分段控制器(Segmented)
这是一个基于 Vue 的分段控制器组件 `Segmented`,支持多种选项和自定义渲染。通过 `v-model` 绑定当前选中值,并提供 `block`、`disabled` 和 `size` 等属性来调整样式。
Vue3分段控制器(Segmented)
|
2天前
|
JavaScript
Vue3渐变文字(GradientText)
该文档介绍了一个基于 Vue 的渐变文字组件 `GradientText`,允许用户通过配置参数实现不同样式和尺寸的文字渐变效果。支持自定义起始和结束颜色、渐变角度及多种预设类型(如 `primary`、`info` 等)。
Vue3渐变文字(GradientText)
|
2天前
|
JavaScript
Vue3抽屉(Drawer)
这是一个基于Vue的抽屉组件(Drawer),提供了丰富的自定义选项,如宽度、高度、标题、关闭按钮等,并支持顶部、右侧、底部和左侧四种方向。
Vue3抽屉(Drawer)
|
2天前
|
JavaScript API 开发者
关于维护vue3的响应式的那些事:unref、toRef、toRefs、toRaw、toValue
总结:Vue 3的Composition API提供的这些工具,大大增强了我们对响应式状态的操作能力,让状态管理变得更为灵活和高效。`unref`、`toRef`、`toRefs` 以及 `toRaw` 各有其用途和应用场景,灵活应用这些工具,将有助于开发出更为强大和响应式的Vue应用。在开发过程中,正确区分和使用这些API,能够有效提高开发效率以及应用的性能。
6 0
|
2天前
|
JavaScript 开发者
[译] 监听第三方 Vue 组件的生命周期钩子
[译] 监听第三方 Vue 组件的生命周期钩子
|
2天前
|
JavaScript 前端开发
[译] 复用 Vue 组件的 6 层手段
[译] 复用 Vue 组件的 6 层手段
|
3天前
|
JavaScript API
vue 批量自动引入并注册组件或路由
vue 批量自动引入并注册组件或路由