1. 组件数据存放
-
组件是一个单独功能模块的封装,这个模块有自己HTML模板,也应该有自己的数据data。
-
那么组件的数据存放在哪里呢?组件能直接访问顶层的vue实例中的数据吗?
-
我们发现不能直接访问顶层的vue实例中的数据。
-
因此组件应该有自己存放数据的地方。
-
组件对象也有一个data属性
-
这个属性必须是一个函数
- 如果不是一个函数,Vue直接就会报错
- Vue让每个组件对象都返回一个新的对象,因为如果是同一个对象的,组件在多次使用后会相互影响。
-
而且这个函数返回一个对象,对象内部保存着数据
全局组件的数据存放
<template id="cpn1">
<div>
<h1>{{title}}</h1>
<p>这是全局组件中数据存放</p>
</div>
</template>
<script src="../js/vue.js"></script>
<script type="text/javascript">
Vue.component('cpn1',{
template: '#cpn1',
data(){
return{
title: 'bbbb'
}
}
})
</script>
局部组件的数据存放
<template id="cpn">
<div>
<h1>{{title}}</h1>
<p>这是局部组件中数据存放</p>
</div>
</template>
<script src="../js/vue.js"></script>
<script type="text/javascript">
//局部组件的数据存放
var app= new Vue({
el: "#app",
data: {
message:'小贱'
},
components:{
'cpn':{
template:'#cpn',
data(){
return {
title : 'aaaaa'
}
}
},
}
})
</script>
2. 父子组件之间的通信
- 从数据的存放中我们得知子组件是不能引用父组件或者vue实例的数据的。
- 但是往往在开发中,一些数据需要从上层传递到下层
- 如何进行父子组件之间的通信,官方提到
- 父组件通过props向子组件传递数据
- 子组件通过事件向父组件传递消息
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-6PjS8V9p-1595236228981)(vue-images/Snipaste_2020-07-07_17-43-51.png)]
1. 父传子(props)
- 字符串数组,数组中的字符串就是传递时的名称
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-CYiZQTN3-1595236228984)(vue-images/Snipaste_2020-07-09_18-36-39.png)]
-
对象,对象可以设置传递时的类型,也可以设置默认值
-
当我们需要对props进行数据类型的验证的时候就需要用到对象类型了
- 支持验证的数据类型
- String , Number , Boolean , Array , Object , Date ,Function , Symbol
<body>
<div id="app">
//此处用到props的驼峰命名规则 c-message
<cpn1 :c-message="message" :removies="movies"></cpn1>
<cpn2 :message="message"></cpn2>
</div>
<template id="cpn">
<div>
<ul>
<li v-for="item in removies">{{item}}</li>
</ul>
<h2>{{cMessage}}</h2>
</div>
</template>
<template id="cpn2">
<h2>数组、:{{message}}</h2>
</template>
<script src="../js/vue.js"></script>
<script type="text/javascript">
//父传子 props
var cpn = {
template: '#cpn',
props:{
cMessage:{
type: String,
default: 'aaaaa'
},
//类型时对象或者数组的时候,默认值必须是一个函数
removies: {
type: Array,
default(){
return []
}
}
}
}
const app= new Vue({
el: "#app",
data: {
message: "hello vue",
movies: ['红楼梦','水浒','三国演义','西游记']
},
components:{
cpn1:cpn ,
cpn2:{
template: '#cpn2',
props: ['message']
}
}
})
</script>
</body>
2. 子传父(事件)
- 我们可以通过自定义事件使子组件可以向父组件传递数据
- v-on不仅可以监听DOM事件,也可以用来自定义事件
- 流程
- 子组件通过$emit()触发事件
- 父组件通过v-on监听事件
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
//监听+-的次数
</head>
<body>
<div id="app">
<child-cpn @increment='changeTotal' @decrement="changeTotal"></child-cpn>
<h2>点击次数:{{total}}</h2>
</div>
<template id="cpn">
<div>
<button @click="increment">+1</button>
<button @click="decrement">-1</button>
</div>
</template>
<script src="../js/vue.js"></script>
<script type="text/javascript">
var app= new Vue({
el: "#app",
data: {
total:0
},
methods:{
changeTotal(counter){
this.total=counter
}
},
components: {
'child-cpn':{
template:"#cpn",
data(){
return{
counter:0
}
},
methods:{
increment(){
this.counter++
//发送一个事件$emit
this.$emit('increment',this.counter)
},
decrement(){
this.counter--
this.$emit('decrement',this.counter)
}
}
}
}
})
</script>
</body>
</html>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</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 type="text/javascript">
const cpn= {
template: '#cpn',
data(){
return{
categories:[
{id: 'aaa',name:'热门推荐'},
{id: 'bbb',name:'手机数码'},
{id: 'ccc',name:'家用家电'},
{id: 'ddd',name:'电脑办公'}
]
}
},
methods:{
btnClick(item){
this.$emit('item-click',item)
}
}
}
const app= new Vue({
el: "#app",
data: {
message: "hello vue"
},
components: {
cpn:cpn
},
methods:{
cpnClick(item){
console.log('cpnClick',item)
}
}
})
</script>
</body>
</html>
3.父子组件之间的访问
1. 父组件访问子组件
-
$children
- this.$children是一个数组类型,包含所有的子组件对象
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <div id="app"> <cpn></cpn> <button @click="btnClick">按钮</button> </div> <template id="cpn"> <div>我是子组件</div> </template> <script src="../js/vue.js"></script> <script type="text/javascript"> var app= new Vue({ el: "#app", data: { message: "hello vue" }, methods:{ btnClick(){ //$children console.log(this.$children) for(let c of this.$children){ console.log(c.name); c.showMessage() } // console.log(this.$children[1].name) } }, components: { cpn: { template: '#cpn', data(){ return{ name: '我是子组件的name' } }, methods: { showMessage(){ console.log('showMessage!!!') } } } } }) </script> </body> </html>
-
$refs
- 通过$children访问子组件的时候,因为是一个数组类型,访问子组件必须通过其索引值
- 当子组件过多的时候,我们往往不能确定其子组件的索引
- 当我们想明确的取出其中的一个特定的子组件,可以使用$refs
-
$refs的使用
- $refs和ref指令一起使用
- 通过ref给组件添加一个特定的ID
- 通过this.$refs.ID就可以访问该组件
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <div id="app"> <cpn></cpn> <cpn></cpn> <my-cpn></my-cpn> <y-cpn></y-cpn> <cpn ref="xiaojian"></cpn> </div> <template id="cpn"> <div>我是子组件</div> </template> <script src="../js/vue.js"></script> <script type="text/javascript"> var app= new Vue({ el: "#app", data: { message: "hello vue" }, methods:{ btnClick(){ //2.$refs 对象类型 默认的是一个空的对象 console.log(this.$refs.xiaojian.name) } }, components: { cpn: { template: '#cpn', data(){ return{ name: '我是子组件的name' } }, methods: { showMessage(){ console.log('showMessage!!!') } } } } }) </script> </body> </html>
2. 子组件访问父组件
- 在开发中我们可以通过$parent来控制子组件访问父组件
- 但是子组件应该尽量避免直接访问父组件的数据,这样代码间的耦合度太高
- 通过$parent 可能直接修改父组件的状态,这样的话父组件的状态将会变得飘忽不定,很不利于维护和开发
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<div id="app">
<cpn></cpn>
</div>
<template id="cpn">
<div>
<h2>我是cpn组件</h2>
<ccpn></ccpn>
</div>
</template>
<template id="ccpn">
<div>
<h2>我是ccpn子组件</h2>
<button @click="btnClick">按钮</button>
</div>
</template>
<script src="../js/vue.js"></script>
<script type="text/javascript">
var app= new Vue({
el: "#app",
data: {
message: "hello vue"
},
components:{
cpn: {
template:'#cpn',
data(){
return{
name: '我是父组件的cpn'
}
},
components: {
ccpn: {
template: '#ccpn',
methods:{
btnClick(){
console.log(this.$parent.name);
console.log(this.$root.message)
}
}
}
}
}
}
})
</script>
</body>
</html>