vue – 封装组件

组件系统是 Vue 的另一个重要概念,因为它是一种抽象,允许我们使用小型、独立和通常可复用的组件构建大型应用。仔细想想,几乎任意类型的应用界面都可以抽象为一个组件树:

Vue.component('todo-item', {
  // todo-item 组件现在接受一个
  // "prop",类似于一个自定义 attribute。
  // 这个 prop 名为 todo。
  props: ['todo'],
  template: '<li>{{ todo.text }}</li>'
})
 

子单元通过 prop 接口与父单元进行了良好的解耦。

Vue 组件提供了纯自定义元素<slot name="s">所不具备的一些重要功能,最突出的是跨组件数据流、自定义事件通信以及构建工具集成。

一、 基础 组件

  1. 组件是可复用的 Vue 实例,且带有一个名字,它们与 new Vue 接收相同的选项,例如 data、computed、watch、methods 以及生命周期钩子等。仅有的例外是像 el 这样根实例特有的选项。
  2. 因为你每用一次组件,就会有一个它的新实例被创建。
  3. 一个组件的 data 选项必须是一个函数
  4. 组件注册类型:全局注册和局部注册

二、局部组件

局部注册的组件在其子组件中不可用

适用于 业务型组件

 

三、全局组件

  1. 使用

    Vue.component('my-component-name', {
    // ... 选项 ...
    })
     
  2. 基础组件的自动化全局注册

  3. 全局注册

    • webpack中使用 require.context 全局注册
    • src/main.js 中全局导入
  4. 注意: 全局注册的行为必须在根 Vue 实例 (通过 new Vue) 创建之前发生

四、组件参数

  1. 无指定类型
    props: ['title', 'likes', 'isPublished', 'commentIds', 'author']
     
  2. 每个 prop 都有指定的值类型
    props: {
        title: String,
        likes: Number,
        isPublished: Boolean,
        commentIds: Array,
        author: Object,
        callback: Function,
        contactsPromise: Promise // or any other constructor
    }
     
  3. 传入不同类型的props
  • 传入一个布尔值

    <!-- 包含该 prop 没有值的情况在内,都意味着 `true`。-->
    <blog-post is-published></blog-post>
    <!-- 即便 `false` 是静态的,我们仍然需要 `v-bind` 来告诉 Vue -->
    <!-- 这是一个 JavaScript 表达式而不是一个字符串。-->
    <blog-post v-bind:is-published="false"></blog-post>
    
     
  • 传入一个对象的所有 property

    如果你想要将一个对象的所有 property 都作为 prop 传入,你可以使用不带参数的 v-bind (取代 v-bind:prop-name)。例如,对于一个给定的对象 post:

    post: {
        id: 1,
        title: 'My Journey with Vue'
    }
    下面的模板:
    
    <blog-post v-bind="post"></blog-post>
     

Prop 验证

五、组件之间的传参

  1. 单向数据流

    所有的 prop 都使得其父子 prop 之间形成了一个单向下行绑定:父级 prop 的更新会向下流动到子组件中,但是反过来则不行。这样会防止从子组件意外变更父级组件的状态,从而导致你的应用的数据流向难以理解。

    额外的,每次父级组件发生变更时,子组件中所有的 prop 都将会刷新为最新的值。这意味着你不应该在一个子组件内部改变 prop。如果你这样做了,Vue 会在浏览器的控制台中发出警告。

    这里有两种常见的试图变更一个 prop 的情形:

    • 这个 prop 用来传递一个初始值;这个子组件接下来希望将其作为一个本地的 prop 数据来使用。在这种情况下,最好定义一个本地的 data property 并将这个 prop 用作其初始值:
    props: ['initialCounter'],
        data: function () {
                return {
                counter: this.initialCounter
            }
        }
     

    这个 prop 以一种原始的值传入且需要进行转换。在这种情况下,最好使用这个 prop 的值来定义一个计算属性:

    props: ['size'],
        computed: {
        normalizedSize: function () {
            return this.size.trim().toLowerCase()
        }
    }
     

PS:注意在 JavaScript 中对象和数组是通过引用传入的,所以对于一个数组或对象类型的 prop 来说,在子组件中改变变更这个对象或数组本身将会影响到父组件的状态。

  1. props验证
Vue.component('my-component', {
  props: {
    // 基础的类型检查 (`null` 和 `undefined` 会通过任何类型验证)
    propA: Number,
    // 多个可能的类型
    propB: [String, Number],
    // 必填的字符串
    propC: {
      type: String,
      required: true
    },
    // 带有默认值的数字
    propD: {
      type: Number,
      default: 100
    },
    // 带有默认值的对象
    propE: {
      type: Object,
      // 对象或数组默认值必须从一个工厂函数获取
      default: function () {
        return { message: 'hello' }
      }
    },
    // 自定义验证函数
    propF: {
      validator: function (value) {
        // 这个值必须匹配下列字符串中的一个
        return ['success', 'warning', 'danger'].indexOf(value) !== -1
      }
    }
  }
})
 

PS注意:那些 prop 会在一个组件实例创建之前进行验证,所以实例的 property (如 data、computed 等) 在 default 或 validator 函数中是不可用的。

  1. 类型检查

类型检查
type 可以是下列原生构造函数中的一个:

String
Number
Boolean
Array
Object
Date
Function
Symbol
 

额外的,type 还可以是一个自定义的构造函数,并且通过 instanceof 来进行检查确认。例如,给定下列现成的构造函数:

function Person (firstName, lastName) {
  this.firstName = firstName
  this.lastName = lastName
}
 

你可以使用:


Vue.component('blog-post', {
  props: {
    author: Person
  }
})
 

来验证 author prop 的值是否是通过 new Person 创建的。

  1. 非 Prop 的 Attribute
    • 替换/合并已有的 Attribute
      想象一下 的模板是这样的: <input type="date" class="form-control">
      为了给我们的日期选择器插件定制一个主题,我们可能需要像这样添加一个特别的类名:

      <bootstrap-date-input
          data-date-picker="activated"
          class="date-picker-theme-dark"
      >
      </bootstrap-date-input>
       

      在这种情况下,我们定义了两个不同的 class 的值:

      form-control,这是在组件的模板内设置好的

      date-picker-theme-dark,这是从组件的父级传入的
      对于绝大多数 attribute 来说,从外部提供给组件的值会替换掉组件内部设置好的值。所以如果传入 type=”text” 就会替换掉 type=”date” 并把它破坏!庆幸的是,class 和 style attribute 会稍微智能一些,即两边的值会被合并起来,从而得到最终的值:form-control date-picker-theme-dark。

    • 禁用 Attribute 继承

      如果你不希望组件的根元素继承 attribute,你可以在组件的选项中设置 inheritAttrs: false。例如:

      Vue.component('my-component', {
          inheritAttrs: false,
          // ...
      })
       

      这尤其适合配合实例的 $attrs property 使用,该 property 包含了传递给一个组件的 attribute 名和 attribute 值,例如:

      {
          required: true,
          placeholder: 'Enter your username'
      }
       

      有了 inheritAttrs: false 和 $attrs,你就可以手动决定这些 attribute 会被赋予哪个元素。在撰写基础组件的时候是常会用到的:

      Vue.component('base-input', {
          inheritAttrs: false,
          props: ['label', 'value'],
          template: 
              ` <label>
              {{ label }}
              <input
                  v-bind="$attrs"
                  v-bind:value="value"
                  v-on:input="$emit('input', $event.target.value)" >
              </label>`
      })
       

      注意 inheritAttrs: false 选项不会影响 style 和 class 的绑定。

      这个模式允许你在使用基础组件的时候更像是使用原始的 HTML 元素,而不会担心哪个元素是真正的根元素:

      <base-input
          v-model="username"
          required
          placeholder="Enter your username"
          >
      </base-input>
       

原创文章,作者:我心飞翔,如若转载,请注明出处:https://www.pipipi.net/12593.html

发表评论

登录后才能评论