组件数据的存放
- 组件不可以访问Vue实例数据
- 组件对象也有一个data属性(也可以有methods等属性)
- 只是这个data属性必须是一个函数,而且这个函数返回一个对象,对象内部保存着数据
为什么data在组件中必须是一个函数呢?原因是在于Vue让每个组件对象都返回一个新的对象,因为如果是同一个对象的,组件在多次使用后会相互影响。下面计数器的例子可以很好的说明这个问题
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59
| <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> </head> <body> <div id='app'> <cpn></cpn> <cpn></cpn> <cpn></cpn> </div> <template id="div1"> <!-- 访问vue实例中的数据,不能显示 --> <!-- <h1>{{message}}</h1> --> <!-- 访问cpn组件中的数据,能显示 --> <!-- <h1> {{message}}</h1> --> <div> <h3>{{count}}</h3> <button @click=count++>+</button> <button @click=count-->-</button> </div> </template> <script src='https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js'></script> <script> const app = new Vue({ el: '#app', data :{ message: '你好!!!'
}, components: { 'cpn':{template: '#div1', data(){ return{ message: "你好!!我是组件中的数据!!!", count: 0, } }, } }
}) </script> </body> </html>
|
父子组件通信
1.通过props向子组件传递数据
props基本用法
在组件中,使用选项props来声明需要从父级接收到的数据。
props的值有两种方式:
方式一:字符串数组,数组中的字符串就是传递时的名称。
方式二:对象,对象可以设置传递时的类型,也可以设置默认值等。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34
| <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> </head> <body> <div id='app'> <cpn :childmessage="message"> </cpn> </div> <template id="div1"> <div> <h3>{{childmessage}}</h3> </div> </template> <script src='https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js'></script> <script> const app = new Vue({ el: '#app', data :{ message: '你好!!!我是父组件的数据' }, components: { 'cpn':{ template: '#div1', props: ['childmessage'] } } }) </script> </body> </html>
|
1 2 3 4 5 6 7 8 9
| props: { title: String, likes: Number, isPublished: Boolean, commentIds: Array, author: Object, callback: Function, contactsPromise: Promise }
|
2.通过事件向父组件发送消息
自定义事件的流程:
在子组件中,通过$emit()来触发事件。
在父组件中,通过v-on来监听子组件事件。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64
| <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> </head> <body>
<div id='app'> <!-- 监听事件 --> <cpn @item-click="change"></cpn> <h1>我是传过来的id:{{Fid}}</h1> </div> <template id="div1"> <div> <button v-for="item in categrories" @click="transfer(item)"> {{item.name}}</button> {{Transferid}} </div> </template> <script src='https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js'></script> <script> const app = new Vue({ el: '#app', data :{ Fid: '' }, methods:{ change(item){ console.log(item.name) this.Fid = item.id } }, components:{ 'cpn':{ template:'#div1', data(){ return{ categrories:[ {id: 'aaa',name: '热门推荐'}, {id: 'bbb',name: '手机数码'}, {id: 'ccc',name: '家用家电'}, {id: 'ddd',name: '电器办公'}, {id: 'eee',name: '服装热卖'}
], Transferid: 0 } }, methods:{ transfer(item){ this.Transferid = item.id this.$emit('item-click',item) } } } } }) </script> </body> </html>
|
父子组件的访问方式
父组件访问子组件:使用$children或$refs
this.$children是一个数组类型,它包含所有子组件对象。可以通过一个遍历,取出所有子组件的message状态。
$children的缺陷:
通过$children访问子组件时,是一个数组类型,访问其中的子组件必须通过索引值。但是当子组件过多,我们需要拿到其中一个时,往往不能确定它的索引值,甚至还可能会发生变化。有时候,我们想明确获取其中一个特定的组件,这个时候就可以使用$refs
$refs的使用:
- $refs和ref指令通常是一起使用的。
- 首先,我们通过ref给某一个子组件绑定一个特定的ID。
- 其次,通过this.$refs.ID就可以访问到该组件了。
子组件访问父组件:使用$parent
- 尽管在Vue开发中,我们允许通过$parent来访问父组件,但是在真实开发中尽量不要这样做。子组件应该尽量避免直接访问父组件的数据,因为这样耦合度太高了。
- 如果我们将子组件放在另外一个组件之内,很可能该父组件没有对应的属性,往往会引起问题。
- 另外,更不好做的是通过$parent直接修改父组件的状态,那么父组件中的状态将变得飘忽不定,很不利于我的调试和维护。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78
| <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> </head> <body> <!-- 父组件 --> <div id='app'> <cpn1 ref="cpn1"> </cpn1> <button @click="parentclick">显示所有子组件信息</button> </div> <!-- 子组件1 --> <template id="div1"> <div> <h1>{{message}}</h1> <cpn2 ref="cpn2"></cpn2> </div> </template> <!-- 子组件2 --> <template id="div2" > <div> <h1>{{message}}</h1> <button @click="cpn2click">显示父组件信息</button> </div> </template> <script src='https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js'></script> <script> const app = new Vue({ el: '#app', data :{ message: '我是根组件,组件1的父组件' }, methods:{ parentclick(){ for(let i=0;i<this.$children.length;i++){ console.log(this.$children[i].message) } console.log(this.$refs.cpn1.message) } }, components:{ 'cpn1': { template:'#div1', data(){ return{ message: '我是组件1,是根组件的子组件,组件2的父组件' } }, components:{ 'cpn2': { template:'#div2', data(){ return{ message: '我是组件2' } }, methods:{ cpn2click(){ console.log(this.$parent.message) console.log(this.$root.message) } } } } }, } }) </script> </body> </html>
|