Skip to content

第5章:页面与视图基础

1. 页面组件编写(基础页面结构、样式编写)

1.1 基础页面结构

页面组件:在 pages 目录下创建的 .vue 文件,每个页面组件对应一个路由。

基本结构

vue
<template>
  <div>
    <h1>Page Title</h1>
    <p>Page content</p>
  </div>
</template>

<script setup>
// 组件逻辑
</script>

<style scoped>
/* 组件样式 */
</style>

示例

vue
<!-- pages/index.vue -->
<template>
  <div class="home">
    <h1>Welcome to Nuxt.js</h1>
    <p>This is the home page</p>
    <Button text="Click me" />
  </div>
</template>

<script setup>
// 无需导入 Button 组件,自动导入
</script>

<style scoped>
.home {
  padding: 20px;
  max-width: 800px;
  margin: 0 auto;
}

h1 {
  color: #333;
  font-size: 2rem;
}

p {
  color: #666;
  font-size: 1rem;
}
</style>

1.2 样式编写

1.2.1 单文件组件样式

使用 <style scoped>

vue
<template>
  <div class="page">
    <h1>Page Title</h1>
  </div>
</template>

<style scoped>
.page {
  padding: 20px;
}

h1 {
  color: #333;
}
</style>

使用 <style>:全局样式

vue
<template>
  <div class="page">
    <h1>Page Title</h1>
  </div>
</template>

<style>
/* 全局样式 */
body {
  font-family: Arial, sans-serif;
  margin: 0;
  padding: 0;
}

.page {
  padding: 20px;
}
</style>

1.2.2 CSS 预处理器

使用 SCSS

  1. 安装依赖

    bash
    npm install --save-dev sass
  2. 使用 SCSS

    vue
    <template>
      <div class="page">
        <h1>Page Title</h1>
      </div>
    </template>
    
    <style lang="scss" scoped>
    .page {
      padding: 20px;
      
      h1 {
        color: #333;
        font-size: 2rem;
      }
    }
    </style>

使用 Less

  1. 安装依赖

    bash
    npm install --save-dev less
  2. 使用 Less

    vue
    <template>
      <div class="page">
        <h1>Page Title</h1>
      </div>
    </template>
    
    <style lang="less" scoped>
    .page {
      padding: 20px;
      
      h1 {
        color: #333;
        font-size: 2rem;
      }
    }
    </style>

2. 组件自动导入与全局注册

2.1 组件自动导入

特性:在 components 目录下的组件会被自动导入,无需手动导入。

使用方法

vue
<template>
  <div>
    <Button text="Click me" />
    <Card title="Card Title">
      Card content
    </Card>
  </div>
</template>

<script setup>
// 无需导入 Button 和 Card 组件
</script>

2.2 组件目录结构

嵌套目录:组件可以放在 components 目录的子目录中,自动导入时会使用目录名作为组件名的前缀。

示例

  • components/ui/Button.vue → 组件名:UiButton
  • components/form/Input.vue → 组件名:FormInput

使用方法

vue
<template>
  <div>
    <UiButton text="Click me" />
    <FormInput v-model="inputValue" placeholder="Enter text" />
  </div>
</template>

<script setup>
const inputValue = ref('')
</script>

2.3 全局注册组件

plugins 目录下创建插件

typescript
// plugins/global-components.ts
import { defineNuxtPlugin } from '#app'
import MyGlobalComponent from '../components/MyGlobalComponent.vue'

export default defineNuxtPlugin((nuxtApp) => {
  nuxtApp.vueApp.component('MyGlobalComponent', MyGlobalComponent)
})

使用方法

vue
<template>
  <div>
    <MyGlobalComponent />
  </div>
</template>

<script setup>
// 无需导入,全局可用
</script>

3. 组件分层(页面组件、公共组件、业务组件拆分规范)

3.1 组件分层

3.1.1 页面组件

  • 位置pages 目录
  • 作用:对应路由,负责页面布局和逻辑
  • 特点:通常包含多个子组件,处理页面级别的状态和逻辑

示例

vue
<!-- pages/products/index.vue -->
<template>
  <div class="products-page">
    <h1>Products</h1>
    <ProductList :products="products" />
    <Pagination :total="total" :page="page" @change="handlePageChange" />
  </div>
</template>

<script setup>
const { data: products, pending, error } = useFetch('/api/products')
const { data: total } = useFetch('/api/products/count')
const page = ref(1)

function handlePageChange(newPage) {
  page.value = newPage
}
</script>

3.1.2 公共组件

  • 位置components/uicomponents/common 目录
  • 作用:可复用的 UI 组件,如按钮、输入框、卡片等
  • 特点:独立、可复用、无业务逻辑

示例

vue
<!-- components/ui/Button.vue -->
<template>
  <button 
    class="btn" 
    :class="{ 'btn-primary': primary, 'btn-secondary': !primary }"
    @click="$emit('click')"
  >
    <slot />
  </button>
</template>

<script setup>
defineProps({
  primary: {
    type: Boolean,
    default: false
  }
})

defineEmits(['click'])
</script>

<style scoped>
.btn {
  padding: 8px 16px;
  border: none;
  border-radius: 4px;
  cursor: pointer;
}

.btn-primary {
  background-color: #007bff;
  color: white;
}

.btn-secondary {
  background-color: #6c757d;
  color: white;
}
</style>

3.1.3 业务组件

  • 位置components 目录下按业务模块组织
  • 作用:包含业务逻辑的组件
  • 特点:与具体业务相关,可在多个页面中复用

示例

vue
<!-- components/product/ProductCard.vue -->
<template>
  <div class="product-card">
    <img :src="product.image" :alt="product.name" />
    <h3>{{ product.name }}</h3>
    <p>{{ product.description }}</p>
    <p class="price">${{ product.price }}</p>
    <Button @click="addToCart">Add to Cart</Button>
  </div>
</template>

<script setup>
defineProps({
  product: {
    type: Object,
    required: true
  }
})

defineEmits(['add-to-cart'])

function addToCart() {
  $emit('add-to-cart', product)
}
</script>

<style scoped>
.product-card {
  border: 1px solid #ddd;
  border-radius: 8px;
  padding: 16px;
  margin-bottom: 16px;
}

.product-card img {
  width: 100%;
  height: 200px;
  object-fit: cover;
  border-radius: 4px;
}

.price {
  font-weight: bold;
  color: #007bff;
}
</style>

4. 静态资源处理(图片、字体、样式文件存放规则与引用方式)

4.1 静态资源存放

public 目录:存放静态资源,如图片、字体、图标等。

目录结构

public/
├── images/         # 图片
├── fonts/          # 字体
├── icons/          # 图标
└── favicon.ico     # 网站图标

4.2 引用静态资源

直接引用

vue
<template>
  <div>
    <img src="/images/logo.png" alt="Logo" />
    <link rel="stylesheet" href="/css/main.css" />
  </div>
</template>

在 CSS 中引用

css
/* assets/css/main.css */
body {
  background-image: url('/images/bg.jpg');
  font-family: 'CustomFont', sans-serif;
}

@font-face {
  font-family: 'CustomFont';
  src: url('/fonts/custom-font.woff2') format('woff2');
  font-weight: normal;
  font-style: normal;
}

4.3 资产目录

assets 目录:存放需要经过构建处理的资源,如 SCSS、Less 文件等。

目录结构

assets/
├── css/            # 样式文件
├── scss/           # SCSS 文件
├── js/             # JavaScript 文件
└── images/         # 图片(会被构建处理)

引用 assets 目录中的资源

vue
<template>
  <div>
    <img src="~/assets/images/logo.png" alt="Logo" />
  </div>
</template>

<script setup>
// 导入 assets 中的样式
import '~/assets/css/main.css'
</script>

5. 元标签配置(useHead 钩子,自定义页面标题、描述、meta 标签)

5.1 基本用法

使用 useHead 钩子

vue
<template>
  <div>
    <h1>Home Page</h1>
  </div>
</template>

<script setup>
useHead({
  title: 'Home Page - My Nuxt App',
  meta: [
    { name: 'description', content: 'Welcome to my Nuxt.js application' },
    { name: 'keywords', content: 'nuxt, vue, javascript' }
  ],
  link: [
    { rel: 'canonical', href: 'https://example.com' }
  ]
})
</script>

5.2 动态元标签

使用响应式数据

vue
<template>
  <div>
    <h1>{{ product.name }}</h1>
  </div>
</template>

<script setup>
const route = useRoute()
const { data: product } = useFetch(`/api/products/${route.params.id}`)

useHead(() => ({
  title: product.value ? `${product.value.name} - Product` : 'Loading...',
  meta: [
    {
      name: 'description',
      content: product.value ? product.value.description : 'Loading product...'
    }
  ]
}))
</script>

5.3 全局元标签配置

nuxt.config.ts 中配置

typescript
export default defineNuxtConfig({
  app: {
    head: {
      title: 'My Nuxt App',
      meta: [
        { name: 'description', content: 'A Nuxt.js application' },
        { charset: 'utf-8' },
        { name: 'viewport', content: 'width=device-width, initial-scale=1' }
      ],
      link: [
        { rel: 'icon', type: 'image/x-icon', href: '/favicon.ico' }
      ]
    }
  }
})

5.4 布局中的元标签

在布局组件中使用 useHead

vue
<!-- layouts/default.vue -->
<template>
  <div>
    <header>Header</header>
    <main>
      <slot />
    </main>
    <footer>Footer</footer>
  </div>
</template>

<script setup>
useHead({
  meta: [
    { name: 'author', content: 'John Doe' }
  ]
})
</script>

小结

本章介绍了 Nuxt.js 的页面与视图基础,包括页面组件编写、组件自动导入、组件分层、静态资源处理和元标签配置。通过本章的学习,你应该已经掌握了如何创建和组织 Nuxt.js 页面和组件,以及如何处理静态资源和配置元标签。

在接下来的章节中,我们将学习 Nuxt.js 的数据获取与状态管理、布局与组件化开发等核心特性,帮助你更深入地理解和使用 Nuxt.js。

© 2026 编程马·菜鸟教程 版权所有