Vue组件二——data选项、局部组件、组件通信

data选项

  • data选项用于储存组件数据

与实例data差别

  1. 必须存储在有返回值的函数当中
  2. 数据设置在返回值对象里
1、方式一             
data:function(){
    return{
        title:"组件标题",
        content:"组件内容"
    }
}
2、ES6的简写方式
data(){
    return{
        title:"组件标题",
        content:"组件内容"
    }
}

作用:确保每个组件实例单独维护一份返回对象的独立拷贝,相互之间不受影响(因为函数内部是单独的作用域)

Props选项

props命名规则

示例:我想跳转
建议prop定义时命名采用camelCase(驼峰命名),父组件绑定时使用kebab—case(因为html的属性不区分大小写)

局部注册

  • 局部注册组件只能作用在当前实例或组件中

挂载在id为app的实例中的组件ComA,ComB只能在app实例内使用

<div id="app">
    <com-a></com-a>
    <com-b></com-b>
</div>

方式一:在实例内部定义

		<script type="text/javascript">
			new Vue({
				el:"#app",
				components:{
					'ComA':{
						template:"<div>{{word}}</div>",
						data:function(){
							return{
								word:"this is A Compotent"
							}
						}
					},
					'ComB':{
						template:"<div>{{word}}</div>",
						data:function(){
							return{
								word:"this is B Compotent"
							}
						}
					},
				}
			})
		</script>

方式二:在实例外单独定义,实例内调用

		<script type="text/javascript">
			var ComA ={
							template:"<div>{{word}}</div>",
							data:function(){
								return{
									word:"this is A Compotent"
								}
							}
						};
			var ComB = {
				template:"<div>{{word}}</div>",
				data:function(){
					return{
						word:"this is B Compotent"
					}
				}
			};			
			new Vue({
				el:"#app",
				components:{
                    //—kabak命名必须带'',pascal命名法可不带引号
					'com—a':ComA,
					 ComB:ComB
				}
			})
		</script>

ES6简写:

要求:组件定义的名称必须符合pascal命名规则

			new Vue({
				el:"#app",
				components:{
					ComA,
					ComB
				}
			})

效果:

this is A Compotent

this is B Compotent

组件通信

组件通信——组件间传递数据的操作

常见类型:

  • 父组件向子组件传值
  • 子组件向父组件传值
  • 非父子组件传值
  • 其他通信方式

父组件向子组件传值

  1. 通过子组件的props选项参数接收父组件的传值
  2. 传值的类型可以是是值类型,也可以是数组及对象

三种传值方式:

  • 直接赋值
  • 传匿名值变量
  • 传父实例变量,随父组件数据值的变化而改变
		<div id="app">
			<!--直接赋值—— props里的title直接赋值-->
			<com-a my-title = "直接赋值的标题"></com-a>
			<!--匿名值变量—— 相当于将值为'这是静态标题'的匿名变量赋值给props里的title -->
			<com-a v-bind:my-title="'这是静态标题'"></com-a>
			<!-- 将父实例数据title、content这两个变量赋值给props里的title、words -->
			<com-a :my-title="title" :words="content"></com-a>	
		</div>
    	<script type="text/javascript">
		Vue.component('ComA',{
                        props:['myTitle','words'],
						template:`<div>
						<h3>{{title}}</h3>
						<p>{{words}}</p>
						</div>`
					});
			new Vue({
				el:"#app",
				data:{
					title:"全局标题",
					content:"全局内容"
				}
			})
		</script>
v-for在传值中的应用
		<div id="app">
			<com-a v-for="item in items" :key="item.title"
			:item-title="item.title"
			:item-words="item.content"
			:item="item"
			></com-a>
		</div>
			<script type="text/javascript">
			Vue.component('ComA',{
							props:['itemTitle','itemWords','item'],
							template:`<div>
							<h3>{{itemTitle}}</h3>
							<p>{{item.content}}</p>
							</div>`
						});
				new Vue({
					el:"#app",
					data:{
						items:[
							{
								title:"全局标题1",
								content:"全局内容1"
							},
							{
								title:"全局标题2",
								content:"全局内容2"
							},
							{
								title:"全局标题3",
								content:"全局内容3"
							}
						]
						
					}
				})
			</script>

子组件向父组件传值

自定义触发事件

子组件向父组件传值需要自定义事件

  1. 子组件数据变化时,通过$emit() 触发自定义事件
  2. 自定义事件名称建议使用kebab-case

具体步骤:

  1. 在子组件的方法里通过$emit() 自定义触发事件名称
  2. 在子组件实例html上指定自定义触发事件名称对应的响应函数或表达式
  3. 在父组件定义函数的具体内容(如果响应是表达式此步骤省略)
		<div id="app">
			<!-- 2、在自定义组件里声明这个事件对应的函数或者表达式 -->
			<com-a v-for="item in items" :key="item.id"
			:item-title="item.title"
			@count-change="TotalCount++"
			></com-a>
          <span>TotalCount:{{TotalCount}}</span>
		</div>
			<script type="text/javascript">
			Vue.component('ComA',{
							props:['itemTitle','itemWords','item'],
							template:`<div>
							<div >
								<span>{{itemTitle}}</span>
								<span>{{count}}</span>
								<button type="button" @click="countIns">+1</button>
							</div>
							</div>`,
							data(){
								return {
									count:0
								}
							},
							methods:{
								'countIns':function(){
									//1、通过emit自定义一个事件count-change
									this.$emit('count-change');
									this.count++;
								}
							}
						});
				new Vue({
					el:"#app",
					data:{
						items:[
							{
								title:"苹果",
								id:"1"
							},
							{
								title:"香蕉",
								id:"2"
							},
							{
								title:"芒果",
								id:"3"
							}
						],
						TotalCount:0
						
					},
					methods:{
						totalchange:function(){
							
							this.TotalCount++;
						}
					}
				})
			</script>

效果:

$emit详解

1、无参数(参考上述例子)

  • 定义:

    this.$emit('count-change');
    

    指定(此处指定的是表达式):

    <com-a v-for="item in items" :key="item.id"
    			:item-title="item.title"
    			@count-change="TotalCount++"
    			></com-a>
    

2、带参数,通过$event去接收参数

  • 定义:

    this.$emit('count-change',5);
    
  • 指定(此处指定的是函数):

    			<com-a v-for="item in items" :key="item.id"
    			:item-title="item.title"
    			@count-change="totalchange($event)"
    			></com-a>
    
  • 在父组件定义对应的响应函数totalchange

    methods:{
    						// 3、在父组件定义触发事件对应的函数
    						totalchange:function(num){	
    							this.TotalCount+= num;
    						}
    					}
    

效果:

非父子组件传值

分类

  • 兄弟组件

  • 完全无关的组件

兄弟组件传值

思路1:通过父组件进行数据中转

思路n....

如下图思路:

  1. 首先通过com-a传值给父组件data里的value接收
  2. 将父组件的value传给com-b组件里props里的val接收
<div id="app">
			<com-a @count-change="value=$event"></com-a>
			<com-b :val="value"></com-b>
		</div>
new Vue({
    el:"#app",
    data:{
        items:[
            value:""
        ]				
    }
})

完整代码:

		<div id="app">
			<com-a @title-change="value=$event"></com-a>
			<com-b :val="value"></com-b>
		</div>
    <script type="text/javascript">
        Vue.component('ComA',{
        template:`<div>
                <h3>这是组件A的标题:{{title}}</h3>
                <button type="button" @click="countIns">传值</button>
                </div>`,
        data(){
            return {
                title:"生日快乐"
            }
        },
        methods:{
            countIns(){
                this.$emit('title-change',this.title);
            }
        }
    });
    Vue.component('ComB',{
        props:['val'],
        template:`<div>
                <h3>这是组件B的标题:{{val}}</h3>
                </div>`
    });			

    new Vue({
        el:"#app",
        data:{
            value:""			
        }
    })
    </script>

效果:

完全无关组件传值(EventBus)

定义

EventBus(事件总线),类似数据搬运工、邮递员的角色

  • 一个独立的事件中心
  • 用于管理不同组件间的传值操作。
形式
  • 通过Vue实例来管理传值操作
  • 通过注册事件、调用事件来实现数据传递
  • 发送组件——触发bus事件,通过$emit去触发
    接收组件——给bus注册对应事件,通过$on去注册接收函数
步骤
  1. 新建一个Eventbus.js,定义一个bus的实例

    // 定义eventBus实例
    var bus = new Vue();
    
  2. 在html里引入EventBus.js

    	<head>
    		<meta charset="utf-8">
    		<title></title>
    		<script src="vue.js" type="text/javascript" charset="utf-8"></script>
    		<!-- 1、引入定义的eventbus -->
    		<script src="EventBus.js" type="text/javascript" charset="utf-8"></script>
    	</head>
    
  3. 组件里触发和注册

    		<div id="app">
    			<com-a :my-title="title"></com-a>
    			<com-b></com-b>
    		</div>
    
    		<script type="text/javascript">
    		// 传递组件A
    			Vue.component('com-a',{
    				props:['myTitle'],
    				template:`<div>
    								<span>{{myTitle}}</span>
    								<span>{{count}}</span>
    								<button type="button" @click="countIns">+1</button>
    							</div>`,
    				data(){
    					return{
    						count:0
    					}
    				},
    				methods:{
    					countIns(){
    						//2、传递者——定义触发事件
    						bus.$emit('count-change',1);
    						this.count++;
    					}
    				}
    							
    							
    			});
    		//接收组件B	
    			Vue.component('com-b',{
    				
    				template:`<div>
    								<span>totalCount:{{totalCount}}</span>
    						</div>`,
    				data(){
    					return {
    						totalCount:0
    					}
    				},
    				created() {
    					//ES6的写法
    					// bus.$on('count-change',num=>{
    					// 	console.log(this.totalCount);
    					// 	this.totalCount += num;
    					// });
    					// 注意和上面ES6写法的区别,此处方法内的this是指的函数,不能通过this.totalCount取到值
    					var t =this;
    					//3、接收者——通过$on获取值
    					bus.$on('count-change',function(num){
    						console.log(this);
    						t.totalCount += num;
    					});			
    				}		
    			});
    			new Vue({
    				el:"#app",
    				data:{
    					title:"苹果",
    					id:1,
    					totalCount:0
    				}
    			});
    		</script>
    

    效果: