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

目录
相关文章
|
14天前
|
缓存 JavaScript UED
Vue3中v-model在处理自定义组件双向数据绑定时有哪些注意事项?
在使用`v-model`处理自定义组件双向数据绑定时,要仔细考虑各种因素,确保数据的准确传递和更新,同时提供良好的用户体验和代码可维护性。通过合理的设计和注意事项的遵循,能够更好地发挥`v-model`的优势,实现高效的双向数据绑定效果。
117 64
|
14天前
|
JavaScript 前端开发 API
Vue 3 中 v-model 与 Vue 2 中 v-model 的区别是什么?
总的来说,Vue 3 中的 `v-model` 在灵活性、与组合式 API 的结合、对自定义组件的支持等方面都有了明显的提升和改进,使其更适应现代前端开发的需求和趋势。但需要注意的是,在迁移过程中可能需要对一些代码进行调整和适配。
|
14天前
|
前端开发 JavaScript 测试技术
Vue3中v-model在处理自定义组件双向数据绑定时,如何避免循环引用?
Web 组件化是一种有效的开发方法,可以提高项目的质量、效率和可维护性。在实际项目中,要结合项目的具体情况,合理应用 Web 组件化的理念和技术,实现项目的成功实施和交付。通过不断地探索和实践,将 Web 组件化的优势充分发挥出来,为前端开发领域的发展做出贡献。
24 8
|
13天前
|
存储 JavaScript 数据管理
除了provide/inject,Vue3中还有哪些方式可以避免v-model的循环引用?
需要注意的是,在实际开发中,应根据具体的项目需求和组件结构来选择合适的方式来避免`v-model`的循环引用。同时,要综合考虑代码的可读性、可维护性和性能等因素,以确保系统的稳定和高效运行。
18 1
|
13天前
|
JavaScript
Vue3中使用provide/inject来避免v-model的循环引用
`provide`和`inject`是 Vue 3 中非常有用的特性,在处理一些复杂的组件间通信问题时,可以提供一种灵活的解决方案。通过合理使用它们,可以帮助我们更好地避免`v-model`的循环引用问题,提高代码的质量和可维护性。
25 1
|
14天前
|
JavaScript
在 Vue 3 中,如何使用 v-model 来处理自定义组件的双向数据绑定?
需要注意的是,在实际开发中,根据具体的业务需求和组件设计,可能需要对上述步骤进行适当的调整和优化,以确保双向数据绑定的正确性和稳定性。同时,深入理解 Vue 3 的响应式机制和组件通信原理,将有助于更好地运用 `v-model` 实现自定义组件的双向数据绑定。
|
17天前
|
JavaScript 前端开发 API
从Vue 2到Vue 3的演进
从Vue 2到Vue 3的演进
31 0
|
17天前
|
JavaScript API 开发者
Vue是如何进行组件化的
Vue是如何进行组件化的
|
19天前
|
JavaScript 前端开发 开发者
vue 数据驱动视图
总之,Vue 数据驱动视图是一种先进的理念和技术,它为前端开发带来了巨大的便利和优势。通过理解和应用这一特性,开发者能够构建出更加动态、高效、用户体验良好的前端应用。在不断发展的前端领域中,数据驱动视图将继续发挥重要作用,推动着应用界面的不断创新和进化。
|
20天前
|
JavaScript 前端开发 开发者
vue学习第一章
欢迎来到我的博客!我是瑞雨溪,一名热爱前端的大一学生,专注于JavaScript与Vue,正向全栈进发。博客分享Vue学习心得、命令式与声明式编程对比、列表展示及计数器案例等。关注我,持续更新中!🎉🎉🎉
23 1
vue学习第一章