Vue 工程化开发:组件复用、插槽、项目结构与 ES6 模块化

一、组件基础

组件是可复用的界面单元,通常包含自己的模板、数据、方法、样式和生命周期。把页面拆成组件,可以降低单个文件的复杂度,也便于多人协作和后续维护。

组件的 data 必须是一个返回对象的函数。这样每次创建组件实例时都会得到独立的数据,避免多个实例共享同一个对象。

二、全局组件与局部组件

1. 全局组件

全局组件通过 Vue.component() 注册,注册后当前页面中的所有 Vue 实例和子组件都可以使用。全局组件适合按钮、图标等通用程度很高的组件,但数量过多会增加命名冲突和维护成本。

html 复制代码
<div id="app">
  <child-card></child-card>
</div>

<script src="./vue2/vue.js"></script>
<script>
  Vue.component('child-card', {
    template: `
      <section>
        <h2>{{ name }}</h2>
        <button @click="showMessage">显示提示</button>
      </section>
    `,
    data() {
      return { name: '子组件' }
    },
    methods: {
      showMessage() {
        alert('组件按钮被点击了')
      }
    }
  })

  new Vue({ el: '#app' })
</script>

2. 局部组件

局部组件只在注册它的父组件模板中可用,更适合业务页面中的专用组件。推荐把组件对象单独放在 .vue 文件中,再通过 import 引入。

html 复制代码
<div id="app">
  <photo-card></photo-card>
</div>

<script src="./vue2/vue.js"></script>
<script>
  const PhotoCard = {
    template: `
      <div>
        <img :src="image" alt="示例图片" width="200">
        <button @click="changeImage">切换图片</button>
      </div>
    `,
    data() {
      return { image: './img/1.png' }
    },
    methods: {
      changeImage() {
        this.image = './img/2.png'
      }
    }
  }

  new Vue({
    el: '#app',
    components: { PhotoCard }
  })
</script>

三、动态组件与 keep-alive

动态组件使用 <component :is="..."> 根据变量切换组件,适合选项卡、不同商品分类和多步骤表单。相比堆叠多个 v-if,动态组件能让切换逻辑更集中。

html 复制代码
<div id="app">
  <button @click="current = 'fresh-panel'">生鲜</button>
  <button @click="current = 'seafood-panel'">水产</button>
  <button @click="current = 'meat-panel'">肉类</button>

  <component :is="current"></component>
</div>

<script>
  Vue.component('fresh-panel', { template: '<h3>生鲜商品</h3>' })
  Vue.component('seafood-panel', { template: '<h3>水产商品</h3>' })
  Vue.component('meat-panel', { template: '<h3>肉类商品</h3>' })

  new Vue({
    el: '#app',
    data: { current: 'fresh-panel' }
  })
</script>

默认切换组件时,旧组件可能被销毁,输入框内容和局部状态也会丢失。keep-alive 会缓存动态组件实例,使组件切换回来时保留状态。

html 复制代码
<keep-alive>
  <component :is="current"></component>
</keep-alive>

被缓存组件可以使用 activateddeactivated 处理激活、停用逻辑。缓存不是越多越好,页面数量较多时要结合 includeexcludemax 控制缓存范围。

四、插槽 slot

插槽用于让父组件向子组件传入模板内容。子组件负责统一布局,父组件决定具体内容,因此很适合封装卡片、弹窗和页面布局。

1. 默认插槽

html 复制代码
<div id="app">
  <base-card>
    <p>这是父组件传入的正文。</p>
  </base-card>
</div>

<script>
  Vue.component('base-card', {
    template: `
      <section class="card">
        <h2>通用卡片</h2>
        <slot>没有传入内容时显示的默认文本</slot>
      </section>
    `
  })

  new Vue({ el: '#app' })
</script>

父组件写在 <base-card> 标签内部的内容会渲染到子组件的 <slot> 位置。没有传入内容时,slot 标签内部的文本会作为默认内容。

2. 具名插槽

一个组件需要多个内容区域时,可以使用具名插槽。Vue 2 中父组件使用 slot="名称",子组件用 <slot name="名称"> 接收。

html 复制代码
<base-layout>
  <template slot="header"><h2>文章标题</h2></template>
  <p>文章正文内容。</p>
  <template slot="footer"><button>保存</button></template>
</base-layout>

<script>
  Vue.component('base-layout', {
    template: `
      <div class="layout">
        <header><slot name="header"></slot></header>
        <main><slot></slot></main>
        <footer><slot name="footer"></slot></footer>
      </div>
    `
  })
</script>

Vue 3 使用 v-slot#header 的写法。项目升级时应按照对应版本的插槽语法编写,避免混用。

五、创建 Vue 项目

Vue 2 常使用 Vue CLI 创建项目,Vue 3 新项目通常使用 Vite。两者都依赖 Node.js 环境;Node.js 提供运行时,npm 负责安装和管理依赖。

bash 复制代码
# 查看 Node.js 和 npm 是否安装成功
node -v
npm -v

# 可选:配置 npm 镜像源
npm config set registry https://registry.npmmirror.com
npm config get registry

# Vue CLI(主要用于 Vue 2 或旧项目)
npm install -g @vue/cli
vue create vue-demo

# 进入项目并启动开发服务器
cd vue-demo
npm run serve

包管理器的核心职责是根据 package.json 安装依赖。不要把 node_modules 提交到 Git;把项目交给其他人时,执行 npm install 即可依据锁定文件重新安装依赖。

六、Vue 项目目录结构

典型 Vue CLI 项目结构如下:

text 复制代码
vue-demo/
├─ public/
│  └─ index.html       # SPA 的 HTML 入口
├─ src/
│  ├─ assets/          # 需要经过构建处理的图片、样式
│  ├─ components/      # 可复用的小组件
│  ├─ views/           # 页面级组件
│  ├─ router/          # 路由配置
│  ├─ store/           # 状态管理配置
│  ├─ App.vue          # 根组件
│  └─ main.js          # 应用启动入口
├─ package.json        # 项目脚本和依赖声明
├─ package-lock.json   # 依赖版本锁定文件
└─ vue.config.js       # Vue CLI 构建配置(可选)

public/index.html 通常只保留挂载点,Vue 会把根组件渲染到 #app。业务代码主要写在 src 中。assets 中的资源会被构建工具处理,直接放在 public 的资源则按原路径提供。

七、Vue 单文件组件规范

.vue 文件通常由 <template><script><style> 三部分组成。scoped 会让样式只作用于当前组件生成的节点,避免普通类名污染其他组件。

vue 复制代码
<template>
  <header class="top-bar">
    <button @click="goBack">后退</button>
    <span>{{ title }}</span>
    <button @click="goForward">前进</button>
  </header>
</template>

<script>
export default {
  name: 'TopBar',
  data() {
    return { title: '首页' }
  },
  methods: {
    goBack() {
      window.history.back()
    },
    goForward() {
      window.history.forward()
    }
  }
}
</script>

<style scoped>
.top-bar {
  display: flex;
  justify-content: space-between;
  align-items: center;
}
</style>

在其他组件中使用时,需要先导入,再注册,最后在模板中使用:

vue 复制代码
<template>
  <div id="app">
    <TopBar />
  </div>
</template>

<script>
import TopBar from '@/components/TopBar.vue'

export default {
  name: 'App',
  components: { TopBar }
}
</script>

@ 通常是构建工具配置的 src 别名。组件名推荐使用多单词形式,避免和原生 HTML 标签冲突。

八、路由与页面组件

使用 Vue Router 后,URL 和页面组件的对应关系由路由表决定。App.vue 一般只保留布局和 <router-view />,当前路由匹配的页面会渲染到这个位置。

js 复制代码
// src/router/index.js
import Vue from 'vue'
import VueRouter from 'vue-router'
import HomeView from '@/views/HomeView.vue'
import AboutView from '@/views/AboutView.vue'

Vue.use(VueRouter)

export default new VueRouter({
  mode: 'history',
  routes: [
    { path: '/', name: 'home', component: HomeView },
    { path: '/about', name: 'about', component: AboutView }
  ]
})
vue 复制代码
<!-- App.vue -->
<template>
  <div id="app">
    <router-link to="/">首页</router-link>
    <router-link to="/about">关于</router-link>
    <router-view />
  </div>
</template>

创建新页面时,通常在 views 中新建页面组件,再在路由配置中注册路径。组件内部的可复用部分放入 components,不要把所有代码都堆在页面组件中。

九、ES6 常用语法

1. let、const 与块级作用域

let 声明可重新赋值的块级变量,const 声明不能重新赋值的绑定。对象用 const 声明后,仍然可以修改对象内部属性;不能做的是给变量重新绑定另一个对象。

js 复制代码
let count = 1
count = 2

const user = { name: 'lqz' }
user.name = 'new name' // 可以修改属性
// user = {}           // 不允许重新赋值

if (true) {
  let inside = '只在代码块内有效'
  const fixed = 1
}
// console.log(inside) // ReferenceError

var 具有函数作用域和变量提升,容易造成意外覆盖。现代项目通常优先使用 const,确实需要重新赋值时使用 let

2. 模板字符串

反引号字符串支持换行和插值,适合拼接提示文本或组件模板:

js 复制代码
const name = 'lqz'
const message = `你好,${name}!`
console.log(message)

3. 解构赋值

解构可以从对象或数组中提取值,接口返回数据和函数参数处理中经常使用。

js 复制代码
const user = { name: 'lqz', age: 19 }
const { name, age, city = '未知' } = user

const numbers = [11, 22, 33]
const [first, second] = numbers

function getUser() {
  return { username: 'tom', role: 'admin' }
}
const { username, role } = getUser()
console.log(name, age, city, first, second, username, role)

缺少的对象属性会得到 undefined,可以在解构时使用 = 提供默认值。

4. 默认参数与展开运算符

js 复制代码
function greet(name = '访客') {
  return `你好,${name}`
}

const base = { age: 19, hobby: '阅读' }
const user = { name: 'lqz', ...base }

const first = [1, 2]
const all = [0, ...first, 3]

function collect(firstValue, ...rest) {
  return { firstValue, rest }
}

console.log(greet())
console.log(user, all, collect(...[10, 20, 30]))

对象展开通常用于浅拷贝和合并配置;嵌套对象仍然共享引用,需要深拷贝时应使用专门方案。

十、ES6 模块化

模块通过 export 暴露内容,通过 import 引入内容。默认导出一个模块只能有一个,命名导出可以有多个。

js 复制代码
// utils.js:默认导出
const appName = 'Vue Demo'
function add(a, b) {
  return a + b
}
export default { appName, add }
js 复制代码
// 使用默认导出
import utils from './utils.js'
console.log(utils.appName)
console.log(utils.add(3, 4))
js 复制代码
// utils.js:命名导出
export const version = '1.0.0'
export function subtract(a, b) {
  return a - b
}
js 复制代码
import { version, subtract as minus } from './utils.js'
console.log(version, minus(8, 3))

如果目录下存在 index.js,导入时通常可以只写目录路径。模块化的价值在于拆分职责、避免全局变量污染,并使依赖关系在文件顶部清晰可见。

十一、总结与练习

  1. 全局组件使用方便但容易产生命名和维护问题,业务组件优先局部注册。
  2. 动态组件负责切换,keep-alive 负责缓存;插槽负责让父组件注入可变内容。
  3. Vue 项目通过 main.js 启动,页面组件放在 views,可复用组件放在 components,路由配置集中在 router
  4. letconst、解构、展开和模块化是 Vue 工程中高频使用的 ES6 语法。
  5. 建议完成一个带选项卡、可缓存表单、具名插槽卡片和路由页面的综合练习,体会组件拆分和数据复用。
相关推荐
这是个栗子2 小时前
前端开发中的常用工具函数(十):JavaScript 数组遍历
javascript·map·遍历·filter·foreach·for·for...of
FYKJ_20102 小时前
django学习成绩预警系统10905
java·javascript·spring boot·python·spark·django·php
云浪2 小时前
给大模型装上"手":三分钟看懂 AI Agent 的 Tool 工具调用
javascript·人工智能·node.js
风月说与山鬼2 小时前
六、React事件
前端·javascript·react.js
岁岁种桃花儿2 小时前
Vue核心语法第十四篇:列表过滤
前端·javascript·vue.js
晓得迷路了2 小时前
栗子前端技术周刊第 143 期 - npm 攻击事件、Bun 1.4...
前端·javascript
常宇佳2 小时前
vue3 实战系列之踩过的一些坑
javascript·vue.js·elementui
孙克旭_14 小时前
Docker 镜像构建|Vue+SpringBoot+Go 多语言项目 Dockerfile 案例
linux·运维·vue.js·spring boot·docker·dockerfile
雪芽蓝域zzs15 小时前
(六)打包优化 + Nginx 部署完整配置 + 项目收尾
前端·vue.js