父组件模板的内容在父组件做用域内编译;子组件模板的内容在子组件做用域内编译。
父子组件的编译相互独立,编译时只能使用各自做用域中的属性和方法,例如,你不能够在父组件模板内,将一个指令绑定到子组件的属性或方法上。若是这么作控制台会报一个属性未定义的错误。javascript
若是想要绑定一个指令以便控制子组件的行为,那么你能够在子组件的模板内,将一个指令绑定到子组件的属性或方法上;或者在父组件的模板内,将指令绑定到父组件的属性或方法上。java
new Vue({ el: '#app-2', data: { makeChildShow: true }, components: { "component-2-1": { template: '<span>I am an sub component.</span>', data: function () { return { childIsShow: true } } }, "component-2-2": { template: '<span v-show="childIsShow">I am an sub component.</span>', data: function () { return { childIsShow: true } } } } })
<div id="app-2"> <ul> <li>绑定到子组件属性:<component-2-1 v-show="childIsShow"></component-2-1></li> <li>绑定到父组件属性:<component-2-1 v-show="makeChildShow"></component-2-1></li> <li>在子组件模板内将指令绑定到子组件属性:<component-2-2></component-2-2></li> </ul> </div>
列表第一项,因为父组件找不到属性childIsShow
,将不会显示。es6
将父组件的内容插入子组件模板的方式,咱们称为内容分发。
默认状况下,在子组件中插入的父组件内容是不显示的。app
new Vue({ el: '#app-1', data: { message: 'I come from parent.' }, components: { "component-1": { template: '<p>I am an sub component.</p>', } } })
<div id="app-1" class="demo"> <component-1> {{ message }} </component-1> </div>
内容分发失败,message
不会显示。spa
若是想使用内容分发,将父组件内容插入到子组件的模板中,必须在子组件的模板内标记一个<slot>备选内容</slot>
,父组件将找到这个<slot>备选内容</slot>
标记,并将本身的内容替换<slot>备选内容</slot>
。
若是父组件没有待分发的内容,备选内容
成为最终渲染的结果。3d
new Vue({ el: '#app-3', components: { "component-3": { template: '\ <ul>\ <li>子组件内容</li>\ <li>子组件内容</li>\ <slot><li>插口备选内容</li></slot>\ <li>子组件内容</li>\ <li>子组件内容</li>\ </ul>' } } })
<div id="app-3"> <h5>父组件标题</h5> <component-3> <li>父组件插入内容</li> </component-3> </div>
单插口模式作内容分发,只能一股脑把套入子模板的内容插入到有<slot></slot>
标记的地方。
而具名插口在内容和slot
上都作上标记,对应的内容只能分发到对应的slot
上。
标记内容用slot="tag"
; 标记slot
用 <slot name="tag">
code
new Vue({ el: '#app-4', components: { "component-4": { template: '\ <div>\ <header>\ <slot name="header"></slot>\ </header>\ <article>\ <slot></slot>\ </article>\ <footer>\ <slot name="footer"></slot>\ </footer>\ <section><slot></slot></section>\ </div>' } } })
<div id="app-4"> <component-4> <h5 slot="header">我来组成头部</h5> <p>没被标记的slot都我插</p> <div slot="footer">我来组成腿部</div> </component-4> </div>
以上定义了两个个不具名的插口,虽然这里显示正确,可是控制台报错,说定义重复的默认插口会有不预期的错误component
根据具名插口,再来看个组件做用域的例子对象
new Vue({ el: '#app-7', methods: { parentMethod: function () { console.log("It is the parent's method"); } }, components:{ "component-7":{ methods:{ childMethod: function(){ console.log("It is the child's method") } }, template:"\ <button>\ <slot name='first'></slot>\ <span @click='childMethod'>子组件模板定义部分①|</span>\ <slot name='second'></slot>\ <span @click='childMethod'>子组件模板定义部分②</span>\ </button>" } } })
<div id="app-7"> <component-7> <span slot="first" @click="parentMethod">内容分发部分①|</span> <span slot="second" @click="parentMethod">内容分发部分②|</span> </component-7> </div>
内容分发部分属于父组件做用域,所以点击按钮的内容分发部分,会调用父组件方法,输出"It is the parent's method"
。
子组件模板定义属于子组件做用域,点击这个部分,会调用子组件方法,输出"It is the child's method"
blog
在内容分发的过程当中,父组件分发的内容可使用定义在子组件模板<slot>
上的属性(即插口做用域上定义的属性)。如<slot slotval="值"></slot>
,在父组件分发内容上,能够经过slot-scope="obj"
获取到全部在插口上定义的属性,经过{{obj.slotval}}
就能够在slot-scope
内部使用这个数据。
特殊的,在<template>
标签中使用slot-scope
,<template>
自身是不会在页面上显示,只起到传递数据媒介的做用。
new Vue({ el: '#app-5', components: { "component-5":{ template: '<div class="child">\ <slot slotvala="a、来自插口做用域上的数据" slotvalb="b、来自插口做用域上的数据"></slot>\ </div>' } } })
<div id="app-5"> <component-5> <!--这里能够是其余标签,但会被渲染到页面,如<div slot-scope="">--> <template slot-scope="slot_data_obj"> <span>{{slot_data_obj.slotvala}}</span> <span>{{slot_data_obj.slotvalb}}</span> </template> </component-5> </div>
因为slot-scope的值本质上只是个javascript对象,所以可使用es6的解构语法进行<slot>
属性的映射。
以上又能够怎么写
<template slot-scope="{slotvala,slotvalb}"> <span>{{slotvala}}</span> <span>{{slotvalb}}</span> </template>
插口不只能够经过自身属性传递数据给分发的内容,还能够在其上定义v-for
指令,从而将迭代的特性也传递给分发的内容。
new Vue({ el: '#app-6', components: { "component-6":{ data:function(){ return { items: [ {id:1,text:"哪都通快递"}, {id:2,text:"龙虎山天师府"}, {id:3,text:"曜星社"} ] } }, template: '\ <ul>\ <slot name="item" v-for="item in items" v-bind:text="item.text" v-bind:id="item.id"></slot>\ </ul>' } } })
<div id="app-6"> <component-6> <li slot="item" slot-scope="{text,id}"> {{ id+"、"+text }} </li> </component-6> </div>
内容分发中的<li>
被插入slot
中,而且由于slot
中的v-for
指令而进行迭代,迭代以后经过slot-scope
获取slot
上的属性数据。
当使用子组件的内联特性——inline-template
时,父组件的内容分发部分就被解释为子组件的模板,而子组件的template
属性也将被这个部分取代(取代后template
失效),而且做用域也属于子组件。
new Vue({ el:'#app-8', components:{ 'component-8':{ template:'...'//所有被替换 data:function(){ return { childMsg:'child\'s data' } } } } })
<div id="app-8"> <component-8 inline-template> <div> <p>这些将做为组件自身的模板。</p> <p>而非父组件透传进来的内容。</p> <p>子组件数据: {{ childMsg }}</p> </div> </component-8> </div>
"child's data"
来自子组件的childMsg
因为其特色,在使用内联模板时,最容易产生的误区就是混淆做用域。