全局组件
<my-button></my-button>  
Vue.component('my-button',{
  template:'<button>点我啊</button>'
})
let vm = new Vue({
  el:'#app'
})
局部组件
<my-button></my-button>
let vm = new Vue({
  el:'#app',
  components:{
      'MyButton':{
          template:'<button>按钮</button>'
      }
  }
});
HTML不支持自闭合的自定义元素,在DOM模板里永远不要使用自闭和组件,在HTML中也不支持MyButton的写法,所以组件调用全部使用短横线连接的方式!
https://www.w3.org/TR/html/syntax.html#void-elements
在组件中的数据必须是函数的形式
'MyButton':{
    data(){
        return {content:'按钮'}
    },
    template:'<button>{{content}}</button>'
}
<my-button button-content="按钮"></my-button>
components:{
    'MyButton':{
        props:['buttonContent'],
        template:'<button>{{buttonContent}}</button>'
    }
}
属性在组件标签上需要使用短横线命名法,在组件中声明需要采用驼峰命名法
<my-button button-content="按钮" :number="'1'"></my-button>
components:{
    'MyButton':{
        props:{
            buttonContent:String,
            arr:{
                type:Array,
                default:()=>([])
            },
            number:{
                type:Number,
                validator:(value)=>{
                    return typeof value == 'number'
                }
            },
        },
        template:'<button>{{buttonContent}} {{arr}} {{number}}</button>'
    }
}
<my-button v-bind="info"></my-button>
let vm = new Vue({
    el:'#app',
    data:{
        info:{name:'姜文',age:18}
    },
    components:{
        'MyButton':{
            props:['name','age'],
            inheritAttrs:false,
            mounted(){
                console.log(this.$attrs)
            },
            template:'<button>{{name}} {{age}} </button>'
        }
    }
});
<!-- 给组件绑定方法,在内部触发绑定的方法 -->
<my-button @click="change" msg="按钮"></my-button>
let vm = new Vue({
    el:'#app',
    methods:{
        change(){ alert('hello'); }
    },
    components:{
        'MyButton':{
            props:['msg'],
            template:`<div>
                <button @click="this.$listeners.click">{{msg}}</button>
                <button v-on="this.$listeners">{{msg}}</button>
                <button @click="$emit('click')"></button>
            </div>`
        }
    }
});
在组件的根元素上直接监听一个原生事件
<my-button @click.native="change"></my-button>
实现收缩面板功能
<collapse>
    <collapse-item title="react">内容1</collapse-item>
    <collapse-item title="vue">内容2</collapse-item>
    <collapse-item title="node">内容3</collapse-item>
</collapse>  
Vue.component('Collapse',{
    methods:{
        open(id){
            this.$children.forEach(child => {
                if(child._uid != id){
                    child.show = false;
                }
            });
        }
    },
    template:`<div class="wrap">
        <slot></slot>
    </div>`
});
Vue.component('CollapseItem',{
    props:['title'],
    data(){
        return {show:true}
    },
    methods:{
        change(){
            this.$parent.open(this._uid);
            this.show =!this.show;
        }
    },  
    template:`<div class="collapse-item" @click="change">
        <div class="title">{{title}}</div>
        <div v-show="show">
            <slot></slot>    
        </div>
    </div>`
});
v-slot:可以简写成#
<List>
  <template v-slot:banana>🍌</template>
  <template v-slot:apple>🍎</template>
      🍊
</List>  
list:{
  template:`
      <ul>
          <li><slot></slot></li>
          <li><slot name="banner"></slot></li>    
          <li><slot name="apple"></slot></li>   
      </ul>
  `
}
作用域插槽
<List #default="{val}">
  {{val}}
</List> 
list:{
  data(){
      return {arr:[1,2,3]}
  },
  template:`
      <ul>
          <li v-for="a in arr" :key="a">
              <slot :val="a">{{a}}</slot>
          </li>
      </ul>
  `
}
跨组件数据传递,主要为高阶插件/组件库提供用例
provide:{ name:'zf' },
components:{
    list:{
        inject:['name'],
        template:`<div>{{name}}</div>`
    }
}
.sync 和 v-model的使用
<div id="app">
        {{msg}}
        <tab :msg="msg" @update:msg="change"></tab>
        <tab :msg.sync="msg"></tab>
        <tab v-model="msg"></tab>
</div>
let vm = new Vue({
    el:'#app',
    data:{
        msg:'hello'
    },
    methods:{
        change(value){
            this.msg = value
        }
    },
    components:{
        tab:{
            props:['msg'],
            methods:{
                change(){
                    this.$emit('update:msg','world')
                    this.$emit('input','world');
                }
            },
            template:`<div>
                {{msg}} <button @click="change">切换</button>
            </div>`
        }
    }
})
// 在组件中可以获取组件实例
<tab :msg="msg" @update:msg="change" ref="ele"></tab>
this.$refs.ele.change()
// 放在dom上表示获取当前dom元素
<div ref="ele"></div>
this.$refs.ele.style.border="1px solid red"
// 在v-for中获取的是集合
<template v-for="a in 3">
    <tab :msg="msg" @update:msg="change" ref="ele" :key="a"></tab>
</template>
console.log(this.$refs.ele.length)
Vue.component('async', function (resolve, reject) {
    setTimeout(function () {
        resolve({
            template: '<div>异步组件</div>'
        })
    }, 1000);
});
在后期我们一般配合webpack的import语法使用