先看例子效果,是个简单的选择输入框:
这个例子将Vue组件的学习简化为三部分:
- 组件注册(全局注册和局部注册)
- 组件组合(父子组件间的通信)
- 组件复用(Prop、事件、插槽)
1、组件注册
全局注册和局部注册
官方文档已经给出了全局注册和局部注册的实例代码:
全局注册
// 注册
Vue.component('my-component', {
template: 'A custom component!'
})
局部注册
var vm = new Vue({//声明一个vue实例
el: '#main',
components: {//在实例中注册组件
'my-component': {
template: 'A custom component!'
}
}
}
使用局部注册的组件只能在其所在实例中使用。
本例中使用局部注册的方式来注册组件。
为方便接下来的父子组件间通信的学习,将下拉列表块作为单独的子组件注册,整个选择输入框是它的父组件。
var Father = {//父组件,在template中使用子组件
data:function(){//组件中的data必须写成函数形式
return {
value:""
}
},
template:' ',
components:{//在父组件中注册子组件
'child-component': {
template:'
'
}
}
}
//创建一个vue实例
var vm = new Vue({
el: '#main',
components: {//注册父组件
'father-component': Father
}
})
html部分:
2、组件组合
父子组件间的通信官方文档总结得很清楚:
在 Vue 中,父子组件的关系可以总结为 prop 向下传递,事件向上传递。父组件通过 prop 给子组件下发数据,子组件通过事件给父组件发送消息。
父组件通过prop将数据传递给子组件
我们希望从外部将下拉列表的数据传给父组件,父组件再将它下发给子组件,使用prop完成这个过程。
首先在实例中定义city的值,并传入父组件:
var vm = new Vue({
el: '#main',
components: {
'father-component': Father
},
data:{
city:["北京","上海","杭州","广州"]//初始化city的值
}
})
父子组件中使用prop,父组件在使用子组件的地方绑定传入的列表值,子组件使用v-for将列表值显示出来:
var Father = {//父组件,在template中使用子组件
props:['list'],
data:function(){//组件中的data必须写成函数形式
return {
value:""
}
},
template:' ',
components:{//在父组件中注册子组件
'child-component': {
props:['list'],
template:'- {{item}}
'
}
}
}
这时我们只要改变外部定义的city的值,子组件中列表值也会改变。
子组件通过vue的自定义事件系统与父组件进行通信
我们想要实现点击子组件的列表项时,就将该列表项的值传到父组件输入框里,即改变父组件中定义的value的值(input已于value建立双向数据绑定)。
每个vue实例都实现了事件接口:
- 使用 $on(eventName) 监听事件
- 使用 $emit(eventName, optionalPayload) 触发事件
首先在注册子组件时,为每个列表项绑定一个点击事件childFun,在childFun中我们将触发父组件的tempFun事件,同时将列表项的值传过去。
'child-component': {
props:['list'],
template:'- {{item}}
',
methods:{
childFun:function(value){
this.$emit('tempFun',value);
}
}
}
在父组件中监听tempFun事件是否被触发,一旦被触发将调用fatherFun方法更新value的值。
var Father = {//父组件,在template中使用子组件
props:['list'],
data:function(){//组件中的data必须写成函数形式
return {
value:""
}
},
template:' ',
components:{//在父组件中注册子组件
'child-component': {
props:['list'],
template:'- {{item}}
',
methods:{
childFun:function(value){
this.$emit('tempFun',value);
}
}
}
},
methods:{
fatherFun:function(item){
this.value = item;
}
}
}
效果:
用同样的思路完善一下代码,实现:监听输入框的输入值,当手动输入值时将列表显现出来,将手动将输入值清空时列表自动隐藏;当输入框隐藏时,右边的三角形的尖角指向下,当输入框显现时,右边的三角形的尖角指向上。
var Father = {
props:['list'],
data:function(){
return {
value:"",
isShow:false,
spanDownShow:true,
spanUpShow:false
}
},
template:' ',
components:{
'child-component': {
props:['list'],
template:'- {{item}}
',
methods:{
childFun:function(value){
this.$emit('tempFun',value);
}
}
}
},
methods:{
fatherFun:function(item){
this.value = item;
},
showPanel:function(){
this.isShow = !this.isShow;
this.spanDownShow = !this.spanDownShow;
this.spanUpShow = !this.spanUpShow;
}
},
watch:{
value:function(newValue,oldValue){
if(newValue === ""){
this.isShow = false;
this.spanDownShow = true;
this.spanUpShow = false;
}else{
this.isShow = true;
this.spanDownShow = false;
this.spanUpShow = true;
}
}
}
}
var vm = new Vue({
el: '#main',
components: {
'father-component': Father
},
data:{
city:["北京","上海","杭州","广州"]
}
})
3、组件复用
Vue 组件的 API 来自三部分——prop、事件和插槽:
prop允许外部环境传递数据给组件
当我们在vue实例中使用多个输入选择框组件时,可以通过传入不同的列表值使每个输入选择框的下拉列表值都不一样。
事件允许从组件内触发外部环境的副作用
同子组件触发父组件的事件,也可通过$emit从父组件内部触发外部环境的function。
插槽允许外部环境将额外的内容组合在组件中
使用
示例:
我们使用父组件时想加上一段话:
使用插槽
父组件的template改为:
template:'没有内容哦 '
页面渲染结果是:
父子组件间的插槽使用同上。更多插槽相关知识请查看官方文档。
demo源码地址: https://github.com/Lizer1995/vuedemo1.git