1. 父子组件传值
父组件通过属性向子组件传值
<div id='root'>
=>如果count加上冒号,则双引号里面是js表达式,传给的是数字
=>如果不加冒号,就是一个字符串
<counter :count="0" @change='toCount'></counter>
<counter :count="0" @change='toCount'></counter>
<div>{{total}}</div>
</div>
var counter1={
props:['count'],=>子组件接收父组件传值count
data:function(){=>在组件中,data中必须是一个方法
return {
number:this.count
}
=>子组件不能去修改父组件传递过来的count(单向数据流),原因在于,防止从子组件意外改变父级组件的状态
=>修改了值之后可能会对其它组件造成影响,因此,把count传值给自身的data(在这里是number,即count的一个副本)
},
template:'<div>{{number}}\
<button @click=\'handleClick\'>click</button>\
</div>'
}
子组件通过事件触发的形式向父组件传值
===在子组件中定义一个方法:向外触发事件change
methods:{
handleClick:function(){
this.number+=2;
this.$emit('change',2)
=>向外触发了一个事件,名叫change,并传了一个参数2
}
===父组件中监听change事件
<counter :count="0" @change='toCount'></counter>
<counter :count="0" @change='toCount'></counter>
===在父组件中定义toCount方法
methods:{ =>父组件接收到的参数2传给n
toCount:function(n){
this.total+=n
}
}
2. 组件参数校验
是指子组件从父组件接收到的参数需要符合一定的条件
props:{
content:[Number,String]
=>传递过来的content必须是一个数字或者一个字符串
=>更复杂的形式:
content:{
type:String, =>传递过来的content必须是一个String
required:true,=>传递过来的content是必须要传的
default:'default value',=>若required为false,则默认值就是default的值
validator:function (value) {
return(value.length>10)//传递过来的长度必须大于10
}
}
}
3. 非props特性
props特性: 1.从父组件接收的props属性在dom结构中不会显示 2.子组件接收之后可以通过插值表达式或this.content的形式去取得content里的内容
非props特性: 1.并不在子组件中用props接收 2.在dom结构中会作为一个dom元素的属性
4. 给组件绑定原生事件
Vue.component("child",{
=>在此处,即模板内绑定的事件才是原生事件,子组件监听自身元素的事件
template:'<div @click=\'handleClick\'>Child</div>',
methods:{
handleClick:function(){
alert('child click');
this.$emit('clickthis')
=>该语句向外触发事件,在父组件监听后产生一个自定义事件
}
}
});
<div id="root">
<child @clickthis="handleThis"></child>
=>父组件监听到自定义事件
</div>
如何在父组件中直接监听到原生事件?
<div id="root">
<child @click.native="handleThis"></child>
=>使用v-on的 .native 修饰符
</div>
<script>
Vue.component("child",{
template:'<div>Child</div>'
});
var vm=new Vue({
el:'#root',
methods:{
handleThis:function(){
alert('this')
}
}
})
</script>
5. 非父子组件传值
父子组件传值:1-2之间,2-3之间的数据传递
非父子组件传值:1-3之间,2-2之间,3-3之间的数据传递
利用总线机制(Bus)/发布-订阅模式/观察者模式 解决非父子组件传值
<div id="root">
<child content="我是第一个组件"></child>
<child content="我是第二个组件"></child>
</div>
<script>
Vue.prototype.bus=new Vue();
=>在Vue的prototype上绑定一个属性bus,使得每个实例/组件中都含有bus属性
Vue.component("child",{
props:{
content:String
},
data:function(){
return{
selfContent:this.content
}
},
template:'<div @click="handleClick">{{selfContent}}</div>',
methods:{
handleClick:function(){
this.bus.$emit('change',this.selfContent)
=>向外触发事件,并传递一个参数,即自身的selfContent
}
},
mounted:function(){
var this_=this;
=>防止this的作用域发生改变
this.bus.$on('change',function(msg){
=>监听事件,修改传递过来的msg值
this_.selfContent=msg;
})
}
});
var vm=new Vue({
el:'#root'
})
</script>
6. 在Vue中使用插槽
<div id="root">
<child> =>并没有插入任何内容,就会显示插入的<slot>
</child>
</div>
<script>
Vue.component("child",{
template:'<div>\
<p>hello </p>\
<slot>默认内容</slot>\
</div>'
=>元素作为组件模板之中的内容分发插槽。 元素自身将被替换。
})
var vm=new Vue({
el:'#root'
})
</script>
经过浏览器的渲染之后会是下面的效果:
如果在组件中插入任意的标签后,模板中的<slot>
标签就会被替换为插入的内容:
<child>
<p>world!</p>
<p>I am Vue.js</p>
</child>
渲染结果会是这样:
具名插槽
元素有一个特殊的特性:name。这个特性可以用来定义额外的插槽.
一个不带 name 的 出口会带有隐含的名字“default”
具名插槽也可以有默认值
如果这样定义模板:
Vue.component("child",{
template:'<div class="container">\
<slot name="header"></slot>\
<slot></slot>\
<slot name="footer"></slot>\
</div>'
})
在组件中这样使用:
<child>
<p slot="header">this is a header</p>
<p>this is a main body</p>
<p slot="footer">this is a footer</p>
</child>
当然也可以在一个 <template>
元素上使用 v-slot
指令,并以 v-slot
的参数的形式提供其名称,会渲染出相同效果:
<child>
<template v-slot:header>
<p>this is a header</p>
</template>
<template>
<p>this is a main body</p>
</template>
<template v-slot:footer>
<p>this is a footer</p>
</template>
</child>
作用域插槽
当子组件做循环或者某一部分dom结构应该由外部传递进来时可以使用作用域插槽
<div id="root">
<child>
<template slot-scope="thisSlot">
=>item的数据就放于thisSlot中
<!-- <li>{{thisSlot.item}}</li> -->
<h1>{{thisSlot.item}}</h1>
</template>
</child>
</div>
<script>
Vue.component("child",{
data:function(){
return {
list:[1,2,3,4]
}
},
template:
`<div>
<ul>
<slot
v-for="item of list"
:item=item
></slot>
<ul>
</div>`
=> :item=item指的是向slot里面传递item数据
});
var vm=new Vue({
el:'#root'
})
</script>
7. 动态组件与v-once指令
在不同组件之间进行动态切换,可以使用component,渲染一个“元组件”为动态组件。依 is 的值,来决定哪个组件被渲染。
<body>
<div id="root">
<component v-bind:is="show"></component>
<button @click="handleChange">Change</button>
</div>
<script>
Vue.component('child-one',{
template:'<div v-once>child one show</div>'
});
Vue.component('child-two',{
template:'<div v-once>child two show</div>'
});
var vm =new Vue({
el:'#root',
data:{
show:'child-one'
},
methods:{
handleChange:function(){
this.show=this.show==='child-one'
?'child-two':'child-one'
}
}
})
</script>
</body>
v-once指令只渲染元素和组件一次。随后的重新渲染,元素/组件及其所有的子节点将被视为静态内容并跳过。这可以用于优化更新性能。