| 全局、局部组件
| 数据传递(props、组件通信、slot)
| props、sync双向绑定、once单次绑定
| 组件之间通信,$dispatch() 派发事件、 $broadcast() 广播事件,事件向下传导给所有后代
| slot 内容分发
| 组件是Vue的最强大功能之一,组件可以扩展html元素,封装可复用代码

全局组件

全局组件在任何组件内都可以调用,无需引用或通过component加载

main.js

    // 定义一个全局的组件
    var myComponent = Vue.extend({
        template: '<div> 组件已经渲染出来 </div>'
    })

    // 全局注册
    Vue.component('crm-component', myComponent);

    let vm = new Vue({
        ...
    }}


main.vue 子组件

    <templte>
        <div class="welcome">
            <h1>视图列表页面</h1>
            <crm-component></crm-component>            <!-- 调用 -->
        </div>
    </template>

局部组件

必须使用components对象来引用组件

<div id="appA">
    <User></User>
</div>

<script>
    import User import './user';

    var vmA = new Vue({
        el: "#appA",
        components: {        // 局部的写法
            User
        }
    })
</script>

————— 父与子组件之间的数据传递 —————

props

父组件将数据传给子组件通过props,子组件通过自定义事件$on、$emit来挂参数传递给父组件

一、props

    <div id="app">
        <!-- 这里的两个属性值通过props传到组件中 -->
        <component-parent my-name="siguang" my-age='33'></component-parent>
    </div>

    <script>
        var componentCrm = Vue.extend({
            props: ['myName', 'myAge'],
            template: '<h2>{{ myName }} {{ myAge }}</h2>'
        })

        var vm = new Vue({
            el: '#app',
            components: {
                'component-parent': componentCrm
            }
        })
    </script>

    注意: my-name="siguang" 自定义属性以“-”分割

         props: ['myName', 'myAge']        // props 定义的必须以驼峰形势


二、props动态值

    parent.vue:

        <div id="app">
            <child-component :user-name="uname"></child-component>
        </div>

        <script>
            import childComponent from 'childComponent.vue';

            export default{
                data(): {
                    return{
                        uname: 'siguang'
                    }
                },
                components:{
                    childComponent
                }
            }
        </script>


    childComponent.vue:

        <div>
            {{ userName }}        <!-- siguang -->
        </div>

        <script>
            export default{
                propos: ['userName'],
            }
        </script>


三、once 将渲染的结果缓存

    不过当组件中包含大量静态内容时,可以考虑使用 v-once 将渲染结果缓存起来

    <div id="app">
        <component-parent></component-parent>
    </div>

    <script>

        var childrenComponent = Vue.extend({
            template: '<div v-once>'+
                '<h3>这里是子组件的内容: {{ myMsg }}</3>'+
                '<p>这里输入不会影响父组件: <input type="text" v-model="myMsg" /></p>'+
                '</div>',
            data: function(){
                return {
                    myMsg: ''
                }
            },
            props: ['myMsg']
        })

        var parentComponent = Vue.extend({
            template: '<div v-once>'+
                '<p><input text="text" v-model="msg"></p>'+
                '<p>父组件的值 {{ msg }}</p>'+
                '</div>'+
                '<childen-component v-bind:my-msg.once="msg"></childen-component>',
            data: function(){
                return {
                    msg: '这里值只传给子组件一次'
                }
            },
            components: {
                'childen-component': childrenComponent
            }
        })

        var vm = new Vue({
            el: '#app',
            components: {
                'component-parent': parentComponent
            }
        })
    </script>

组件之间通信

props是单向数据流父向子组件传递数据,子向父组件传递可以通过自定义事件来处理

$on(eventName) 监听事件    、$emit(eventName) 触发事件

一、子向父组件发消息

    parent.vue: 

        <template>
            <div class="login">
                <div class="parent-box">
                    <p>显示子组件数据: {{ childrenText }}</p>
                </div>
                <children-component ref="childrenRef" v-on:showChildrenVal="childrenVal"></children-component>
            </div>
        </template>

        <script>
            import ChildrenComponent from './children.vue'
            export default{
                data(){
                    return {
                        childrenText: ''
                    }
                },
                methods:{
                    childrenVal(val){
                        this.childrenText = val;
                    }
                },
                components:{
                    ChildrenComponent
                }
            }
        </script>

    children.vue:

        <template>
            <div class="children" style="padding-top: 50px; border-top: 1px #ccc solid">
                <p><input type="text" v-model="childrenInp" id=""></p>
                <p><input type="button" @click="toParentData" value="提交到父组件中"></p>
            </div>
        </template>

        <script>
            export default{
                data(){
                    return {
                        childrenInp: ''
                    }
                },
                methods:{
                    toParentData(){
                        this.$emit("showChildrenVal", this.childrenInp);
                    }
                }
            }
        </script>


二、父向子发消息

    parent.vue:

        <template>
            <div class="login">
                <div class="parent-box">
                    <p><input type="text" name="" v-model="inputParent" ><br></p>
                    <p><input type="button" value="值传给父组件" @click="sendChildren"><br></p>
                    <p>显示子组件数据: {{ childrenText }}</p>
                </div>

                <children-component ref="childrenRef"></children-component>
            </div>
        </template>

        <script>
            import ChildrenComponent from './children.vue'
            export default{
                data(){
                    return {
                        inputParent: '',
                        childrenText: ''
                    }
                },
                methods:{
                    sendChildren(){
                        this.$refs.childrenRef.$emit('showText', this.inputParent);        // 也可以用props
                    }
                },
                components:{
                    ChildrenComponent
                }
            }
        </script>


    children.vue:

        <template>
            <div class="children" style="padding-top: 50px; border-top: 1px #ccc solid">
                这里是父组件传递的值: {{transmitVal}}
            </div>
        </template>

        <script>
            export default{
                created(){
                    this.$on('showText', function(val){
                        this.transmitVal = val;
                    })
                },
                data(){
                    return {
                        transmitVal: ''
                    }
                }
            }
        </script>


三、v-ref 直接访问到组件

    <div id="app">
        <span ref="msg"> hello </span>
        <span ref="other-msg"> world </span>
    </div>

    <script>
        var vm = new Vue({
            el: "#app",
            data: {
                someProp: 'idName',
                otherProp: 'prop'
            }
        })

        console.log(vm.$refs.msg.textContent);        // hello
        console.log(vm.$refs.otherMsg.textContent);    // world
    </script>

slot 分发内容

parent.vue:
    <template>
        <div class="login">
            <children-component>
                <h1 slot="header">这里可能是一个页面标题</h1>
                <div class="tag">
                    这里是没有定义slot名称走的默认的slot
                    <div class="tag-til">标题</div>
                    <div class="tag-content">内容部分</div>
                </div>
            </children-component>
        </div>
    </template>

children.vue:
    <template>
        <div class="children">
            <slot name="header"></slot>
            <slot></slot>
        </div>
    </template>

组件化的css

可以通过scoped属性来控制样式是否是只在当前组件下使用

<style>
    /* 全局下的样式 */
</style>

<style scoped>
    /* 当前组件下使用的样式 */
</style>