Vue博客搭建(2)组件初探

184 阅读3分钟

在上一篇文章中,我们创建了一个项目,也探究了一些基础文件的作用。这次我们要探究Vue中的App.vue文件,以及其他.vue文件的作用。

组件

每个Vue项目都是由若干个.vue文件,也就是“组件”组成的。组件和HTML中的元素类似,但是不光有画面UI上的功能,也承担的一定的代码和运算任务。我们以App.vue(这是所有Vue项目的入口文件)的代码为例,看一下一个组件的大致结构。

// 脚本部分,也就是JavaScript代码
<script setup>
import HelloWorld from './components/HelloWorld.vue'
import TheWelcome from './components/TheWelcome.vue'
</script>

// 页面部分,也就是HTML代码
<template>
  <header>
    <img alt="Vue logo" class="logo" src="./assets/logo.svg" width="125" height="125" />

    <div class="wrapper">
      <HelloWorld msg="You did it!" />
    </div>
  </header>
  
  <main>
    <TheWelcome />
  </main>
</template>

// 样式表部分,也就是css代码
<style scoped>
header {
  line-height: 1.5;
}

.logo {
  display: block;
  margin: 0 auto 2rem;
}

@media (min-width: 1024px) {
  header {
    display: flex;
    place-items: center;
    padding-right: calc(var(--section-gap) / 2);
  }

  .logo {
    margin: 0 2rem 0 0;
  }

  header .wrapper {
    display: flex;
    place-items: flex-start;
    flex-wrap: wrap;
  }
}
</style>

可以看到,前端的三件套的三部分分离的都很好,放入了一个文件中,经过Vue的处理后能够实现所有的功能。这被称作单文件组件(SFC)。Vue处理后,每个组件都会变成一个JavaScript对象,如下所示:

import { ref } from 'vue'

export default {
  setup() {
    const count = ref(0)
    return { count }
  },
  template: `
    <button @click="count++">
      You clicked me {{ count }} times.
    </button>`
  // 或者 `template: '#my-template-element'`
}

组件的引入和嵌套

我们观察上文的template中的代码,会发现有一些HTML元素并不是原生的元素,例如<HelloWorld msg="You did it!" /><TheWelcome />,观察components文件夹,会发现里面也有对应的HelloWorld.vue文件和TheWelcome.vue文件。是不是组件发生了嵌套?确实是这样的。在Vue中一个组件可以嵌套另一个组件,以实现复杂的功能。Vue项目中的组件们会以“组件树”的形式被渲染,类似于DOM树。

<script setup>
import HelloWorld from './components/HelloWorld.vue'
import TheWelcome from './components/TheWelcome.vue'
</script>

Vue使用了ES6中的模块化特性来实现组件的导入和导出。我们可以尝试把<Helloworld>元素和对应的import语句删除,会发现页面上已经看不到了。

组件的参数传递

既然组件是可以嵌套的,那么我们能不能在父组件中传递一些参数反应在子组件中呢?当然是可以的。这被称为组件的参数传递。我们先新建一个ArticlePreview.vue组件来进行测试。这个组件担任着在博客列表中预览博客标题和正文的功能。

<script setup>

defineProps(['title','mainText']);

</script>

<template>
    <div>
    <!-- 这里的语法可以让HTML显示script中的数据 -->
        {{ title }}
        {{ mainText }}
    </div>
</template>

<style>
</style>

defineProps是Vue3中预编译的宏指令,不需要引入,当Vue处理组件的时候,所有的参数都会被包装成一个对象(作为函数的返回值)绑定到组件中。

<header>
    <img alt="Vue logo" class="logo" src="./assets/logo.svg" width="125" height="125" />
    <ArticlePreview title="1" main-text="111"/>
    <ArticlePreview title="2" main-text="222"/>
    <div class="wrapper">
    </div>
</header>

在网页中就可以看到文章的标题和正文。

组件插槽

我们都知道元素不仅仅都是以单个HTML标签存在的,还有很多是以成对的元素存在的(比如<div></div>)。我们是不是也可以在自定义组件中实现这种效果呢?答案当然是可以的。这就叫做组件的插槽(slots)。

比如我们想让博客预览组件中的插槽代表博客标题,而不使用组件的属性传递,那么就可以直接用<slot/>元素来创造一个占位符。

<script setup>

defineProps(['mainText']);

</script>

<template>
    <div>
        <slot/>
        {{ mainText }}
    </div>
</template>

<style>
</style>

App.vue中可以像下文这样使用它,就能达到我们需要的效果了。

  <header>
    <img alt="Vue logo" class="logo" src="./assets/logo.svg" width="125" height="125" />
    <ArticlePreview main-text="111">1</ArticlePreview>
    <ArticlePreview main-text="222">2</ArticlePreview>
    <div class="wrapper">
    </div>
  </header>

组件插槽和传参的区别是显而易见的。插槽使用的是占位符,因此传入的值是很难作为JavaScript的数据来使用的,而且插槽是不能使用多个占位符的,毕竟两个元素之间只能夹一个数据。

<template>
    <div>
    <!-- 这样就会报错 -->
        <slot/>
        1
        <slot/>
        {{ mainText }}
    </div>
</template>