组件的基本使用

组件命名建议使用-连接的形式,驼峰式命名在使用的时候也要换成-连接的方式
组件模板中只允许有一个根元素
组件 data 为一个函数,返回值是对象,因为重复使用组件的时候相当于每一次都创建了一个组件实例,这样才能让各个组件独立使用互不干扰
组件中除了 el 其他 vue 实例的东西都可以拥有
全局组件可以在任何实例中使用,也可以在别的组件中使用,局部组件只能在创建的实例中使用
全局组件可以在任何组件中使用,局部组件只能在父组件中使用
子组件的对象要定义在父组件上面

全局组件的定义

//global-components是组件的名称,data要是一个返回对象的函数。
//全局组件的写法之一,整体写
Vue.component('global-components', {
	data() {
		return {
			msg: 'global'
		}
	},
	template: `
    <div>全局组件里的信息:{{ msg }}</div>
  `
})
//全局组件的写法二,拆开写
//global-components2是组件的名字
let globalObj = {
	data() {
		return {
			msg: 'global2'
		}
	},
	template: `
    <div>这是一个抽离的全局组件信息:{{ msg }}</div>
  `
}
Vue.component('global-components2', globalObj)

局部组建的定义

//定义在全局实例对象中
let localComponents = {
    data() {
      return {
        msg: 'local'
      }
    },
    template:`
      <div>这是局部组件的值:{{ msg }}</div>
    `
  }
let vm = new Vue({
  el: '#app',
  data: {},
  components: {
    //localComponents: localComponents
    localComponents,
    ...//可以定义多个组件
  }
})
//定义在别的自定义组件中
Vue.component('global-components', {
  data() {
    return {
      msg: 'global'
    }
  },
  components: {
    localComponents,
    ...//可以同时定义多个子组件
  }
})

全局组件的使用

  • 在全局实例中使用
<div id="app">
	<global-components></global-components>
	<global-components2></global-components2>
</div>
<script>
	Vue.component('global-components', {
	  data() {
	    return {
	      msg: 'global'
	    }
	  },
	  template:`
	    <div>全局组件里的信息:{{ msg }}</div>
	  `
	})
	...
</script>
  • 在局部组件中使用
// 局部组件的定义部分
let localComponents = {
	data() {
		return {
			msg: 'local'
		}
	},
	//直接将全局组件插入到局部组件的模板中
	template: `
    <div>这是局部组件的值:{{ msg }}
      <global-components></global-components>    
    </div>
  `
}
//全局组件
Vue.component('global-components', {
	data() {
		return {
			msg: 'global'
		}
	},
	template: `
    <div>全局组件里的信息:{{ msg }}</div>
  `
})

局部组件的使用

局部组件只能在父组件中使用

let localComponents = {
	data() {
		return {
			msg: 'local'
		}
	},
	template: `
<div>这是局部组件的值:{{ msg }}</div>
`
}
//子组件的定义部分要在父组件的上面
// 父组件
Vue.component('global-components', {
	data() {
		return {
			msg: 'global'
		}
	},
	//在父组件的模板里插入子组件
	template: `
    <div>全局组件里的信息:{{ msg }}
      <local-components></local-components>       
    </div>
  `,
	//父组件中的子组件
	components: {
		localComponents
	}
})

组件的嵌套

<!DOCTYPE html>
<html lang="en">
	<head>
		<meta charset="UTF-8" />
		<title>Document</title>
		<style>
			div {
				border: 2px pink solid;
			}
		</style>
	</head>

	<body>
		<div id="app">
			<baba></baba>
			<mama></mama>
		</div>
	</body>
	<script src="../vue.js"></script>
	<script>
		//子组件gege
		let gege = {
			data() {
				return {
					msg: 'i am gege'
				}
			},
			template: `
      <div style="color: pink;">{{ msg }}</div>
    `
		}
		//子组件妹妹
		let meme = {
			data() {
				return {
					msg: 'i am meme'
				}
			},
			template: `
    <div style="color: red;">{{ msg }}</div>
    `
		}
		//Vue实例的子组件baba
		let baba = {
			data() {
				return {
					msg: 'i am baba'
				}
			},
			template: `
    <div style="border: 2px blue solid;">{{ msg }}
      <gege></gege>
      <meme></meme>
    </div>
    `,
			//baba的子组件
			components: {
				gege,
				meme
			}
		}
		//全局组件mama
		Vue.component('mama', {
			data() {
				return {
					msg: 'i am mama'
				}
			},
			//在这里使用
			template: `
    <div style="border: 2px green solid;">{{ msg }}
      <gege></gege>
      <meme></meme>
    </div>
    `,
			//mama的孩子们
			components: {
				gege,
				meme
			}
		})
		// vm实例
		let vm = new Vue({
			el: '#app',

			data: {},
			components: {
				baba
			}
		})
	</script>
</html>

父对子组件传值

传值的步骤和细节

props 后面跟一个数组,数组里面是接收到的父组件传递来的值,可以接收多个值

  • 步骤
<!-- // 父组件中的数据 data: { vuenews: 'hi i am vue' }
//父组件向子组件传递消息,vnews自定义名字,后面的值与data数据一致
//如果传递时不加:即用v-bind绑定则总是隐式转换为string,动态绑定则不会隐式转换。
// 可以传递数组对象
//子组件中设置props接收父组件传的值,名字是自定义名字
//直接使用this.vnews即可在方法中使用接收到的这个值 -->
<!--  在这里传递值 -->
<baba :vnews="vuenews"></baba>
<script>
	props: ['vnews'],
	data() {
	  return {
	    babanews: 'hi i am baba'
	  }
	}
	//子组件使用接收到的值,内容也是自定义名字
	<div>我收到{{ vnews }}</div>
	//子模版继续向下传递值,步骤一致
	 template: `
	<div style="border: 2px blue solid;">{{ msg }}我收到{{ vnews }}
	// 如果想将自己得到的父组件的数据继续向下传递,则直接使用props里面的值即可,步骤一致
	  <gege :bnews="babanews" :jixuchuandi="vnews"></gege>
	  <meme :bnews="babanews"></meme>
	</div>
	`,
	...
</script>
  • 具体示例
<!DOCTYPE html>
<html lang="en">
	<head>
		<meta charset="UTF-8" />
		<title>Document</title>
		<style>
			div {
				border: 2px pink solid;
			}
		</style>
	</head>

	<body>
		<div id="app">
			<!-- vue的消息在这里向子组件传递 -->
			<baba :vnews="vuenews"></baba>
			<mama :vnews="vuenews"></mama>
		</div>
	</body>
	<script src="../vue.js"></script>
	<script>
		//子组件gege
		let gege = {
			//获取到baba mama还有mama传递过来的vue的数据
			props: ['bnews', 'mnews', 'mvnews'],
			data() {
				return {
					msg: 'i am gege',
					gegenews: 'hi i am gege'
				}
			},
			template: `
      <div style="color: pink;">{{ msg }}这里是{{ bnews }}{{ mnews }}{{ mvnews }}</div>
    `
		}
		//子组件妹妹
		let meme = {
			//获取到baba mama还有mama传递过来的vue的数据
			props: ['bnews', 'mnews', 'mvnews'],
			data() {
				return {
					msg: 'i am meme',
					memenews: 'hi i am meme'
				}
			},
			template: `
    <div style="color: red;">{{ msg }}这里是{{ bnews }}{{ mnews }}{{ mvnews }}</div>
    `
		}
		//Vue实例的子组件
		let baba = {
			//这里接收vue的信息
			props: ['vnews'],
			data() {
				return {
					msg: 'i am baba',
					babanews: 'hi i am baba'
				}
			},
			//在这里使用vue的消息
			template: `
    <div style="border: 2px blue solid;">{{ msg }}我收到{{ vnews }}
      <gege :bnews="babanews"></gege>
      <meme :bnews="babanews"></meme>
    </div>
    `,
			//baba的子组件
			components: {
				gege,
				meme
			}
		}
		//全局组件
		Vue.component('mama', {
			//这里接收vue的信息
			props: ['vnews'],
			data() {
				return {
					msg: 'i am mama',
					mamanews: 'hi i am mama'
				}
			},
			//在这里使用vue的消息
			//向子组件传递自己的数据以及传递自己获取到的vue的数据
			template: `
    <div style="border: 2px green solid;">{{ msg }}我收到{{ vnews }}
      <gege :mnews="mamanews" :mvnews="vnews"></gege>
      <meme :mnews="mamanews" :mvnews="vnews"></meme>
    </div>
    `,
			//mama的孩子们
			components: {
				gege,
				meme
			}
		})
		// vm实例
		let vm = new Vue({
			el: '#app',

			data: {
				msg: 'i am vue',
				vuenews: 'hi i am vue'
			},
			components: {
				baba
			}
		})
	</script>
</html>

监听子组件事件&&接收传递上来的数据

父组件可以通过监听子组件触发的事件来达到响应事件的目的,同时也可以获取到子组件传递给自己的数据。

父组件响应子组件的事件

  • 子组件定义事件
    1. 在模板中直接定义
      在子组件的模板里定义一个事件,通过这个事件的触发来让父组件接收,$emit()里面就是要传递给父组件的事件名
      //子组件的模板
      template: ` <div style="color: pink;">{{ msg }} <button @click="$emit('ge-event')">{{ msg }}</button> </div> `
      
    2. 在 methods 中定义
      在 methods 定义一个方法,方法里使用 this.$emit()实例方法来定义要传递给父组件的事件名,子组件模板里通过触发事件来调用这个方法。
       //子组件的模板
        template: ` <div style="color: red;">{{ msg }} <button @click="gege">{{ msg }}</button> </div> `,
        methods: { gege() { this.$emit('ge-event') } }
      
  • 父组件监听事件
    1. 直接在模板中使用表达式 这里@后面的事件名和子组件$emit()里面传递的一致,在模板里使用 data 里面的值不需要加 this
      template: ` <div style="border: 2px green solid;">{{ msg }} <gege @ge-event="msg += 'ok'"></gege> </div> `
      
    2. 在 methods 中定义响应事件 @后面的事件名与子组件$emit()传递的一致,后面跟着触发后调用的方法,方法定义在 methods 中
      template: ` <div style="border: 2px green solid;">{{ msg }} <gege @ge-event="mahandle"></gege> </div> `,
      components: { gege },
      methods: { mahandle() { this.msg += 'ojbk' } }
      

父组件接收子组件的数据

  • 子组件传递数据的方式是放在$emit('event', )逗号后面
data() {
  return {
    msg: 'i am gege',
    gegenews: 'hi i am gege'
  }
},
//在模板中书写不需要加this
template: `
<div style="color: pink;">{{ msg }}
  <button @click="$emit('ge-event', gegenews)">{{ msg }}</button>
</div>
`
// 在方法中书写需要加this
template: `
<div style="color: red;">{{ msg }}
  <button @click="gege">{{ msg }}</button>
</div>
`,
methods: {
  gege() {
    this.$emit('ge-event', this.gegenews)
  }
}
  • 父组件接收数据使用$event 接收
//直接在模板中使用传递过来的数据,直接使用$event即可
template: `
<div style="border: 2px green solid;">{{ msg }}
  <gege @ge-event="msg += $event"></gege>
</div>
`
//在方法中使用需要设置形参接收,mahandle后面可以省略括号和里面的内容,但是方法一定要设置形参
template: `
<div style="border: 2px green solid;">{{ msg }}
  <gege @ge-event="mahandle($event)"></gege>
</div>
`,
//mama的孩子
components: {
  gege
},
methods: {
  mahandle(val) {
    this.msg += val
  }
}
  • 整体例子
<!DOCTYPE html>
<html lang="en">
	<head>
		<meta charset="UTF-8" />
		<title>Document</title>
		<style>
			div {
				border: 2px pink solid;
			}
		</style>
	</head>
	<body>
		<div id="app">
			<!-- <mama></mama> -->
		</div>
	</body>
	<script src="../vue.js"></script>
	<script>
		//子组件gege
		let gege = {
			data() {
				return {
					msg: 'i am gege',
					gegenews: 'hi i am gege'
				}
			},
			template: `
      <div style="color: pink;">{{ msg }}
        <button @click="$emit('ge-event', gegenews)">{{ msg }}</button>
      </div>
    `
		}
		//子组件妹妹
		let meme = {
			data() {
				return {
					msg: 'i am meme',
					memenews: 'hi i am meme'
				}
			},
			template: `
    <div style="color: red;">{{ msg }}
      <button @click="meme">{{ msg }}</button>      
    </div>
    `,
			methods: {
				meme() {
					this.$emit('me-event', this.memenews)
				}
			}
		}
		//全局组件mama
		Vue.component('mama', {
			data() {
				return {
					msg: 'i am mama'
				}
			},
			//在这里使用
			template: `
    <div style="border: 2px green solid;">{{ msg }}
      <gege @ge-event="mahandle($event)"></gege>
      <meme @me-event="msg += $event"></meme>
    </div>
    `,
			//mama的孩子们
			components: {
				gege,
				meme
			},
			methods: {
				mahandle(val) {
					this.msg += val
				}
			}
		})
		// vm实例
		let vm = new Vue({
			el: '#app',
			data: {}
		})
	</script>
</html>

v-model 在组件中的使用

使用 v-model 可以使父组件中的数据与子组件的表单数据保持一致,实际上就是通过父组件传值给子组件,子组件接受,绑定属性为接收到的值,然后再通过父组件监听子组件的事件来接收到子组件改变后的值。

<div id="app">
	<!-- <mama></mama> -->
</div>
<script src="../vue.js"></script>
<script>
	//子组件gege
	let gege = {
		props: ['value'],
		template: `
    <input type="text" :value="value" @input="$emit('input', $event.target.value)">  
    `
	}
	//全局组件
	Vue.component('mama', {
		data() {
			return {
				msg: 'i am mama'
			}
		},
		//在这里使用
		template: `
    <div style="border: 2px green solid;">{{ msg }}
      <gege v-model="msg"></gege>
    </div>
    `,
		//mama的孩子
		components: {
			gege
		}
	})
	// vm实例
	let vm = new Vue({
		el: '#app',
		data: {}
	})
</script>

实现的原理就是 v-model 是通过 v-bind 绑定属性和 v-on 绑定事件来实现的,所以可以用 v-model 来替代他们

//子组件gege
let gege = {
	props: ['mamsg'],
	data() {
		return {
			msg: 'i am gege'
		}
	},
	template: `
    <div style="color: pink;">{{ msg }}
      <input type="text" :value="mamsg" @input="$emit('ge-input', $event.target.value)">  
    </div>
  `
}
//全局组件
Vue.component('mama', {
	data() {
		return {
			msg: 'i am mama'
		}
	},
	//在这里使用
	template: `
  <div style="border: 2px green solid;">{{ msg }}
    <gege :mamsg="msg" @ge-input="msg = $event"></gege>
  </div>
  `,
	//mama的孩子
	components: {
		gege
	}
})

兄弟组件之间相互传值

//第一步提供一个事件中心
let hub = new Vue()
//子组件gege
let gege = {
	data() {
		return {
			msg: 'i am gege'
		}
	},
	//第二步模板里定义一个事件,触发传递的方法
	template: `
  <button @click="handle">{{ msg }}</button>
  `,
	methods: {
		// 第三步触发的方法里传递信息
		handle() {
			hub.$emit('gege', this.msg)
		}
	}
}
//子组件妹妹
let meme = {
	data() {
		return {
			msg: 'i am meme'
		}
	},
	template: `
  <div style="color: red;">{{ msg }}</div>
  `,
	//第四步使用生命周期函数接收消息
	mounted() {
		// 监听事件
		hub.$on('gege', val => {
			this.msg += val
		})
	}
}
//全局组件
Vue.component('mama', {
	data() {
		return {
			msg: 'i am mama'
		}
	},
	//在这里使用
	template: `
  <div style="border: 2px green solid;">
    <gege></gege>
    <meme></meme>
  </div>
  `,
	//mama的孩子们
	components: {
		gege,
		meme
	}
})