组件是可以复用的 vue 实例

在通过 new Vue 创建的 Vue 根实例中,组件作为自定义元素使用

每用一次组件,就会有一个它的新实例被创建

组件的 data 必须是函数

一个网页可以看作是一颗嵌套的组件树:

components.png

组件名

  • 使用全小写并用短横线分割 (推荐)
  1. /* 定义 */
  2. Vue.component('component-name', {/* ... */})
  3. /* 使用 */
  4. <component-name>
  • 使用首字母大写
  1. /* 定义 */
  2. Vue.component('ComponentName', { /* ... */ })
  3. /* 使用 */
  4. <ComponentName>
  5. <component-name>

全局注册

注册后可用在任何新创建的 Vue 实例(new Vue)的模板中与所有子组件中

  1. Vue.component('component-name', {
  2. // 选项
  3. })

局部注册

  1. var ComponentA = { /* ... */ }
  2. var ComponentB = { /* ... */ }
  1. new Vue({
  2. el: '#app',
  3. components: {
  4. 'component-a': ComponentA,
  5. 'component-b': ComponentB,
  6. }
  7. })

在组件 ComponentC 中使用局部注册的 ComponentA, ComponentB

推荐使用模块系统:创建一个 components 目录,并将每个组件放置在其各自的文件中。

  1. import ComponentA from './ComponentA.vue'
  2. import ComponentB from './ComponentA.vue'
  3. export default {
  4. components: {
  5. ComponentA, // 析构赋值,相当于 {ComponentA: ComponentA}
  6. ComponentB
  7. }
  8. }

由于有些操作系统不分大小写,因此推荐文件名使用全小写,组件名使用大驼峰

选项 Props

  • props 用于存放外部属性,即从父组件中获得数据
  • 类型:Array | Object
  • 由于 HTML大小写不敏感,因此在模板中使用 kebab-case (短横线分隔命名) 命名

传递值和函数:通过父组件改变子组件的 props 值
子组件 props.vue 中:

  1. <template>
  2. <div>
  3. {{ number }}
  4. <button @click="fn">+1</button>
  5. </div>
  6. </template>
  7. <script>
  8. export default {
  9. name: "Prop",
  10. // props 为对象,可设置类型检验
  11. props: {
  12. number: Number,
  13. fn: Function,
  14. },
  15. // props 为数组
  16. // props: ["number", "fn"],
  17. };
  18. </script>
  19. <style lang="scss">
  20. </style>

父组件中:

  1. <template>
  2. <div id="app">
  3. <Prop :number="n" :fn="add" />
  4. </div>
  5. </template>
  6. <script>
  7. import Prop from "./components/prop.vue";
  8. export default {
  9. name: "App",
  10. data() {
  11. return {
  12. n: 0,
  13. };
  14. },
  15. components: {
  16. Prop,
  17. },
  18. methods: {
  19. add() {
  20. console.log(1);
  21. this.n += 1;
  22. },
  23. },
  24. };
  25. </script>
  26. <style lang="scss">
  27. </style>

props2.png

  • 使用 v-bind 动态赋值

父组件中:

  1. <!-- 传递静态值,number 为字符串 n -->
  2. <Prop number="n" />
  3. <!-- 动态赋值使用 v-bind,双引号内为 js 代码, number 为变量 n 的值 -->
  4. <Prop :number="n" />
  5. <!-- 以下两个等价,都传递字符串 'n' -->
  6. <Prop number="n" />
  7. <Prop :number=" 'n' " />
  • props 可传递的 type : String, Number, Boolean, Array, Object, Date, Function, Symbol, 自定义构造函数
  • 需要规定每个 prop 的类型与类型检验时,可使用对象
  • props 验证:为 props 中的值提供带有验证需求的对象,若验证失败则产生警告
  1. Vue.component('my-component', {
  2. props: {
  3. // 基础的类型检查 (`null` 和 `undefined` 会通过任何类型验证)
  4. propA: Number,
  5. // 多个可能的类型
  6. propB: [String, Number],
  7. // 必填的字符串
  8. propC: {
  9. type: String,
  10. required: true
  11. },
  12. // 带有默认值的数字
  13. propD: {
  14. type: Number,
  15. default: 100
  16. },
  17. // 带有默认值的对象
  18. propE: {
  19. type: Object,
  20. // 对象或数组默认值必须从一个工厂函数获取
  21. default: function () {
  22. return { message: 'hello' }
  23. }
  24. },
  25. // 自定义验证函数
  26. propF: {
  27. validator: function (value) {
  28. // 这个值必须匹配下列字符串中的一个
  29. return ['success', 'warning', 'danger'].indexOf(value) !== -1
  30. }
  31. }
  32. }
  33. })
  • 验证自定义构造函数
  1. function Person (firstName, lastName) {
  2. this.firstName = firstName
  3. this.lastName = lastName
  4. }
  5. Vue.component('blog-post', {
  6. props: {
  7. author: Person
  8. }
  9. })

修饰符 .sync

  • 父子 props 之间单向下行绑定,即只能通过父组件改变子组件的 props 属性,反过来则不行
  • 若要在子组件中改变自身的 props 值,同时父组件同步更新,即实现双向绑定,则可使用 update:myPropName 的模式触发事件,父组件中使用 v-on 监听事件,为了方便,为这种模式提供简写 .sync
  • 带有 .sync 修饰符的 v-bind 不能和表达式一起使用,只能提供你想要绑定的属性名

子组件:

  1. <template>
  2. <div class="child">
  3. <!-- 更改父组件属性 -->
  4. <button @click="$emit('update:number', number + 1)">+1</button>
  5. </div>
  6. </template>
  7. <script>
  8. export default {
  9. name: "Child",
  10. props: ["number"],
  11. };
  12. </script>
  13. <style></style>

父组件:

  1. <template>
  2. <div class="app">
  3. {{ n }}
  4. <hr />
  5. <!-- $event 可获取子组件中 $emit 的参数-->
  6. <Child :number="n" v-on:update:number="n = $event" />
  7. <!-- 简写 <Child :number.sync="n" /> -->
  8. </div>
  9. </template>
  10. <script>
  11. import Child from "./components/child.vue";
  12. export default {
  13. name: "Father",
  14. data() {
  15. return {
  16. n: 0,
  17. };
  18. },
  19. components: { Child },
  20. };
  21. </script>
  22. <style></style>