1.组件中的数据存放
案例:
<!DOCTYPE html>
<html>
<head lang="en">
<meta charset="UTF-8">
<title></title>
</head>
<body>
<div id="app1">
<!--使用组件-->
<mycpnc></mycpnc>
</div>
<!--使用template标签抽离组件模板-->
<template id="script_template">
<div>
<h3>{{message}}</h3>
</div>
</template>
<!--引入本地的vue.js文件-->
<script src="../vue.js"></script>
<script>
let app1 = new Vue({
el: '#app1', // 讲这个vue实例与id为app1的标签关联起来
data: {},
//使用语法糖方式注册局部组件
components: {
'mycpnc':{
template: '#script_template',
data:function(){
return {message: '我是组件中的数据'}
}
}
}
})
</script>
</body>
</html>
运行效果如下:
总结:
- 组件中无法使用vue实例中的数据。
- 组件中使用data属性来存放组件自己的数据。
- 组件中的data属性是一个函数,且必须返回一个对象,在对象中存放数据。
2.组件中的data属性为什么是函数?
vue讲组件中的data属性设置为一个函数,主要原因是为了防止引用多个组件实例时产生数据冲突。
3.父子组件之间的通信
(1)父组件传递数据给子组件-props
拓展:vue实例也可以看成一个组件,注册在vue实例中的组件就是其子组件。
(1.1)父组件传递数据给子组件的步骤:
子组件中
-
子组件中使用props声明变量用于接受父组件的数据。
方式1:使用数组形式声明变量
let app = new Vue({ el: '#app1', // 讲这个vue实例与id为app1的标签关联起来 data: { message: '哈哈哈', number: 10 }, //使用语法糖方式注册局部组件 components: { 'mycpnc':{ template: '#script_template', //声明变量用于接受父组件的数据 //使用props声明后cmessage和cnumber就相当于子组件中的属性变量 //父组件使用时可以使用v-bind的方式将数据传递给cmessage和cnumber props:['cmessage','cnumber'] } } })
方式2:使用对象的方式声明变量(常用)
let app = new Vue({ el: '#app1', // 讲这个vue实例与id为app1的标签关联起来 data: { message: '哈哈哈', number: 10 }, //使用语法糖方式注册局部组件 components: { 'mycpnc':{ template: '#script_template', //声明变量用于接受父组件的数据 //使用props声明后cmessage和cnumber就相当于子组件中的属性变量 //父组件使用时可以使用v-bind的方式将数据传递给cmessage和cnumber props:{ cmessage:{ type:String, //指定父组件需要传递数据的类型 default:'嘿嘿嘿', //指定父组件需要传递数据的默认值 required:true //指定父组件使用子组件时,必须传递该数据 }, cnumber:{ type:Number, default:55, required:false } } } } })
-
子组件的模板中使用数据
<!--使用template标签抽离组件模板--> <!--在子组件的模板中直接使用经过props声明的变量--> <template id="script_template"> <div> <h3>{{cmessage}}</h3> <h3>{{cnumber}}</h3> </div> </template>
父组件中
-
父组件中使用子组件时,需要使用
v-bind
的方式将数据传递给子组件声明好的变量<div id="app1"> <!--使用组件--> <mycpnc :cmessage="message" :cnumber="number"></mycpnc> </div>
(1.2)案例
<!DOCTYPE html>
<html>
<head lang="en">
<meta charset="UTF-8">
<title></title>
</head>
<body>
<div id="app1">
<!--使用组件-->
<mycpnc :cmessage="message" :cnumber="number"></mycpnc>
</div>
<!--使用template标签抽离组件模板-->
<template id="script_template">
<div>
<h3>{{cmessage}}</h3>
<h3>{{cnumber}}</h3>
</div>
</template>
<!--引入本地的vue.js文件-->
<script src="../vue.js"></script>
<script>
let app = new Vue({
el: '#app1', // 讲这个vue实例与id为app1的标签关联起来
data: {
message: '哈哈哈',
number: 10
},
//使用语法糖方式注册局部组件
components: {
'mycpnc':{
template: '#script_template',
//声明变量用于接受父组件的数据
//使用props声明后cmessage和cnumber就相当于子组件中的属性变量
//父组件使用时可以使用v-bind的方式将数据传递给cmessage和cnumber
props:{
cmessage:{
type:String, //指定父组件需要传递数据的类型
default:'嘿嘿嘿', //指定父组件需要传递数据的默认值
required:true //指定父组件使用子组件时,必须传递该数据
},
cnumber:{
type:Number,
default:55,
required:false
}
}
}
}
})
</script>
</body>
</html>
效果如下:
(1.3)父组件传递数据给子组件的过程图解
因为组件之间数据的传递比较繁杂,这里使用图解的方式表示一下。
(1.4)子组件中使用驼峰标识及没有跟标签的坑
子组件中使用驼峰标识变量的坑
子组件中使用驼峰标识的变量来接受父组件传递过来的数据时,会导致父组件传递数据失败。
<!DOCTYPE html>
<html>
<head lang="en">
<meta charset="UTF-8">
<title></title>
</head>
<body>
<div id="app1">
<!--使用组件-->
<mycpnc :cMessage="message"></mycpnc>
</div>
<!--使用template标签抽离组件模板-->
<template id="script_template">
<div>
<h3>{{cMessage}}</h3>
</div>
</template>
<!--引入本地的vue.js文件-->
<script src="../vue.js"></script>
<script>
let app = new Vue({
el: '#app1', // 讲这个vue实例与id为app1的标签关联起来
data: {
message: '哈哈哈',
number: 10
},
//使用语法糖方式注册局部组件
components: {
'mycpnc':{
template: '#script_template',
props:{
cMessage:{
type:String, //指定父组件需要传递数据的类型
default:'我是默认值', //指定父组件需要传递数据的默认值
required:true //指定父组件使用子组件时,必须传递该数据
},
}
}
}
})
</script>
</body>
</html>
效果如下:
所有我们在定义子组件用于接受数据的变量时,应该避免使用驼峰标识。如果一定要使用驼峰标识,那么中父组件给子组件传递数据时,应将子组件的属性使用’-'连接来代替驼峰标识。
<!DOCTYPE html>
<html>
<head lang="en">
<meta charset="UTF-8">
<title></title>
</head>
<body>
<div id="app1">
<!--使用组件-->
<mycpnc :c-message="message"></mycpnc>
</div>
<!--使用template标签抽离组件模板-->
<template id="script_template">
<div>
<h3>{{cMessage}}</h3>
</div>
</template>
<!--引入本地的vue.js文件-->
<script src="../vue.js"></script>
<script>
let app = new Vue({
el: '#app1', // 讲这个vue实例与id为app1的标签关联起来
data: {
message: '哈哈哈',
number: 10
},
//使用语法糖方式注册局部组件
components: {
'mycpnc':{
template: '#script_template',
props:{
cMessage:{
type:String, //指定父组件需要传递数据的类型
default:'我是默认值', //指定父组件需要传递数据的默认值
required:true //指定父组件使用子组件时,必须传递该数据
},
}
}
}
})
</script>
</body>
</html>
运行效果如下:
子组件模板中不使用跟标签的坑
当在我们子组件模板使用了多个变量来渲染内容时,如果子组件的模板中未使用跟标签,会导致只有一个变量的数据能渲染成功,其他变量数据不会被渲染。
<!DOCTYPE html>
<html>
<head lang="en">
<meta charset="UTF-8">
<title></title>
</head>
<body>
<div id="app1">
<!--使用组件-->
<mycpnc :c-message="message" :c-number="number"></mycpnc>
</div>
<!--使用template标签抽离组件模板-->
<template id="script_template">
<h3>{{cMessage}}</h3>
<h3>{{cNumber}}</h3>
</template>
<!--引入本地的vue.js文件-->
<script src="../vue.js"></script>
<script>
let app = new Vue({
el: '#app1', // 讲这个vue实例与id为app1的标签关联起来
data: {
message: '哈哈哈',
number: 10
},
//使用语法糖方式注册局部组件
components: {
'mycpnc':{
template: '#script_template',
props:{
cMessage:{
type:String, //指定父组件需要传递数据的类型
default:'我是默认值', //指定父组件需要传递数据的默认值
required:true //指定父组件使用子组件时,必须传递该数据
},
cNumber:{
type:Number,
}
}
}
}
})
</script>
</body>
</html>
效果如下:
所有我们在定义子组件的模板时,最好加上一个跟标签div
<!DOCTYPE html>
<html>
<head lang="en">
<meta charset="UTF-8">
<title></title>
</head>
<body>
<div id="app1">
<!--使用组件-->
<mycpnc :c-message="message" :c-number="number"></mycpnc>
</div>
<!--使用template标签抽离组件模板-->
<template id="script_template">
<div>
<h3>{{cMessage}}</h3>
<h3>{{cNumber}}</h3>
</div>
</template>
<!--引入本地的vue.js文件-->
<script src="../vue.js"></script>
<script>
let app = new Vue({
el: '#app1', // 讲这个vue实例与id为app1的标签关联起来
data: {
message: '哈哈哈',
number: 10
},
//使用语法糖方式注册局部组件
components: {
'mycpnc':{
template: '#script_template',
props:{
cMessage:{
type:String, //指定父组件需要传递数据的类型
default:'我是默认值', //指定父组件需要传递数据的默认值
required:true //指定父组件使用子组件时,必须传递该数据
},
cNumber:{
type:Number,
}
}
}
}
})
</script>
</body>
</html>
效果如下:
(2)子组件传递数据给父组件-通过自定义事件
子组件传递数据给父组件流程:
- 子组件使用
$emit()
来发送自定义事件。this.$emit('自定义事件的名称','需要传递的数据')
- 父组件中使用
v-on
监听子组件中发送的自定义事件
案例:在子组件中定义数据count,并创建两个按钮+-
。实现点击按钮后count加或者减1。并将子组件中的count数据传递到父组件的fcount中,进行展示。
<!DOCTYPE html>
<html>
<head lang="en">
<meta charset="UTF-8">
<title></title>
</head>
<body>
<!--父组件模板-->
<div id="app1">
<!--使用组件-->
<!--父组件中使用v-on来监听子组件的自定义参数,注意这里不需要传入实参。因为子组件自定义事件时的第二个参数this.count,会作为默认参数传进来-->
<mycpnc @cclick="faccpet"></mycpnc>
<h3>{{fcount}}</h3>
</div>
<!--使用template标签抽离组件模板-->
<template id="script_template">
<div>
<button type="button" @click="addclick">+</button>
<button type="button" @click="reduceclick">-</button>
</div>
</template>
<!--引入本地的vue.js文件-->
<script src="../vue.js"></script>
<script>
let app = new Vue({
el: '#app1', // 讲这个vue实例与id为app1的标签关联起来
data: {fcount:0},
methods: {
//子组件自定义事件的监听方法,注意这里必须要有形参item。
faccpet: function(item){
this.fcount = item;
}
},
//使用语法糖方式注册局部组件
components: {
'mycpnc':{
template: '#script_template',
data: function(){
return {count:0}
},
methods:{
addclick: function(){
this.count++;
//发送自定义事件,第一个参数为自定义事件的名称,第二个参数为需要传递的数据
this.$emit('cclick',this.count);
},
reduceclick: function(){
this.count--;
this.$emit('cclick',this.count);
}
}
}
}
})
</script>
</body>
</html>
效果如下:
4.子组件中改变父组件传递过来的数据
前面我们讲了父组件传递给子组件的数据是保存在props
中,当我们需要使用该数据时,直接使用props
中的变量即可。但是当我们需要改变父组件传递过来的数据时,可以直接改变props
中变量的值吗?
<!DOCTYPE html>
<html>
<head lang="en">
<meta charset="UTF-8">
<title></title>
</head>
<body>
<div id="app1">
<!--使用组件-->
<mycpnc :cmessage="message"></mycpnc>
</div>
<!--使用template标签抽离组件模板-->
<template id="script_template">
<div>
<button type="button" @click="cmessage++">+</button>
<button type="button" @click="cmessage--">-</button>
<h3>{{cmessage}}</h3>
</div>
</template>
<!--引入本地的vue.js文件-->
<script src="../vue.js"></script>
<script>
let app = new Vue({
el: '#app1', // 讲这个vue实例与id为app1的标签关联起来
data: {message:0},
//使用语法糖方式注册局部组件
components: {
'mycpnc':{
template: '#script_template',
props:['cmessage']
}
}
})
</script>
</body>
</html>
结果如下:
那么如何解决这个问题呢?答案就是将父组件传递过来的数据存放到子组件的data属性中,如何改变data中的值。
<!DOCTYPE html>
<html>
<head lang="en">
<meta charset="UTF-8">
<title></title>
</head>
<body>
<div id="app1">
<!--使用组件-->
<mycpnc :cmessage="message"></mycpnc>
</div>
<!--使用template标签抽离组件模板-->
<template id="script_template">
<div>
<button type="button" @click="dmessage++">+</button>
<button type="button" @click="dmessage--">-</button>
<h3>{{dmessage}}</h3>
</div>
</template>
<!--引入本地的vue.js文件-->
<script src="../vue.js"></script>
<script>
let app = new Vue({
el: '#app1', // 讲这个vue实例与id为app1的标签关联起来
data: {message:0},
//使用语法糖方式注册局部组件
components: {
'mycpnc':{
template: '#script_template',
props:['cmessage'],
data:function(){
return {
dmessage:this.cmessage //将props中的cmessage值保存到data中的dmessage中
}
}
}
}
})
</script>
</body>
</html>
结果如下:
总结:
父组件传递数据给子组件,子组件中需要在props中设置变量来接受数据。当我们需要展示数据时,直接使用props中的变量即可。但是当我们需要改变数据时,可以直接改变props中的变量,但是代码会有警告所有不推荐这种方式。推荐将props中的变量赋值给data中的一个变量,如何通过改变data中的变量,来改变数据的值。