Vue 最强大的功能之一就是组件(Component)!
组件可以扩展 HTML 元素,封装可重用的代码,方便开发者更灵活的构建大型的前端项目。

一、定义全局组件

全局组件定义格式:Vue.component(tagName, options),下面的程序我们注册一个全局组件,并使用<helloWorld></helloWorld>的标签进行引用:

<template>
  <div id="hello">
      <helloWorld></helloWorld>
  </div>
</template>
<script>
  import Vue from "vue";
  Vue.component('helloWorld',{
    template:'<h2>自定义全局组件:helloWorld</h2>'
  })
  export default {
    name: 'hello'
  }
</script>

二、定义局部组件

我们也可以在实例中注册局部组件,只能在实例中通过components:{ }属性注入使用:

<template>
  <div id="hello">
      <helloWorld></helloWorld>
  </div>
</template>
<script>
  var Child = {
    template: '<h3>自定义局部组件:helloWorld</h3>'
  }
  export default {
    name: 'hello',
    components: {
      'helloWorld': Child
    }
  }
</script>

三、Prop属性使用

1、常规使用方式:

prop 是父组件用来传递数据的一个自定义属性,子组件需要显式地用 props 选项声明 “prop”。下面的实例中,我们在组件内部使用 props: [‘msg’] 来引入msg变量,并在组件内部使用:

<template>
  <div id="hello">
      <helloWorld msg="hello World 12345!!"></helloWorld>
    <helloWorld2></helloWorld2>
  </div>
</template>
<script>
  import Vue from "vue";
  Vue.component('helloWorld',{
    props: ['msg'],
    template:'<h2>自定义全局组件:{{msg}}</h2>'
  })
  export default {
    name: 'hello'
  }
</script>
2、动态绑定方式:

除了上面的props属性使用方式,我们还可以将props属性绑定到一个动态变量中,下面程序定义一个hello_World的变量将其绑定到props:msg属性中,并定义了一个表单input元素,用于手动修改输入的数据:

<template>
  <div id="hello">
  	  <input v-model="hello_World">
      <br>
      <helloWorld v-bind:msg="hello_World"></helloWorld>
  </div>
</template>
<script>
  import Vue from "vue";
  Vue.component('helloWorld',{
    props: ['msg'],
    template:'<h2>自定义全局组件:{{msg}}</h2>'
  })
  export default {
    name: 'hello',
    data(){
      return{
        hello_World:'wx:594218572'
      }
    }
  }
</script>

运行效果:

3、数组属性绑定:

在这个实例中,我们结合v-for和组件实现数组方式的模板调用:

<template>
  <div id="hello">
      <helloWorld v-for = 'item in books'  v-bind:msg = "item"></helloWorld>
  </div>
</template>
<script>
  import Vue from "vue";
  Vue.component('helloWorld',{
    props: ['msg'],
    template:'<h2>自定义全局组件:{{msg.book}}</h2>'
  })
  export default {
    name: 'hello',
    data(){
      return{
        books:[
          { book: 'Java编程思想' },
          { book: 'Vue教程学习' },
          { book: 'JavaScript高手' }
        ]
      }
    }
  }
</script>

另外,prop 属于单向绑定:父组件的属性变化时,会传递给子组件,反之不会。

4、Prop验证:

组件可以指定 props 的验证要求,下面我们对msg进行Number类型验证:

<template>
  <div id="hello">
    <helloWorld v-bind:msg="hello_World"></helloWorld>
  </div>
</template>
<script>
  import Vue from "vue";
  Vue.component('helloWorld',{
    props: {
      msg:Number
    },
    template:'<h2>自定义全局组件:{{msg}}</h2>'
  })
  export default {
    name: 'hello',
    data(){
      return{
        hello_World:'wx:594218572'
      }
    }
  }
</script>

由于 wx:594218572 不是Number类型,所以控制台抛出一个异常信息:


此外,还可以进行以下的方式验证:

// 多个可能的类型:
    msg: [Number,String],
    // 必填内容校验 + 默认值:
    msg2: {
      type: Number,
      required: true,
      default: 100
    },
    //自定义验证:
    msg3: {
      validator: function (value) {
        if(value == '0')
        	return false;
        return true;
      }
    }

type 可以是以下类型的原生构造器:

String
Number
Boolean
Array
Object
Date
Function
Symbol
(type 也可以使用 instanceof 检测一个自定义构造器)

四、自定义事件

由于prop 属于单向绑定,如果我们需要子组件要把数据传递回去,需要使用自定义事件,直接使用 v-on 绑定我们自定义的事件, 子组件使用 $emit 触发父组件的自定义事件,以下实例子组件和外部完全解耦,它只是触发一个父组件关心的内部事件:

<template>
  <div id="hello">
    <h1>{{total}}</h1>
    <helloWorld v-on:addition="hello_World"></helloWorld>
  </div>
</template>
<script>
  import Vue from "vue";
  Vue.component('helloWorld',{
    template: '<button v-on:click="counter">{{ count }}</button>',
    data: function () {
      return {
        count : 0
      }
    },
    methods:{
      counter:function () {
        this.count += 1
        this.$emit('addition')
      }
    }
  })
  export default {
    name: 'hello',
    data(){
      return{
        total:0
      }
    },
    methods:{
      hello_World:function () {
        this.total += 1;
      }
    }
  }
</script>

以上的程序执行顺序:

1、执行子组件 v-on:click="counter" 的逻辑;
	2、执行子组件内 counter:function 的函数,然后通过this.$emit('addition')触发父组件中的 v-on:addition 自定义事件;
	3、执行父组件自定义事件 v-on:addition 所指向的 hello_World: function函数,进行加法计算;
	(父、子组件内的加法是两个独立函数)

另外,如果要在组件的根元素上监听原生事件,使用 .native 修饰 v-on :

<helloWorld v-on:click.native="doSomeThing"></helloWorld>

END.