*子组件实例里写props对象,绑定属性,属性里可设置传入的数据类型和无数据传入时的默认值
*子组件里绑定属性接受父组件传来的数据
*将数据展示在页面中
//body
<div id="app">
<h2>这是app组件</h2>
<child1 :child1msg="msg1" :child1-obj="obj"></child1>
</div>
<template id="child1">
<fieldset>
<legend><h2>这是child1组件</h2></legend>
<p>父组件传入的值是:{{child1msg}}</p>
<ul>
<li v-for="(v,k) in child1Obj">{{v+'---'+k}}</li>
</ul>
<button @click="useParentFunc">点击调用父组件的方法</button>
</fieldset>
</template>
//script
let child1 = {
template:"#child1",
props:{
//props里属性名建议全小写字母,可以写成驼峰,但是驼峰的属性名在使用时,所有的单词首字母小写,中间加 - .
child1msg:{
type:String,
default:"无"
},
child1Obj:{
type:Object,
default(){
return {
name:'你好',
age:0,
sex:'未知'
}
}
},
},
methods: {
useParentFunc(){
/*
* 子组件如何获取父组件的方法(实例)?
* 1. $parent: 访问当前组件的父组件实例
* 2. $root: 访问根组件实例
* */
console.log(this.$parent, this.$root);
console.log(this.$parent.sendMsg());
}
}
};
let app = new Vue({
el:'#app',
data:{
msg1:"app的msg1数据",
obj:{
name:'卡卡西',
age:27,
sex:'男'
}
},
methods:{
sendMsg(){
return '这是父组件sendMsg方法返回的数据';
}
},
components:{
child1
}
2. 子向父传值
Vue里, 子组件向父组件传值 使用的是事件发送和事件监听 子组件里发送事件,父组件里监听对应的子组件事件接收数据
父组件里获取child1的实例, 通过 $refs属性获取对应组件里的子组件
*在点击事件里通过$emit自定义事件,将要传递的参数传给监听器
*在子组件里绑定自定义事件,并定义方法接受收子组件传来的数据,方法里有形参.
*在父组件里定义该方法,参数为子组件传来的数据,在父组件里定义一个变量接收子组件传来的数据
//2.
<template id="child1">
<fieldset>
<legend><h2>这是child1组件</h2></legend>
<button @click="sendMsgToApp">点击按钮向父组件发送消息</button>
</fieldset>
</template>
//1.
let child1 ={
template:'#child1',
data(){
return {
child1Msg: "这是child1的msg数据"
}
},
methods: {
sendMsgToApp(){
//发送消息, 事件名不能写成驼峰结构
this.$emit("child1-event",this.child1Msg);
},
}
};
//3.
let app = new Vue({
el:'#app',
data:{
appMsg:'',
randomNum:0
},
methods:{
getMsg(data){
console.log(data);
this.appMsg=data;
},
},
components:{
child1
}
});
3. 兄弟之间传值--中间人模式
1). 子向父传值
2). 父向子传值
上代码:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>兄弟组件传值_中间人模式</title>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
</head>
<body>
<div id="app">
<child1 @child-event="getChild1($event)"></child1>
<child2 :child2msg="appMsg"></child2>
</div>
<template id="child1">
<fieldset>
<legend><h2>这是child1组件</h2></legend>
<button @click="sendMsgToC2">点击向child2组件发送数据</button>
</fieldset>
</template>
<template id="child2">
<fieldset>
<legend><h2>这是child2组件</h2></legend>
<p>这是child1组件传递的数据: {{child2msg}}</p>
</fieldset>
</template>
<script type="text/javascript">
let child1={
template:'#child1',
data(){
return {
child1Msg:'这是child1的msg数据'
}
},
methods: {
sendMsgToC2(){
this.$emit('child-event',this.child1Msg)
}
}
};
let child2={
template:'#child2',
data(){
return {}
},
props:{
child2msg:{
type:String,
default:'无数据'
}
}
};
let app = new Vue({
el:'#app',
data:{
appMsg:''
},
methods:{
getChild1(data){
this.appMsg=data;
}
},
components:{
child1,
child2
}
});
</script>
</body>
</html>
4. 兄弟组件传值--消息发送
新建一个Vue实例,利用该实例发送消息,还利用该实例接收消息
* 在传递数据的子组件child1里定义点击事件,绑定事件,监听数据
* 在接收数据的子组件child2组件创建完毕之后(created)里监听自定义事件,并创建函数回调child1传递来的数据
* 将创建的函数写进child2的方法里,并定义变量接收数据. 显示在页面中
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>兄弟组件传值_消息发送</title>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
</head>
<body>
<div id="app">
<child1></child1>
<child2></child2>
</div>
<template id="child1">
<fieldset>
<legend><h2>这是child1组件</h2></legend>
<button @click="sendMsgToChild2">点击向child2组件发送数据</button>
</fieldset>
</template>
<template id="child2">
<fieldset>
<legend><h2>这是child2组件</h2></legend>
<p>这是child1组件传递的数据: {{child2Msg}}</p>
</fieldset>
</template>
<script type="text/javascript">
//新建一个vue实例
let totalVue = new Vue();
let child1={
template:'#child1',
data(){
return {
child1Msg:'这是child1里的数据msg',
}
},
methods: {
sendMsgToChild2(){
totalVue.$emit("child1-event",this.child1Msg);
}
}
};
let child2={
template:'#child2',
//在child2组件实例化完毕之后历可监听child1-event事件
created(){
totalVue.$on("child1-event",this.getChild1Msg)
},
data(){
return {
child2Msg:''
}
},
methods:{
getChild1Msg(data){
console.log(data)
this.child2Msg=data
}
}
};
let app = new Vue({
el:'#app',
data:{
} ,
methods:{
},
components:{
child1,
child2
}
});
</script>
</body>
</html>
5. Vue插槽
插槽slot: slot的作用: 用来接收写在组件里的内容,这些内容会进入到slot里进行显示
5.1 普通插槽
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>普通插槽</title>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
</head>
<body>
<div id="app">
<child1>
<ul>
<li>这是列表项1</li>
</ul>
</child1>
</div>
<template id="child1">
<fieldset>
<legend><h2>这是child1组件</h2></legend>
<p>这是child1的p标签</p>
<slot></slot>
</fieldset>
</template>
<script type="text/javascript">
let child1={
template:'#child1',
data(){
return {}
}
};
let app = new Vue({
el:'#app',
components:{
child1,
}
});
</script>
</body>
</html>
5.2 具名插槽
给模板里的slot组件添加name属性,表示插槽的名字,在传入的内容标签设置slot属性,值相同进入对应的slot. 凡是没有设置slot属性的标签统统会进入到没有设置name属性的slot组件里
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>具名插槽</title>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
</head>
<body>
<div id="app">
<child2>
<h3 slot="content">这是内容的h2</h3>
<h3 slot="foot">这是尾部的h2</h3>
<h3 slot="head">这是头部的h2</h3>
</child2>
</div>
<template id="child2">
<fieldset>
<legend><h2>这是child2组件</h2></legend>
<slot name="head"></slot>
<slot name="content"></slot>
<slot name="foot"></slot>
</fieldset>
</template>
<script type="text/javascript">
let child2={
template: '#child2'
};
let app = new Vue({
el:'#app',
components:{
child2,
}
});
</script>
</body>
</html>
自 Vue2.6.0 起 v-slot 指令被引入,提供更好的支持 slot 和 slot-scope 特性的 API 替代方案.具体写法如下:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>具名插槽新写法</title>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
</head>
<body>
<div id="app">
<child1>
<template v-slot:header>
<h1>Here might be a page title</h1>
</template>
<p>A paragraph for the main content.</p>
<p>And another one.</p>
<!--简写-->
<template #footer>
<p>Here's some contact info</p>
</template>
</child1>
</div>
<template id="child1">
<div class="container">
<header>
<slot name="header"></slot>
</header>
<main>
<slot></slot>
</main>
<footer>
<slot name="footer"></slot>
</footer>
</div>
</template>
<script type="text/javascript">
let child1={
template:'#child1'
};
let app = new Vue({
el:'#app',
components:{
child1,
}
});
</script>
</body>
</html>
5.3 作用域插槽
默认情况下,组件里的内容要绑定数据,其作用域是父级的作用域,如果想让器对应组建的作用域起效果需要使用作用域插槽写法
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>作用域插槽</title>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
</head>
<body>
<div id="app">
<child3>
<!--slot-scope 用来接收插槽的属性-->
<template slot-scope="data">
<p>这是p元素, 姓名是:{{data.c3Name}}, 年龄是:{{data.c3Age}}</p>
</template>
</child3>
</div>
<template id="child3">
<fieldset>
<legend><h2>这是child3组件</h2></legend>
<slot :c3-name="name" :c3-age="age"></slot>
</fieldset>
</template>
<script type="text/javascript">
let child3={
template: '#child3',
data(){
return {
name:'漩涡鸣人',
age:16
}
}
};
let app = new Vue({
el:'#app',
components:{
child3,
}
});
</script>
</body>
</html>
自 Vue2.6.0 起在<template>上使用特殊的 slot-scope 特性可以接收传递给插槽的prop(把这里提到过的 <slot-example> 组件作为示例):
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>作用域插槽</title>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
</head>
<body>
<div id="app">
<child2>
<template v-slot:default="slotProps">
<p>名字是: {{slotProps.user.name}}</p>
<p>类型是: {{slotProps.user.type}}</p>
</template>
</child2
</div>
<template id="child2">
<div>
<h2>这是child2</h2>
<slot :user="child2Obj"></slot>
</div>
</template>
<script type="text/javascript">
let child2={
template:'#child2',
data(){
return {
child2Obj:{
name:'child2',
type:'组件'
}
}
}
};
let app = new Vue({
el:'#app',
components:{
child2,
}
});
</script>
</body>
</html>
用到更多:
* vue实例.$emit('自定义事件名',要传送的数据);
触发当前实例上的事件,要传递的数据会传给监听器;
* vue实例.$on('事件名',callback)---callback回调$emit要传送的数据; 监听当前实例上自定义事件;