Vue组件

测试代码

创键组件

两种方式:
方法一:使用Vue.extend({})

var component = Vue.extend({
  template: '
component
' }); // 里面还可以添加其他的属性

方法二:使用字面量

 var component = {
   template: '
component
' }

注册组件

全局注册
语法:

Vue.component('my-component', {
  // 选项
})

示例:

// 创建组件
var component = {template: '
component
'} // 全局注册组件 Vue.component('my-component', component);

局部注册

// 创建组件
var component = {template: '
component
'} // 在 Vue组件实例内注册component组件,该组件只能在该实例中使用 var vm = new Vue({ el: '#app', components: { 'mycomponent ': component , } })

注意点:

  • HTML 特性是不区分大小写的。所以,当使用的不是字符串模版,camelCased (驼峰式) 命名的 prop 需要转换为相对应的 kebab-case (短横线隔开式) 命名:
Vue.component('child', {
  // camelCase in JavaScript
  props: ['myMessage'],      // 这里使用的是驼峰式命名
  template: '{{ myMessage }}'
})
// 在下面的HTML文件中引用时,需要改为kebab-case的形式,也就是短横线隔开

如果你使用字符串模版,则没有这些限制。

注意(谨记):在HTML中,属性是不区分大小写的,例如:class、Class或CLASS都是表示class,因此,当在Vue中使用props向子组件传递数据时,如果props是驼峰式命名,那么在HTML文件中使用时,需要修改为kebab-case(短横线隔开式或称为烤肉串)的形式,否则,Vue将会无法解析

使用props传递数据

Vue.component('child', {
  // 声明 props
  props: ['message'],
  // 就像 data 一样,prop 可以用在模板内
  // 同样也可以在 vm 实例中像“this.message”这样使用
  template: '{{ message }}'
})
// 通过下面这种方式传递数据

动态prop

将父组件的数据通过v-bind绑定到子组件上,与绑定HTML特性是一样的;每当父组件的数据变化都会反映到子组件上


字面量语法 VS 动态语法

初学者常犯的一个错误是使用字面量语法传递数值:



因为它是一个字面 prop,它的值是字符串 "1" 而不是 number。如果想传递一个实际的 number,需要使用 v-bind,从而让它的值被当作 JavaScript 表达式计算:



通过v-bind:some-props="1"传递的是一个number,而通过some-prop="1"传递的是一个 字符串

props数据校验

Vue.component("example", {
  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 value > 10
      }
    }
  }
});

注意:props会在组件实例创建之前进行校验,所以在default、validator函数里,诸如:data, computedmethods等实例属性都无法使用

非props特性传递

在Vue中,在大多数情况下,传递给组件的值会覆盖组件本身就设定的值,例如传递type=large会覆盖组件上的type=small,且有可能破坏该组件,但是,对于class和style特性在传递时,不会发生覆盖,只会合并,假如组件上class=one,又传递class=two,则最终组件的class= one two

原生事件监听

通过在事件上添加.native可以增加对原生事件的监听,如下:
`

.sync修饰符

一般情况下,子组件对props的修改无法更新到父组件中,但是在2.3.0之后的版本中添加了.sync修饰符,可以在子组件上更新props,同时同步到父组件上,如下:

上面这段代码会被扩展为,如下代码:

如果子组件需要更新,则按如下方式即可:
this.$emit('update:foo', newValue);

单向数据流

prop绑定数据是单向的,当父组件的属性变化时,将传导给子组件,但是不会反过来。这是为了防止子组件无意修改了父组件的状态——这会让应用的数据流难以理解。

另外,每次父组件更新时,子组件的所有 prop 都会更新为最新值。这意味着你不应该在子组件内部改变 prop。如果你这么做了,Vue 会在控制台给出警告

使用插槽分发内容(slot)

单个插槽

注意几点:

  1. 当子组件没有slot插槽时,父组件调用子组件时,包含的内容都会丢失
  2. 当父组件调用子组件没有包含内容时,显示slot中的内容

示例1:子组件没有slot插槽时

我是父组件的标题

这是一些初始内容

这是更多的初始内容

// 子组件child的模板,在该组件中没有slot,因此父组件调用子组件时包含的内容不会显示出来 Vue.component("c-child", { template: "#child" }); new Vue({ el: "#app-1" });

上面代码输出结果如下:


Vue组件_第1张图片
没有slot的显示效果

当在child组件中添加slot,修改为如下代码:


显示结果如下:

Vue组件_第2张图片
添加slot后,父组件调用子组件时包含的内容显示出来了

示例2:当父组件调用子组件时,没有包含内容,则显示slot中的内容

我是父组件的标题

// 子组件child的模板,在该组件中没有slot,因此父组件调用子组件时包含的内容不会显示出来 Vue.component("c-child", { template: "#child" }); new Vue({ el: "#app-1" });

如下:


Vue组件_第3张图片
显示slot内容

具名插槽

元素可以用一个特殊的属性 name 来配置如何分发内容。多个插槽可以有不同的名字。具名插槽将匹配内容片段中有对应 slot 特性的元素。

也就是说,在子组件中可以为slot通过name属性定义名字,然后在父组件调用子组件的时候,可以通过slot="header"来为子组件中name="header"的slot指定内容,假如指定的name 在子组件中没有找到,那么该内容将会被抛弃

// 子组件模板
// 父组件

这里可能是一个页面标题

主要内容的一个段落。

另一个主要段落。

这里有一些联系信息

最终的渲染结果如下:

这里可能是一个页面标题

主要内容的一个段落。

另一个主要段落。

这里有一些联系信息

该特性非常有用

作用域插槽

作用域插槽是一种特殊类型的插槽,用作一个替换已渲染元素的 (能被传递数据的) 可重用模板。
在子组件中,只需将数据传递到插槽,就像你将 props 传递给组件一样:

在父级中,具有特殊属性 scope 的