vue 组件

Vue.component('my-button', {
    template: '<button @click="count ++">you clicked {{count}} times</button>',
    data: function () {    // data一定要是函数的形式,否则自定义组件在复用时会影响到它的所有实例(默认:自定义组件在复用时每个实例是独立的)
        return {
            count: 0
        }
    }
})

组件是可复用的 Vue 实例,所以它们与 new Vue 接收相同的选项,例如 data、props、computedwatchmethods 以及生命周期钩子等。仅有的例外是像 el 这样根实例特有的选项。

如果想要全局使用该自定义组件,就要进行全局注册。(自定义组件命名:字母全小写且必须包含一个连字符)

<div id="components-demo">
  <my-button></my-button>
</div>

new Vue({ el: '#components-demo' })

局部使用

import ComponentA from './ComponentA.vue'

export default {
  components: {
    ComponentA
  },
  // ...
}

props: 父组件向子组件传递数据

  • 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
  }
})
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) {
        // 这个值必须匹配下列字符串中的一个(当 prop 验证失败的时候,(开发环境构建版本的) Vue 将会产生一个控制台的警告)
        return ['success', 'warning', 'danger'].indexOf(value) !== -1
      }
    }
  }

向子组件传入非props属性:

首先,组件可以接受任意的特性,而这些特性会被添加到这个组件的根元素上

<bootstrap-date-input> 组件的模板是这样的:

<input type="date" class="form-control">

为了定制一个主题(颜色):

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

对于绝大多数特性来说,从外部提供给组件的值会替换掉组件内部设置好的值。所以如果传入 type="text" 就会替换掉 type="date" 。庆幸的是,classstyle 特性会稍微智能一些,即两边的值会被合并起来,从而得到最终的值为:form-control date-picker-theme-dark

如果你希望组件的根元素继承特性,你可以在组件的选项中设置 inheritAttrs: false(选项不会影响 styleclass 的绑定)

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>
  `
})

自定义组件事件绑定(通过调用内建的 $emit 方法,传入事件名称来触发一个事件,通过$emit的第二个参数来抛出一个特定的值)

Vue.component('my-button', {
    template: <button @click="$emit('text-larger', 0.12)">字体放大</button>
)

在父组件中,监听这个事件的时候,我们可以通过 $event 访问到被抛出的这个值。

<my-button
    ......
    v-on:text-larger="postFontSize += $event"
></my-button>

或者事件处理函数是一个方法

<my-button
......
v-on:text-larger="onEnlargeText"
></my-button>

methods: { onEnlargeText:
function (enlargeAmount) { this.postFontSize += enlargeAmount } }

自定义输入框

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

自定义单选框、复选框的v-model

Vue.component('base-checkbox', {
  model: {
    prop: 'checked',
    event: 'change'
  },
  props: {
    checked: Boolean
  },
  template: `
    <input
      type="checkbox"
      v-bind:checked="checked"
      v-on:change="$emit('change', $event.target.checked)"
    >
  `
})

使用这个组件:

<base-checkbox v-model="lovingVue"></base-checkbox>

 

将原生事件绑定到组件上(使用 v-on.native 修饰符)

Vue.component('base-input', {
  inheritAttrs: false,
  props: ['label', 'value'],
  computed: {
    inputListeners: function () {
      var vm = this
      // `Object.assign` 将所有的对象合并为一个新对象
      return Object.assign({},
        // 我们从父级添加所有的监听器
        this.$listeners,
        // 然后我们添加自定义监听器,
        // 或覆写一些监听器的行为
        {
          // 这里确保组件配合 `v-model` 的工作
          input: function (event) {
            vm.$emit('input', event.target.value)
          }
        }
      )
    }
  },
  template: `
    <label>
      {{ label }}
      <input
        v-bind="$attrs"
        v-bind:value="value"
        v-on="inputListeners"
      >
    </label>
  `
})
<base-input v-on:focus.native="onFocus"></base-input>

 

插槽(在vue 2.6中,为具名插槽和作用域插槽引入了一个新的统一的语法——v-slot,取代了以往的slot及slot-scope)

具名插槽(一个不带 name<slot> 出口会带有隐含的名字“default”)

<div class="container">
  <header>
    <slot name="header"></slot>
  </header>
  <main>
    <slot></slot>
  </main>
  <footer>
    <slot name="footer"></slot>
  </footer>
</div>

在向具名插槽提供内容的时候,我们可以在一个 <template> 元素上使用 v-slot 指令,并以 v-slot 的参数的形式提供其名称.

<base-layout>
  <template v-slot:header>
    <h1>Here might be a page title</h1>
  </template>

  <p>A paragraph for the main content.</p>
  <p>And another one.</p>

  <template v-slot:footer>
    <p>Here's some contact info</p>
  </template>
</base-layout>

现在 <template> 元素中的所有内容都将会被传入相应的插槽。任何没有被包裹在带有 v-slot<template> 中的内容都会被视为默认插槽的内容。

作用域插槽

定义<current-user> 组件(user.lastName作为后备内容)

 <span>
    <slot :user="user">{{ user.lastName }}</slot>
  </span>

export default {
  data () {
    return {
      user: {
        firstName: 'hi',
        lastName: 'Black'
      }
    }
  }
}

在父组件中,如果<current-user></current-user>标签内写了内容,就会代替后备内容。

<current-user>
    <template v-slot:default="slotProps">
      {{ slotProps.user.firstName }}
    </template>
 </current-user>

注意:这里在自定义组件(子组件)中需要绑定user,以便在父组件中可以拿到子组件中user的值。同时在父组件中调用时需要使用v-slot进行绑定。

如果子组件只有默认插槽,可将组件的标签当作插槽模板来使用。

<current-user v-slot:default="slotProps">
  {{ slotProps.user.firstName }}
</current-user>

或者更简单:

<current-user v-slot="slotProps">
  {{ slotProps.user.firstName }}
</current-user>

如果存在多个插槽,必要要使用完整的基于 <template> 的语法。

<current-user>
  <template v-slot:default="slotProps">
    {{ slotProps.user.firstName }}
  </template>

  <template v-slot:other="otherSlotProps">
    ...
  </template>
</current-user>

v-slot也有缩写,即把参数之前的所有内容 (v-slot:) 替换为字符 #。例如 v-slot:header 可以被重写为 #header。但该缩写只用在具名插槽中。

<-- 正确 -->
<current-user #default="{ user }">
  {{ user.firstName }}
</current-user>

<-- 错误 -->
<current-user #="{ user }">
  {{ user.firstName }}
</current-user>

 

动态组件

有的时候,需要在不同组件之间进行动态切换。通过以下方式实现:

<component v-bind:is="currentTabComponent"></component>

 动态组件在每次切换时,都是重建实例,如果想要在第一次被创建的时候就缓存下来,可以使用<keep-alive> 元素。

<keep-alive>
  <component v-bind:is="currentTabComponent"></component>
</keep-alive>

 

posted @ 2019-09-23 09:25  cecelia  阅读(96)  评论(0)    收藏  举报