美文网首页
Vue(五、组件)

Vue(五、组件)

作者: 小懒豆 | 来源:发表于2018-07-03 19:16 被阅读11次

五、组件

组件基础

  • data 必须是一个函数,因此每个实例可以维护一份被返回对象的独立的拷贝
data: function () {
  return {
    count: 0
  }
}
  • 通过 Vue.component 全局注册
  • 局部注册,components 选项中定义你想要使用的组件
  • 通过 Prop 向子组件传递数据
  • 通过事件向父级组件发送消息

在组件上使用 v-model,自定义事件也可以用于创建支持 v-model 的自定义输入组件。记住:

<input v-model="searchText">

等价于:

<input
  v-bind:value="searchText"
  v-on:input="searchText = $event.target.value"
>

当用在组件上时,v-model 则会这样:

<custom-input
  v-bind:value="searchText"
  v-on:input="searchText = $event"
></custom-input>

为了让它正常工作,这个组件内的 <input> 必须:
将其 value 特性绑定到一个名叫 value 的 prop 上
在其 input 事件被触发时,将新的值通过自定义的 input 事件抛出
写成代码之后是这样的:

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

现在 v-model 就应该可以在这个组件上完美地工作起来了:

<custom-input v-model="searchText"></custom-input>

基础组件的自动化全局注册

幸好如果你使用了 webpack (或在内部使用了 webpack 的 Vue CLI 3+),那么就可以使用 require.context 只全局注册这些非常通用的基础组件。这里有一份可以让你在应用入口文件 (比如 src/main.js) 中全局导入基础组件的示例代码,记住全局注册的行为必须在根 Vue 实例 (通过 new Vue) 创建之前发生

import Vue from 'vue'
import upperFirst from 'lodash/upperFirst'
import camelCase from 'lodash/camelCase'

const requireComponent = require.context(
 // 其组件目录的相对路径
 './components',
 // 是否查询其子目录
 false,
 // 匹配基础组件文件名的正则表达式
 /Base[A-Z]\w+\.(vue|js)$/
)

requireComponent.keys().forEach(fileName => {
 // 获取组件配置
 const componentConfig = requireComponent(fileName)

 // 获取组件的 PascalCase 命名
 const componentName = upperFirst(
 camelCase(
 // 剥去文件名开头的 `'./` 和结尾的扩展名
 fileName.replace(/^\.\/(.*)\.\w+$/, '$1')
 )
 )

 // 全局注册组件
 Vue.component(
 componentName,
 // 如果这个组件选项是通过 `export default` 导出的,
 // 那么就会优先使用 `.default`,
 // 否则回退到使用模块的根。
 componentConfig.default || componentConfig
 )
})

Prop

传入一个对象的所有属性

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

post: {
  id: 1,
  title: 'My Journey with Vue'
}

下面的模板:

<blog-post v-bind="post"></blog-post>

等价于:

<blog-post
  v-bind:id="post.id"
  v-bind:title="post.title"
></blog-post>

Prop 验证

Vue.component('my-component', {
  props: {
    // 基础的类型检查 (`null` 匹配任何类型)
    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
      }
    }
  }
})

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

String
Number
Boolean
Array
Object
Date
Function
Symbol

插槽

  • 将 <slot> 元素作为承载分发内容的出口。

具名插槽

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


<base-layout>
  <template 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 slot="footer">
    <p>Here's some contact info</p>
  </template>
</base-layout>


<base-layout>
  <h1 slot="header">Here might be a page title</h1>

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

  <p slot="footer">Here's some contact info</p>
</base-layout>

插槽的默认内容

<button type="submit">
  <slot>Submit</slot>
</button>

编译作用域

  • 父组件模板的所有东西都会在父级作用域内编译;子组件模板的所有东西都会在子级作用域内编译。

作用域插槽

<todo-list v-bind:todos="todos">
  <template slot-scope="{ todo }">
    <span v-if="todo.isComplete">✓</span>
    {{ todo.text }}
  </template>
</todo-list>

相关文章

网友评论

      本文标题:Vue(五、组件)

      本文链接:https://www.haomeiwen.com/subject/tftjuftx.html