组件

组件 (Component) 是 Vue.js 最强大的功能之一。组件可以扩展 HTML 元素,封装可重用的代码。在较高层面上,组件是自定义元素.

注册

全局注册

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


<script>
    //注册全局组件
    Vue.compnent('my-component',{
        template:'<div><input type="button" value="弹出" @click="tanshu"/></div>'  ,  
        data:function(){
            return{
                msg1:'helloworld'
            };
        },
        methods:{
            tanchu:function(){
                alert(this.msg1);
            }
        }
    });
    //初始化根实例
         var vm=new Vue({
            el:'#app',
            date:{
                msg:'hello world!',
            },
        });
</script>  

局部注册

不必在全局注册每个组件。通过使用组件实例选项注册,可以使组件仅在另一个实例/组件的作用域中可用:

//初始化根实例
 <div id="app1">
    <my-component1></my-component1>
</div>

<script>
        
    //局部注册
    var zujian={
        template:'<div><input type="button" value="tanchu" @click="tanshu"/></div>'  ,  
        data:function(){
            return{
                msg1:'helloworld'
            };
        },
        methods:{
            tanchu:function(){
                alert(this.msg1);
            }
        }
    });



    //初始化根实例
    var vm=new Vue({
        el:'#app1',
        date:{
            msg:'hello world!',   
        },
        components:{
            'my-component1':zujian
        }
       
    });
</script>  

配置组件

像这些元素 <ul>,<ol>,<table>,<select> 限制了能被它包裹的元素,而一些像 <option> 这样的元素只能出现在某些其它元素内部。在自定义组件中使用这些受限制的元素时会导致一些问题,例如:

<table>
  <my-row>...</my-row>
</table>  

自定义组件 <my-row> 被认为是无效的内容,因此在渲染的时候会导致错误。变通的方案是使用特殊的 is 属性:

<table>
  <tr is="my-row"></tr>
</table>  

应当注意,如果您使用来自以下来源之一的字符串模板,这些限制将不适用:

  • <script type="text/x-template">

  • JavaScript 内联模板字符串

  • .vue 组件

data必须是函数

<div id="app">
    <table>
        <tr is="component-tr"></tr>
        <tr is="component-tr"></tr>
        <tr is="component-tr"></tr>
        <tr is="component-tr"></tr>
    </table>
</div>
<script type="text/x-template" id="tpl1">
    <tr>
        <td>{{msg}}</td><td>2</td><td>3</td><td>4</td>
    </tr>
</script>
<script>

    Vue.compnentIr={
        template:'#tpl1',
        data:function{
            return{
                msg:'helloworld'
            }
        }
    };

    var vm=new Vue({
        el:'#app1',

    });
 
</script>  

组件通讯

组件 A 在它的模板中使用了组件 B。它们之间必然需要相互通信:父组件要给子组件传递数据,子组件需要将它内部发生的事情告知给父组件。

父子通讯

在 Vue 中,父子组件的关系可以总结为 props down, events up。父组件通过 props 向下传递数据给子组件,子组件通过 events 给父组件发送消息。

prop

要让子组件使用父组件的数据,我们需要通过子组件的 props 选项。

Vue.component('child', {
  // 声明 props
  props: ['message'],
  // 就像 data 一样,prop 可以用在模板内
  // 同样也可以在 vm 实例中像“this.message”这样使用
  template: '<span>{{ message }}</span>'
})    

<child message="hello!"></child>
camelCased vs kebab-case

HTML 特性是不区分大小写的。所以,当使用的不是字符串模板,camelCased (驼峰式) 命名的 prop 需要转换为相对应的 kebab-case (短横线隔开式) 命名:

Vue.component('child', {
  // camelCase in JavaScript
  props: ['myMessage'],
  template: '<span>{{ myMessage }}</span>'
})  


<!-- kebab-case in HTML -->
<child my-message="hello!"></child>  
动态prop

要动态地绑定父组件的数据到子模板的 props,与绑定到任何普通的HTML特性相类似,就是用 v-bind。

<div>
  <input v-model="parentMsg">
  <br>
  <child v-bind:my-message="parentMsg"></child>
</div>  

子父传递数据 (emit)

每个 Vue 实例都实现了事件接口 (Events interface),即:

  • 使用 $on(eventName) 监听事件

  • 使用 $emit(eventName) 触发事件

<div id="app">
   <tk v-bind:my-message="msg"></tk>
   <tk msg="helloworld2" v-on:jieshou="jieshoufn"></tk>
   
</div>
<script type="text/x-template" id="tkTpl">
    <div>
        <input type="button" @click="alertMsg" value="弹框"/>
    </div>
</script>
<script>

    var tkTpl={
        template:'#tkTpl',
        props:['myMessage'],
        methods:{
           alertMsg:function(){
                alert(this.myMessage);

                this.$emit("jieshou","abc","def");
            }
        }
    };

    var vm=new Vue({
        el:'#app',
        compnents:{
            tk:tkTpl
        },
        data:{
            msg:"hello vue"
        },
        methods:{
            jieshoufn:function(){
                alert(2);
            }
        }
    });
 
</script>  

非父子组件通信

有时候两个组件也需要通信 (非父子关系)。在简单的场景下,可以使用一个空的 Vue 实例作为中央事件总线:

var bus = new Vue()  

// 触发组件 A 中的事件
bus.$emit('id-selected', 1)  

// 在组件 B 创建的钩子中监听事件
bus.$on('id-selected', function (id) {
  // ...
})      
<div id="app">
   <tk v-bind:my-message="msg"></tk>
   <panel-tpl></panel-tpl>
</div>
<script type="text/x-template" id="tkTpl">
    <div>
        <input type="button" @click="alertMsg" value="弹框"/>
    </div>
</script>
<script>
    var bus=new Vue();

    var tkTpl={
        template:'#tkTpl',
        props:['myMessage'],
        methods:{
           alertMsg:function(){
                bus.$enit("passid",1,2);
            }
        }
    };

    var panelTpl={
        template='<div>{{id}}</div>',
        data:function(){
            return{
                id:0
            };
        },
        mounted:function(){
            var that=this;
            bus.$on("passid",function(arg1,arg2){
                this.id=arg1+arg2;
            });
        }
    }

    var vm=new Vue({
        el:'#app',
        compnents:{
            "tk":tkTpl,
        },
        data:{
            msg:"hello vue"
        },
    });
 
</script>
## 使用slot分发内容  
注意两点:  

1.<app> 组件不知道它会收到什么内容。  这是由使用 <app> 的父组件决定的。  

2.<app> 组件很可能有它自己的模板。

<style>

    .box{
        margin: 10px;
        width: 150px;
        border: 1px solid #ccc;
    }
    .box-header, .box-footer{
        height: 30px;
        background: sandybrown;
    }
    .box-body{
        min-height: 100px;
    }
</style>

<body>

<div class="exp">
    <box>
        <h2 slot="title">Slot内容分发<h2>
        <p>为了让组件可以组合,我们需要一种方式来混合父组件的内容与子组件自己的模板。这个过程被称为 内容分发 (或 “transclusion” 如果你熟悉 Angular)。Vue.js 实现了一个内容分发 API,参照了当前 Web 组件规范草案,使用特殊的 <slot> 元素作为原始内容的插槽。</p>
        <p slot="foot">分发完成</p>
    </box>
</div>

<script type="text/x-template" id="tmp">
    <div class="box">
        <div class="box-header"><slot name="title"></slot></div>
        <div class="box-body">
            <slot></slot>
        </div>
        <div class="box-footer"><slot name="foot"></slot>
        </div>
    </div>
</script>
<script>
    var box={
        template:"#tmp",
    }

    new Vue({
        el:'.exp',
        components:{
            "bilibili":box
        }
    })
</script>

</body>


哈希
744 声望8 粉丝