详解vue3中组件的定义、使用、传递props、监听事件

定义组件

JavaScript 对象形式的组件

当不使用构建步骤时,一个 Vue 组件以一个包含 Vue 特定选项的 JavaScript 对象来定义:

import { reactive, watchEffect } from 'https://cdn.bootcdn.net/ajax/libs/vue/3.3.4/vue.esm-browser.js'
let template = `
    <div>{{data.count}}</div>
    <button @click="data.count++">+1</button>
`

export default {
    setup: function () {
        let data = reactive({
            count: 0
        })

        let stop = watchEffect(()=>{
            console.log('watchEffect',data.count)
        })

        return { data }
    },
    template
}

上面的例子中定义了一个组件,并在一个 .js 文件里默认导出了它自己,但你也可以通过具名导出在一个文件中导出多个组件。

单文件组件

当使用构建步骤时,我们一般会将 Vue 组件定义在一个单独的 .vue 文件中,这被叫做单文件组件(简称 SFC):

Vue的单文件组件是一种特殊的组件,以“.vue”扩展名结尾。这种组件将HTML、CSS和JavaScript代码封装到一个单独的文件中,使得组件的代码更加简洁、易于管理和维护。

一个Vue单文件组件由三个部分组成:

  1. <template>:用于定义组件的HTML结构。
  2. <script>:用于编写组件的逻辑代码。
  3. <style>:用于为组件添加样式。
<script setup>
import { ref } from 'vue'
const greeting = ref('Hello World!')
</script>

<template>
  <p class="greeting">{{ greeting }}</p>
</template>

<style>
.greeting {
  color: red;
  font-weight: bold;
}
</style>

这种组件的引入和使用需要借助特定的加载器(例如vue-loader)和构建工具(例如webpack)。在使用脚手架创建Vue项目时,你可以在项目中直接创建和编写Vue单文件组件。这些组件的文件扩展名默认就是“.vue”,并且在项目中使用时可以直接引入和使用。如果你使用的是其他构建工具或配置,可能需要调整相应的加载器和配置来正确处理Vue单文件组件。

SFC 中的 <style> 标签一般会在开发时注入成原生的 <style> 标签以支持热更新,而生产环境下它们会被抽取、合并成单独的 CSS 文件。在实际项目中,我们一般会使用集成了 SFC 编译器的构建工具,比如 Vite 或者 Vue CLI (基于 webpack)

使用单文件组件可以提高代码的复用性和可维护性,同时也可以方便地实现组件之间的通信和数据共享。

语块注意点

每个 *.vue 文件最多可以包含一个顶层 <template> 块。每个 *.vue 文件最多可以包含一个 <script> 块。(使用<script setup>的情况除外)。每个 *.vue 文件最多可以包含一个 <script setup>。(不包括一般的 <script>),这个脚本块将被预处理为组件的 setup() 函数,这意味着它将为每一个组件实例都执行。<script setup> 中的顶层绑定都将自动暴露给模板。每个 *.vue 文件可以包含多个 <style> 标签,一个 <style> 标签可以使用 scopedmodule attribute来帮助封装当前组件的样式。

预处理器

这三个组成部分都可以使用 lang 这个 attribute 来声明预处理器语言,最常见的用例就是在 <script> 中使用 TypeScript,可以在 <style> 标签中使用 Sass 或是 <template> 中使用 Pug:

src 导入

如果你更喜欢将 *.vue 组件分散到多个文件中,可以为一个语块使用 src 这个 attribute 来导入一个外部文件。请注意 src 导入和 JS 模块导入遵循相同的路径解析规则:

1.相对路径需要以 ./ 开头

<template src="./template.html"></template>
<style src="./style.css"></style>
<script src="./script.js"></script>

2.也可以从 npm 依赖中导入资源

<!-- 从所安装的 "todomvc-app-css" npm 包中导入一个文件 -->
<style src="todomvc-app-css/index.css" />

注释

在每一个语块中你都可以按照相应语言的语法书写注释。对于顶层注释,请使用 HTML 的注释语法

使用组件

我们以单文件组件为例,假设我有个Count.vue子组件:

<template>
  <div>{{ count }}</div>
  <button v-on:click="count++">+1</button>
</template>

<script setup>
import { ref } from "vue";

let count = ref(0);
</script>

<style lang="scss" scoped>
</style>

在父组件就可以引入使用:

<script setup>
import Count from './components/Count.vue'
</script>

<template>
  <Count/>
</template>

<style scoped>
</style>

在 Vue 3 的 <script setup> 中,你可以直接声明组件的属性和方法,而不需要使用 export default。这是因为 <script setup> 本身就是默认导出的。当你使用 <script setup> 时,Vue 会自动从该脚本中提取默认导出,因此你不需要再使用 export default

如果不使用<script setup>,你就要这样写:

<template>
  <div>{{ count }}</div>
  <button v-on:click="count++">+1</button>
</template>

<script>
import { ref } from "vue";
export default {
  setup() {
    let count = ref(0);
    return { count };
  },
};
</script>

<style lang="scss" scoped>
</style>

在单文件组件中,推荐为子组件使用 PascalCase 的标签名,以此来和原生的 HTML 元素作区分:在 Vue.js 的单文件组件中,子组件的标签名通常推荐使用 PascalCase(每个单词首字母大写的命名方式)来命名。这是因为 PascalCase 命名方式更易于区分和阅读,并且与 JavaScript 的命名规范相一致。

虽然原生 HTML 标签名是不区分大小写的,但 Vue 单文件组件是可以在编译中区分大小写的:这意味着在 Vue 的单文件组件中,标签的大小写是敏感的。例如,<MyComponent> 和 <mycomponent> 被视为两个不同的标签。

我们也可以使用 /> 来关闭一个标签:在某些情况下,可以使用 /> 来直接关闭一个标签,而不是使用传统的 形式。这通常在一些没有内容的标签或者自闭合的标签中更常见

传递 props

Props 是一种特别的 attributes,父组件要给子组件传递props,就必须在子组件的 props 列表上声明它。这里要用到 defineProps 宏:

子组件:

<template>
    <div>{{ mes }}</div>
</template>

<script setup>
    defineProps(['mes'])
</script>

<style lang="scss" scoped>

</style>

defineProps 是一个仅 <script setup> 中可用的编译宏命令,并不需要显式地导入。声明的 props 会自动暴露给模板。defineProps 会返回一个对象,其中包含了可以传递给组件的所有 props

或者这样写:

<template>
  <div>{{ props.mes }}</div>
</template>

<script >
export default {
  props: {
    mes: String,
  }, // 还可以这样:props: ['mes']
  setup(props) {
    console.log(props);
    return { props };
  },
};
</script>

<style lang="scss" scoped>
</style>

父组件引入使用:

<Message mes="收到请回复"/>

监听事件

父组件如何监听子组件触发的事件呢?假设子组件完成了一定的任务需要触发一个自定义事件来通知父组件,这怎么做呢?

子组件触发事件

假设有一个Message子组件如下:

在<template>中

在模板中通过点击按钮触发一个自定义事件

<template>
	<div>
		<button v-on:click="$emit('complete')">完成</button>
	</div>
</template>

<script setup></script>

<style lang="scss" scoped></style>

在<script setup>中

或者我们可以通过 defineEmits 宏来声明需要抛出的事件。和 defineProps 类似,defineEmits 仅可用于 <script setup> 之中,并且不需要导入,它返回一个等同于 $emit 方法的 emit 函数。它可以被用于在组件的 <script setup> 中抛出事件:

<template>
</template>

<script setup>
	const emit = defineEmits(['complete'])
	emit('complete')
</script>

<style lang="scss" scoped></style>

在对象形式的组件中

如果你没有在使用 <script setup>,你可以通过 emits 选项定义组件会抛出的事件。你可以从 setup() 函数的第二个参数,即 setup 上下文对象上访问到 emit 函数:

export default {
    emits: ['complete'],
    setup(props, ctx) {
    	ctx.emit('complete')
    },
}

总结:我们有三种方式触发自定义事件

父组件监听事件

那么在父组件的模板中就可以绑定一个事件:

<script setup>
	import Message from './components/Message.vue'
</script>

<template>
	<Message v-on:complete="console.log('收到')" />
</template>

<style scoped></style>

以上的效果就是子组件通过各种方式触发了自定义的complete事件时,被父组件监听到,父组件在控制台打印“收到”

  • 36
    点赞
  • 49
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值