VUE组件之间的通信

一、 组件component

1. 什么是组件?

组件(Component)是 Vue.js 最强大的功能之一。组件可以扩展 HTML 元素,封装可重用的代码
组件是自定义元素(对象)

2. 定义组件的方式

方式1:先创建组件构造器,然后由组件构造器创建组件
    var mycomponent=Vue.extend({
        template:''
    })
    Vue.component('组件名',mycomponent)
方式2:直接创建组件
    Vue.component('组件名',{
        template:''
    })

3. 组件的分类

分类:全局组件、局部组件
全局组件:
    Vue.component('组件名',{
        template:''
    })
局部组件:
    在vue实例中写components:{
        mycomponent: {
            template:'',
            data() { // data必须是函数,值需return返回,data属性默认为当前组件私有,其他组件不能调用
                return {}
            }
        }
    }

4. 引用模板

将组件内容放到模板<template>中并引用
html:
    <template id='template'>
        <div></div>有且只有一个根元素
    </template>
vue:
    Vue.component('组件名',{
        template: '#template'
    })

5. 动态组件

<component :is="">组件 多个组件使用同一个挂载点,然后动态的在它们之间切换
如:
<div id="itany">
	<button @click="flag='my-hello'">显示hello组件</button>
	<button @click="flag='my-world'">显示world组件</button>


	<div>
		<!-- 使用keep-alive组件缓存非活动组件,可以保留状态,避免重新渲染,默认每次都会销毁非活动组件并重新创建 -->
		<keep-alive>
			<component :is="flag"></component>	
		</keep-alive>
	</div>
</div>

<script>
	var vm=new Vue({
		el:'#itany',
		data:{
			flag:'my-hello'
		},
		components:{
			'my-hello':{
				template:'<h3>我是hello组件:{{x}}</h3>',
				data(){
					return {
						x:Math.random()
					}
				}
			},
			'my-world':{
				template:'<h3>我是world组件:{{y}}</h3>',
				data(){
					return {
						y:Math.random()
					}
				}
			}
		}
	});	
</script>
<keep-alive>
    <component></component>
</keep-live>   使用keep-alive组件缓存非活动组件,可以保留状态,避免重新渲染,默认每次都会销毁非活动组件并重新创建

二、 组件间数据传递

1. 父子组件

在一个组件内部定义另一个组件,称为父子组件
子组件只能在父组件内部使用
默认情况下,子组件无法访问父组件中的数据,每个组件实例的作用域是独立的
父组件调用子组件需要在父组件的template中调用即:
<template>
    <h1>我是父组件</h1>
    <my-word></my-word> // 此处调用子组件
</template>

2. 组件间数据传递 (通信)

2.1 子组件访问父组件的数据
a)在调用子组件时,绑定想要获取的父组件中的数据
b)在子组件内部,使用props选项声明获取的数据,即接收来自父组件的数据
总结:父组件通过props向下传递数据给子组件
注:组件中的数据共有三种形式:data、props、computed
如:
父组件:
    html部分:<my-hello :msg='msg'></my-hello>
    vue: data(){ return { msg: 'lll'}}
子组件:
    html部分: {{msg}}
    vue: props:{ ['msg']} 接收父组件传递的值
props注:
    props的type是对象或者数组默认值必须使用函数的形式来返回
    props:{
        name: {
            type: String, // 类型
            default: '默认值',
            required: true, // 是否是必须有的值
            validator(){} // 判断值的函数
        }
    }
2.2 父组件访问子组件的数据
a)在子组件中使用vm.$emit(事件名,数据)触发一个自定义事件,事件名自定义
b)父组件在使用子组件的地方监听子组件触发的事件,并在父组件中定义方法,用来获取数据
总结:子组件通过events给父组件发送消息,实际上就是子组件把自己的数据发送到父组件
父组件:
    html:
        <h1>{{msg}}</h1>
        <my-word @e-word="getData"></my-word>
    vue: 
        methods:{
            getData(msg){ this.msg=msg}
        }
子组件:
    html:
        <button @click="sendData">发送数据</button>
    vue:
        methods:{
            sendData(){
                this.$emit('e-word',this.msg)// 传递多个值以,隔开
            }
        }

3. 单向数据流

props是单向绑定的,当父组件的属性变化时,将传导给子组件,但是不会反过来
而且不允许子组件直接修改父组件中的数据,报错
解决方式:
    方式1:如果子组件想把它作为局部数据来使用,可以将数据存入另一个变量中再操作,不影响父组件中的数据
        如:
            父组件:
                html:
                    <my-hello :age="age"></my-hello>
            子组件:
                html:<button @click='change'>改变值</button>
                vue:
                 new Vue({
                     data:{
                         uage:this.age
                     },
                     props:                            ['age'],
                     methods:{
                         change(){
                            this.uage=18
                         }
                     }
                 })
    方式2:如果子组件想修改数据并且同步更新到父组件,两个方法:
        a.使用.sync(1.0版本中支持,2.0版本中不支持,2.3版本又开始支持)
            需要显式地触发一个更新事件
            父组件:
                html:
                    <my-hello :name.sync="name" ></my-hello>
            子组件:
                html:
                    <h1>{{name}}</h1>
                    <button @click='change'></button>
                vue:
                    props:['name'],
                    methods:{
                        change(){
                            this.$emit('update:name','alice')
                        }
                    }
            
        b.可以将父组件中的数据包装成对象,然后在子组件中修改对象的属性(因为对象是引用类型,指向同一个内存空间),推荐   
            父组件:
                html:
                    <my-word :user='user'></my-word>
                vue:
                    data(){
                        return{
                            user:{
                                name: 'karry',
                                age: 18
                            }
                        }
                    }
            子组件:
                html:
                    <h1>{{user.name}}</h1>
                    <button @click="change"></button>
                vue:
                    props:['user']
                    methods:{
                        change(){
                            this.user.name='roy'
                        }
                    }

4. 非父子组件间的通信

非父子组件间的通信,可以通过一个空的Vue实例作为中央事件总线(事件中心),用它来触发事件和监听事件

var Event=new Vue();
Event.$emit(事件名,数据);
Event.$on(事件名,data => {});
<div id="itany">
	<my-a></my-a>
	<my-b></my-b>
	<my-c></my-c>
</div>

<template id="a">
	<div>
		<h3>A组件:{{name}}</h3>
		<button @click="send">将数据发送给C组件</button>
	</div>
</template>

<template id="b">
	<div>
		<h3>B组件:{{age}}</h3>
		<button @click="send">将数组发送给C组件</button>
	</div>
</template>

<template id="c">
	<div>
		<h3>C组件:{{name}}{{age}}</h3>
	</div>
</template>

<script>
	//定义一个空的Vue实例
	var Event=new Vue();

	var A={
		template:'#a',
		data(){
			return {
				name:'tom'
			}
		},
		methods:{
			send(){
				Event.$emit('data-a',this.name);
			}
		}
	}
	var B={
		template:'#b',
		data(){
			return {
				age:20
			}
		},
		methods:{
			send(){
				Event.$emit('data-b',this.age);
			}
		}
	}
	var C={
		template:'#c',
		data(){
			return {
				name:'',
				age:''
			}
		},
		mounted(){ //在模板编译完成后执行
			Event.$on('data-a',name => {
				this.name=name;
				// console.log(this);
			});

			Event.$on('data-b',age => {
				this.age=age;
			});
		}
	}

	var vm=new Vue({
		el:'#itany',
		components:{
			'my-a':A,
			'my-b':B,
			'my-c':C
		}
	});	
</script>

三、 slot内容分发

本意:位置、槽
作用:用来获取组件中的原内容,类似angular中的transclude指令

<style>
.s2{
	width:100px;
	background:red;
	margin-left:10%;
}
</style>
<body>
<div id="itany">
	<my-hello>
		<ul slot="s1">
			<li>aaa</li>
			<li>bbb</li>
			<li>ccc</li>
		</ul>
		<ol slot="s2">
			<li>111</li>
			<li>222</li>
			<li>333</li>
		</ol>
	</my-hello>
</div>

<template id="hello">
	<div>
		<div  class="s2">
		<slot name="s2"></slot>
		</div>
		<h3>welcome to itany</h3>
		<!-- <slot>如果没有原内容,则显示该内容</slot> -->
		<slot name="s1"></slot>
	</div>
</template>

<script>

	var vm=new Vue({
		el:'#itany',
		components:{
			'my-hello':{
				template:'#hello'
			}
		}
	});	
</script>
</body>
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值