Vue-查缺补漏(2)-组件

DOM 模板解析 注意事项

Vue 组件的模板在某些情况下会受到 HTML 的限制。ul,ol,table,select这些元素,只有某些特定的元素才能出现在它们内部。li,tr,option这些元素只能出现在特定的元素内部。

1
2
3
4
5
6
7
8
<!-- <talbe>元素 内只规定只允许出现<tr>,<td>,<th>等表格元素,所有在此内的直接使用组件时会被作为无效是内容提升到外部-->
<table>
<my-component></my-component>
</table>
<!-- 这种情况下,需要使用 is 属性来挂载组件 -->
<table>
<tr is="my-component"></tr>
</table>

如果从以下来源使用的模板的话,不存在该限制

  • 字符串模板(template:’…’)
  • 单文件组件(.vue)
  • <script type="text/x-template">

使用props 传递数据

  • 选项 props的值 2 种,字符串数组、对象;这些传递的是一个静态的值

    • 字符串数组,一种简便方式
      1
      props: ['message', 'message2'];
    • 对象,可定制prop的验证方法;
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      props: {
      message: Number,
      //多个可能的类型
      message2:[String,Number],
      message3: {
      type: [String, Number],
      required: true,
      default: 100,
      // 验证函数
      validator: function(value) {
      return parseInt(value) > 100;
      }
      },
      message4: {
      type: Object,
      // 对象 和 数组默认值 必须从一个工厂函数获取
      default: function() {
      return {name: '22'}
      }
      }
      }
  • 使用v-bind,动态给Prop赋值,任何类型的值都可以传给一个Prop

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    <!-- 传入一个数字 -->
    <!-- `42`即便是静态的,当使用`v-bind`告诉 Vue,这是一个js表达式(返回number类型),而不是一个字符串 -->
    <my-component v-bind:message="42"></my-component>
    <!-- 传入一个布尔值 -->
    <!-- 包含 该 Prop ,在没有值的情况下,表示:`true` -->
    <my-component message></my-component>
    <!-- `false`是静态的,但`v-bind`告诉了 Vue,t它是一个js表达式(返回Booelean false),而不是一个字符串 -->
    <my-component v-bind:message="false"></my-component>

    <!-- 同理,传入一个对象,数字 -->
    <my-component v-bind:message="{
    name: 'jaing',
    age: 27
    }"></my-component>
    <my-component v-bind:message="['133',3334,'nihao']"></my-component>
  • Prop验证,是在组件实例创建之前进行验证,所有实例的属性在default,validator函数中是不可用的

数据流流向

props传递的数据是单向的,父组件数据变化会传递给子组件,反过来不行。

  • 2 种 改变 Prop情况
    • 父组件传递初始值进来,子组件在data内再声明一个数据,引用父组件的prop,这样就可以在自己的作用域下随意使用和修改
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      // 组件中声明了count,它在组件初始化时会获取来自父组件的initCount,之后就与父组件无关了,只用维护count,避免直接操作initCount
      Vue.component('my-component',{
      props: ['initCount'],
      template: `<div>{{ count }}</div>`,
      data: function () {
      return {
      count: this.initCount
      }
      }
      })
    • 子组件的数据依赖父组件的props传入的数据,这种情况用计算属性
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      Vue.component('my-component', {
      props: ['width'],
      template: '<div :style="style">组件内容</div>',
      computed: {
      style: function() {
      return {
      width: this.width + 'px'
      }
      }
      }
      })

自定义事件

  • 事件名称
    因为v-on事件监听器在 DOM 模板中会被自动转换为全小写(HTML 大小写不敏感),v-on:myEvent会被转换成v-on:myevent,所以导致myEvent不被监听到。
    因此,最好使用 kebab-case 的事件名

  • 自定义组件的 v-model
    具有双向绑定的v-model(本质上:语法糖)组件,需要满足以下条件:

    1
    2
    3
    4
    5
    6
    7
    8
    <!-- 绑定value值,接受value `prop` -->
    <!-- 触发input事件时,$event的值,赋给 text -->
    <my-input
    v-bind:value="text"
    v-on:input="text=$event">
    </my-input>
    <!-- 自定义组件,就可以使用v-model 指令 -->
    <my-input v-model="something"><my-input>
    • 接受一个 valueprop
    • value改变时,触发input事件
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    <my-component v-model="total"></my-component>

    // 注册组件
    Vue.component('my-component',{
    props: ['value'],
    template:'<input :value="value" @input="updateValue">',
    methods: {
    // 默认参数:DOM事件
    updateValue: function(event) {
    this.$emit('input', event.target.value);
    }
    }
    })
  • 原生事件绑定到组件
    在一个组件的根元素直接监听一个原生事件,使用v-on.native修饰符

    1
    <base-input v-on:click.native="onClick"></base-input>

构建完全透明的包裹器(扩展组件)

  • vm.$listeners,它是一个对象,包含了父作用域中的v-on(不包含.native 修饰符的)事件监听器。它可以通过v-on="$listeners"出入到 内部的子组件,从而在 父组件上跟 子组件 相同的监听器都可以工作
  • vm.$props,当前组件接受的 props 对象
  • vm.$attrs, 它是一个对象,包含了 父作用域(父组件)中的不作为prop,且可获取的特性绑定(class,style除外)。当一个组件没有声明任何prop时,这里会包含所有父作用域的绑定。并且可以通过v-bind="$attrs"传入内部的子组件。
  • 选项inhertAttrs,默认情况,父作用域的不被作为props的特性绑定,将会”回退”且作为普通 HTML 特性应用在子元素的根元素上。设置 false,取消。在通过vm.$attrs让其特性生效,且通过 v-bind 显性的绑定到非根元素。
  • extend选项,引用一个”子类”, 父组件的data,覆盖其data.
1
2
3
4
5
6
7
8
9
10
// 这边 `base-table`组件时一个完全透明的包裹器,它完全像一个普通 ivewz 中的  `table`组件
// 所有跟ivew `table`组件相同的特性和监听器`base-table`都可以使用
import { Table } from "iview";
Vue.component('base-table', {
inheritAttrs: fasle,
extends: Table, // 扩展Table组件,合并
template: `<div>
<Table v-on="$listeners" v-bind="$props"></Table>
</div>`
})

父链,子链 ref子组件索引

在组件中,可以使用vm.$parent,直接访问 该组件的父组件或父实例。父组件也可以 通过vm.$children访问 它所有的子组件.
当子组件太多时,通过vm.$children来遍历出我们需要的一个子组件实例是比较困难的,尤其是组件动态渲染时,它们的序列不固定。
使用特殊的属性ref来为子组件指定一个索引名称,在通过vm.$refs(一个对象,持有注册过ref特性的所有DOM元素和组件实例)找到该组件。
$refs只在组件渲染完后才被注册,并非响应式的,应该避免在模板中或计算 属性中使用$refs.