在实际开发中,我们从服务器请求到了很多数据,并不是在整个页面的大组件来展示的,而是需要下面的子组件进行展示,这时不会让子组件再次发生一个网络请求,而是直接让父组件将数据传递给子组件。父组件向子组件传递数据有两种方式:一是通过props;二是通过事件。
在组件中,使用选项props来声明需要从父级接收到的数据,有两种方式:
由于Vue实例可以看作所有组件的根组件,Vue实例的数据要传入子组件时,在注册时往props传入一个对象,然后在使用时用v-bind将props中的属性和data中的数据绑定即可实现传值。
举例:
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Titletitle>
head>
<body>
<div id="app">
<cpn :cmovies="movies" :cmessage="message">cpn>
div>
<template id="cpn">
<div>
<ul>
<li v-for="item in cmovies">{
{item}}li>
ul>
<p>{
{cmessage}}p>
div>
template>
<script src="../js/vue.js">script>
<script>
// 注册全局组件
Vue.component(`cpn`,{
template:`#cpn`,
props:{
//指定类型
cmessage:String,
cmovies:Array
}
})
const app = new Vue({
el:"#app",
data:{
message:`你好啊`,
movies:[`海王`,`海贼王`,`海尔兄弟`]
}
})
script>
body>
html>
除了指定类型,还可以设置默认值或是否必填等:
Vue.component(`cpn`,{
template:`#cpn`,
props:{
// 基础的类型检查('null'匹配任何类型)
propA:Number,
// 多个可能的类型
propB:[String,Number],
// 必填的字符串
propC:{
type:String,
required:true
},
// 带默认值的数字
propD:{
type: Number,
default:100
},
// 带有默认值的对象
propE:{
type:Object,
// 对象或数组默认值必须从一个工厂函数获取
default: function () {
return {
message: `hello`}
}
},
// 自定义验证函数
propF:{
validator:function (value) {
// 这个值必须匹配下列字符串中的一个
return [`success`,`warning`,`danger`].indexOf(value) !== -1
}
}
}
})
需要注意的是v-bind中不支持驼峰语法,如需绑定propA或childMyMessage这样命名的属性就要在绑定时写成用-连接:
当子组件有数据传递到父组件时,需要通过自定义事件来实现。v-on不仅可以用于监听DOM事件,还可以用于组件间的自定义事件。
自定义事件的流程:
举例:
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Titletitle>
head>
<body>
<div id="app">
<cpn @item-click="cpnClick">cpn>
div>
<template id="cpn">
<div>
<button v-for="item in categories" @click="btnClick(item)">{
{item.name}}button>
div>
template>
<script src="../js/vue.js">script>
<script>
// 注册全局组件
Vue.component(`cpn`,{
template:`#cpn`,
data(){
return {
categories: [
{
id: `aaa`, name: `热门推荐`},
{
id: `bbb`, name: `家电家器`},
{
id: `ccc`, name: `手机数码`},
]
}
},
methods:{
btnClick(item){
//发射事件$emit(发射事件名,发射参数)
this.$emit(`item-click`,item)
}
}
})
const app = new Vue({
el:"#app",
data:{
},
methods:{
cpnClick(item){
console.log(item.name);
}
}
})
script>
body>
html>
执行结果:
原本methods需要有参数而监听时没有加括号,就会默认传入事件参数,而在这里
因为监听的是组件的自定义事件,所以会默认传一个自定义事件中btnClick(item){this.$emit(‘item-click’,item)}
发射的参数即item。
还需要注意我这个版本的Vue的v-on所监听的事件名(即此处:@item-click
)好像也不支持驼峰语法,写了驼峰会报错,例子中我都给改成了横杠连接。
有时我们父子之间并不需要传递数据,可能只是想访问父组件或者子组件的对象进行一些操作,这就需要用到:
$children
或$refs
$parent
this.$children是一个数组类型,它包含所有子组件对象,先来看看组件对象内有什么。
举例:
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Titletitle>
head>
<body>
<div id="app">
<cpn>cpn>
<cpn>cpn>
<cpn>cpn>
<button @click="btnClick">按钮button>
div>
<template id="cpn">
<div>
{
{message}}
div>
template>
<script src="../js/vue.js">script>
<script>
const app = new Vue({
el:"#app",
data:{
},
methods:{
btnClick(){
console.log(this.$children);
}
},
components:{
cpn:{
template:`#cpn`,
data(){
return {
message:`我是子组件的message`
}
},
methods:{
showMessage(){
console.log(`我是子组件的方法`);
}
}
}
}
})
script>
body>
html>
执行结果:
点击按钮打印组件对象可以看到有3个子组件对象,每一个对象内包括很多属性,也包括子组件data中的message和methods里的方法,那么就可以通过访问对象属性的方法来访问子组件的属性了。
往btnClick()添加:
console.log(this.$children[0].message);
this.$children[1].showMessage();
执行结果:
即可访问this.$children
数组中,0号子组件对象的message和1号子组件对象的showMessage()。
通过this.$children
数组访问子组件时,一旦之后添加了组件,数组内的顺序就可能发生改变,使得想固定访问某个组件变得困难,这时就需要使用this.$refs
。
this.$refs
数组内默认是没有任何东西的,需要在使用组件时添加ref属性才会生效。
举例:
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Titletitle>
head>
<body>
<div id="app">
<cpn>cpn>
<cpn ref="aaa">cpn>
<cpn>cpn>
<button @click="btnClick">按钮button>
div>
<template id="cpn">
<div>
{
{message}}
div>
template>
<script src="../js/vue.js">script>
<script>
const app = new Vue({
el:"#app",
data:{
},
methods:{
btnClick(){
console.log(this.$refs);
console.log(this.$refs.aaa);
this.$refs.aaa.showMessage()
}
},
components:{
cpn:{
template:`#cpn`,
data(){
return {
message:`我是子组件的message`
}
},
methods:{
showMessage(){
console.log(`我是子组件的方法`);
}
}
}
}
})
script>
body>
html>
执行结果:
ref属性相当于给组件取了个名字,在this.$refs
中取得的是一个对象,给对象取的名字就是key,value为它的组件对象,通过this.$refs.ref属性值
访问组件对象在进行下一步访问。
$parent
与$root
在子组件内想要访问父组件的元素,就要通过this.$parent
或this.$root
。this.$parent
是访问当前组件的父组件,this.$root
是访问根组件,即访问Vue实例。
举例:
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Titletitle>
head>
<body>
<div id="app">
<cpn>cpn>
div>
<template id="cpn">
<div>
我是cpn组件
<ccpn>ccpn>
div>
template>
<template id="ccpn">
<div>
我是ccpn组件
<button @click="btnClick">按钮button>
div>
template>
<script src="../js/vue.js">script>
<script>
// 1.Vue实例
const app = new Vue({
el:"#app",
data:{
message:`你好啊`
},
//2.子组件
components:{
cpn:{
template:`#cpn`,
data(){
return{
message:`我是子组件的message`
}
},
//3.子组件的子组件
components:{
ccpn:{
template:`#ccpn`,
methods:{
btnClick(){
console.log(this.$parent);
console.log(this.$parent.message);
console.log(this.$root);
console.log(this.$root.message);
}
}
}
}
}
}
})
script>
body>
html>
执行结果:
例子中在Vue实例内注册了cpn组件,有在cpn组件中注册了ccpn组件(禁止套娃! ) ,即ccpn的父组件是cpn,cpn组件的父组件是Vue实例。在ccpn中通过this.$parent
访问到的是cpn的组件对象,通过this.$root
访问到的是跟组件,即Vue实例。
Vue.js学习笔记——10.组件化开发(一)
Vue.js学习笔记——12.组件化开发(三)