1、Vue组件基础:组件化思想、组件注册、组件命名规范、组件的基本结构

1.1 组件化思想:从“面条代码”到“乐高积木”

先聊聊组件化思想。说白了,就是把一个复杂的页面,拆成一个个独立的小模块。

我刚开始写前端那会儿,经常一个页面几千行代码。改一个按钮样式,得翻半天。后来接触了组件化,感觉就像从“煮面条”变成了“搭乐高”。每个组件只管自己的事,互不干扰。

组件化的核心价值在哪?

  • 复用性:写一次,到处用。比如一个弹窗组件,项目里几十个地方都能引用。
  • 可维护性:每个组件代码量少,出问题定位快。改一个组件,不影响其他地方。
  • 协作效率:团队里每人负责几个组件,并行开发,互不冲突。

我的经验:组件化不是越细越好。我在项目中见过有人把“一个数字”都做成组件,结果光组件通信就写了一堆代码。适可而止,按业务模块拆分最合理。

1.2 组件注册:全局注册 vs 局部注册

Vue里注册组件有两种方式。我建议你根据场景选,别一股脑全用全局注册。

1.2.1 全局注册

Vue.component() 注册。注册后,任何地方都能直接用。

// main.js
import Vue from 'vue'
import MyButton from './components/MyButton.vue'

Vue.component('MyButton', MyButton)

优点:方便,不用每个页面都 import。缺点:打包时所有全局组件都会打进去,哪怕你没用。

我曾经踩过的坑:项目初期图省事,把所有组件都全局注册了。结果首屏加载慢得不行。后来改成按需加载,速度提升明显。

1.2.2 局部注册

在组件内部通过 components 选项注册。只有当前组件能用。

// ParentComponent.vue
import ChildComponent from './ChildComponent.vue'

export default {
  components: {
    ChildComponent
  }
}

我个人的习惯是:通用组件(比如弹窗、表格)用全局注册;业务组件(比如“用户信息卡片”)用局部注册。这样既方便又不会太臃肿。

1.3 组件命名规范:别让名字成为“坑”

命名这事,看着小,但影响很大。我见过项目里组件名五花八门,查起来头疼。

Vue官方推荐两种风格:

风格 示例 使用场景
PascalCase(大驼峰) MyComponent 组件定义、模板中使用
kebab-case(短横线) my-component HTML模板、DOM中

几个实用规则:

  • 前缀命名:比如 BaseButtonAppHeaderTheModal。一看就知道是基础组件还是业务组件。
  • 语义化:别用 Comp1Comp2。用 UserAvatarOrderList 这种一眼能看懂的。
  • 单文件组件:文件名用 PascalCase,比如 UserCard.vue

小技巧:在模板里,Vue 会自动把 PascalCase 转成 kebab-case。所以你写 <MyComponent /><my-component /> 都行。但我建议统一用 PascalCase,更清晰。

1.4 组件的基本结构:一个 .vue 文件长什么样

一个标准的 Vue 单文件组件(SFC),包含三部分。嗯,这里要注意顺序:

<template>
  <div class="my-component">
    <h1>{{ title }}</h1>
    <button @click="handleClick">点击</button>
  </div>
</template>

<script>
export default {
  name: 'MyComponent',
  data() {
    return {
      title: 'Hello Vue'
    }
  },
  methods: {
    handleClick() {
      alert('你点击了按钮')
    }
  }
}
</script>

<style scoped>
.my-component {
  padding: 20px;
  border: 1px solid #ccc;
}
</style>

拆开来看:

  • <template>:写 HTML 结构。注意只能有一个根元素,我习惯用 <div> 包一下。
  • <script>:写 JavaScript 逻辑。包括数据、方法、生命周期等。
  • <style>:写 CSS。加上 scoped 属性,样式只对当前组件生效,不会污染全局。

避坑指南scoped 不是万能的。它通过添加 data 属性实现样式隔离,但如果你用了子组件的根元素,样式还是能穿透的。我遇到过几次样式冲突,后来养成了给每个组件加唯一类名的习惯。

1.5 组件通信:父子组件怎么“说话”

组件之间需要传递数据。最基础的就是父子通信。

1.5.1 父传子:props

父组件通过属性传值,子组件用 props 接收。

// 父组件
<ChildComponent :message="parentMsg" />

// 子组件
export default {
  props: {
    message: {
      type: String,
      required: true
    }
  }
}

我个人建议:props 一定要写类型校验。不然传错类型,排查起来很痛苦。

1.5.2 子传父:$emit

子组件通过 $emit 触发事件,父组件监听。

// 子组件
this.$emit('update', newValue)

// 父组件
<ChildComponent @update="handleUpdate" />

你想想看,这种模式其实很符合直觉:父组件给指令,子组件汇报结果。

1.6 组件生命周期:组件从生到死

每个组件都有生命周期钩子。我常用的几个:

钩子 触发时机 常用场景
created 实例创建后 初始化数据、调用 API
mounted DOM 挂载后 操作 DOM、集成第三方库
beforeDestroy 组件销毁前 清理定时器、取消订阅

我曾经犯过的错:在 created 里操作 DOM,结果拿不到元素。后来才明白,created 时 DOM 还没渲染,得用 mounted

1.7 小结

组件化开发,说白了就是“分而治之”。把大问题拆成小问题,每个小问题用一个组件解决。

这一章我们聊了:

  • 组件化思想:为什么拆、怎么拆
  • 组件注册:全局 vs 局部,按需选择
  • 命名规范:PascalCase + 前缀,清晰明了
  • 基本结构:template + script + style,三剑客
  • 通信与生命周期:父子传值、钩子时机

下一章,我们会深入组件的进阶用法。比如插槽、动态组件、异步加载。到时候再聊。

我的建议:学组件化,别光看。打开编辑器,写一个最简单的组件,注册、传值、触发事件,走一遍流程。比看十遍文章都管用。