一.父子组件
1.什么是父子组件?
就是在组件中又定义了其他组件
其实局部组件就是最简单的子组件,因为把Vue实例看做一个大的父组件
在Vue中的局部组件就相当于大组件中的小组件,这就是最简单的局部组件
2.如何定义其他父子组件
自定义组件可以使用data,可以使用methods,当然自定义组件还可以使用components
如果把创建的Vue实例对象当做父组件,那么在Vue实例对象中创建的局部组件components就是子组件;如果在局部组件中再次创建components就是孙子组件,此时的Vue实例对象就相当于爷爷组件,在Vue实例对象中创建的局部组件components就是父组件;
<div id="app">
<abc></abc>
</div>
<template id="father">
<div>
<p>我是父组件</p>
<def></def>
</div>
</template>
<template id="son">
<div>
<p>我是子组件</p>
</div>
</template>
<script>
//创建Vue的实例对象
let vue = new Vue({
el:"#app",
data:{ },
methods:{},
computed:{ },
//专门用于定义局部组件
components:{
"abc":{
template: "#father",
components:{
"def":{
template: "#son"
}
}
}
}
});
</script>
二.父组件向子组件传递数据(data)
1.如何传递数据
1.1在父组件中通过v-bind传递数据
传递格式 v-bind:自定义接收名称 = "要传递数据"
1.2在子组件中通过props接收数据
接收格式 props: ["自定义接收名称"]
<div id="app">
<father></father>
</div>
<template id="father">
<div>
<!--注意点: 组件是可以使用自己的数据的-->
<p>{{name}}</p>
<p>{{age}}</p>
<!--这里将父组件的name通过parentname传递给了子组件-->
<son :parentname="name" :abc="age"></son>
</div>
</template>
<template id="son">
<div>
<!--这里通过parentname使用了父组件传递过来的数据-->
<p>{{parentname}}</p>
<p>{{abc}}</p>
</div>
</template>
<script>
// 父组件
Vue.component("father", {
template: "#father",
data: function(){
return {
name: "yaxi",
age: 20
}
},
// 子组件
components: {
"son": {
template: "#son",
// 这里通过parentname接收了父组件传递过来的数据
props: ["parentname", "abc"]
}
}
});
let vue = new Vue({
el: '#app',
data: { },
methods: { },
computed: { },
components: {}
});
</script>
三.父组件向子组件传递方法(methods)
1.如何传递方法
1.1在父组件中通过v-on传递方法
传递格式 v-on:自定义接收名称 = "要传递方法"
1.2在子组件中自定义一个方法
1.3在自定义方法中通过 this.$emit('自定义接收名称');触发传递过来的方法
<div id="app">
<father></father>
</div>
<template id="father">
<div>
<button @click="say">我是按钮</button>
<!--这里通过parentsay将父组件的say方法传递给子组件-->
<son @parentsay="say"></son>
</div>
</template>
<template id="son">
<div>
<button @click="sonFn">我是按钮</button>
</div>
</template>
<script>
// 父组件
Vue.component("father", {
template: "#father",
methods: {
say(){
alert("2541873074@qq.com")
}
},
// 子组件
components: {
"son": {
template: "#son",
methods:{
sonFn(){
this.$emit("parentsay");
}
}
}
}
});
let vue = new Vue({
el: '#app',
data: { },
methods: { },
computed: { },
components: { }
});
</script>
四.子组件向父组件传递数据(data)
1.如何将子组件数据传递给父组件
父组件先传递一个方法给子组件,子组件调用这个方法的时候传递参数给父组件,传递参数就是传递数据
<div id="app">
<father></father>
</div>
<template id="father">
<div>
<button @click="say">我是按钮</button>
<!--这里通过parentsay将父组件的say方法传递给子组件-->
<son @parentsay="say"></son>
</div>
</template>
<template id="son">
<div>
<button @click="sonFn">我是按钮</button>
</div>
</template>
<script>
// 父组件
Vue.component("father", {
template: "#father",
methods: {
//data:接受从子组件传递的参数
say(data){
console.log(data);
}
},
// 子组件
components: {
"son": {
template: "#son",
methods:{
sonFn(){
/*
this.$emit的第一个参数:需要调用的函数名称
this.$emit的后续的参数:给调用的函数传递的参数
*/
this.$emit("parentsay","鱿小鱼");
}
}
}
}
});
let vue = new Vue({
el: '#app',
data: {},
methods: {},
computed: {},
components: {}
});
</script>
五.组件中的命名注意点
1.注册组件的时候使用“驼峰命名”,使用组建的时候转换成“短横线分割命名”
例如:注册时:myFather -- 使用时:my-father
2.在传递参数的时候如果想使用“驼峰名称”,那么就必须写“短横线分割命名”
例如:传递时:parent-name="name" -- 接受时:props["parentName"]
3.在传递方法的时候不同使用“驼峰名称”,只能使用“短横线分割命名”
例如:传递时:@parent-say="say" -> 子组件的methods中:this.$emit("parent-say");
六.数据和方法的多级传递
在Vue中如果儿子想使用爷爷的数据,必须一层一层向下传递
在Vue中如果儿子想使用爷爷的方法,必须一层一层向下传递
<div id="app">
<grandfather></grandfather>
</div>
<template id="grandfather">
<div>
<p>{{name}}</p>
<button @click="say">我是按钮</button>
<father :gfname="name" @gfsay="say"></father>
</div>
</template>
<template id="father">
<div>
<p>{{gfname}}</p>
<button @click="fatherFn">我是按钮</button>
<son :fname="gfname" @fsay="fatherFn"></son>
</div>
</template>
<template id="son">
<div>
<p>{{fname}}</p>
<button @click="sonFn">我是按钮</button>
</div>
</template>
<script>
// 爷爷组件
Vue.component("grandfather", {
template: "#grandfather",
data:function(){
return{
name:"yaxi"
}
},
methods:{
say(){
console.log("我是爷爷的方法");
}
},
// 爸爸组件
components: {
"father": {
template: "#father",
props:["gfname"],
methods:{
fatherFn(){
this.$emit("gfsay");
}
},
//儿子组件
components:{
"son":{
template:"#son",
props:["fname"],
methods:{
sonFn(){
this.$emit("fsay");
}
}
}
}
}
}
});
let vue = new Vue({
el: '#app',
data: {},
methods: {},
computed: { },
components: {}
});
</script>
注意点:
1.如果想要在子组件中使用父组件中的数据,那么必须通过父组件传递
2.如果想要在子组件中使用祖先组件中的数据, 那么就必须一 层一 层的传递
3.兄弟组件之间不能直接传递数据,如果兄弟组件之间想要传递数据,那么就必须借助父组件
虽然通过借助父组件能够实现兄弟组件之间的数据传递,但是这种方式非常的复杂,非常的不推荐
那么当前在企业开发中我们遇到了两个问题:
1.如果想要在子组件中使用祖先组件中的数据,那么就必须一层一层的传递(非常麻烦)
2.兄弟组件之间不能直接传递数据,如果兄弟组件之间想要传递数据,那么就必须借助父组件(非常麻烦)
解决方案:使用Vuex
七.匿名插槽和具名插槽
1.默认情况下是不能在使用子组件的时候,给子组件动态添加内容,如果想在使用子组的时候,给子组件动态添加内容,那么就必须使用插槽;
<slot></slot>标签就是插槽,以后使用者可以根据自己的需求来填补;
注意点:
插槽可以指定默认数据,如果使用者没有填补插槽,那么就会显示默认数据,如果使用者填补了这个插槽,就会利用使用者填补的数据替换整个默认数据;
插槽可以指定名称,默认情况下如果没有指定名称,我们就称之为匿名函数;
默认情况下有多少个匿名插槽,我们填充的数据就会被拷贝多少份,导致了所有插槽中填充的内容都是一样的;
<div id="app">
<father></father>
</div>
<template id="father">
<div>
<!--需求:在使用子组件的时候给子组件动态的添加一下内容-->
<son>
<div>我是追加的内容1</div>
<div>我是追加的内容2</div>
<div>我是追加的内容3</div>
</son>
</div>
</template>
<template id="son">
<div>
<div>我是头部</div>
<!--匿名插槽的特点:有多少个匿名插槽,填充的数据就会拷贝几份
虽然我们可以指定多个匿名插槽,但企业开发中推进只写一个匿名插槽
-->
<slot>我是默认数据</slot>
<div>我是底部</div>
</div>
</template>
效果:
2.如果我们想给不同的插槽中填充不同的内容怎么办呢? 这个时候就可以使用具名插槽
具名插槽的使用:
通过插槽的name属性给插槽指定名称
在使用时可以通过slot=" name"方式,指定当前内容用于替换哪个插槽
注意点:如果没有指定要替换哪个插槽中的内容,则不会被替换
注意点: slot 属性在Vue2.6中已经被废弃,Vue2. 6之后使用v-slot指令替代slot属性
div id="app">
<father></father>
</div>
<template id="father">
<div>
<son>
<!--通过slot属性告诉Vue,当前的内容是要填充到哪一个插槽中的-->
<div slot="one">我是追加的内容1</div>
<div slot="one">我是追加的内容111</div>
<div slot="two">我是追加的内容2</div>
<div slot="two">我是追加的内容222</div>
</son>
</div>
</template>
<template id="son">
<div>
<div>我是头部</div>
<slot name="one">我是one默认数据</slot>
<slot name="two">我是two默认数据</slot>
<div>我是底部</div>
</div>
</template>
效果:
八.v-slot指令和作用域插槽
1.什么是v-slot指令?
v-slot指令是Vue2. 6中用于替代slot属性的一个指令
在Vue2.6之前,我们通过slot属性告诉Vue当前内容填充到哪一个具名插槽
从Vue2.6开始,我们通过v-slot指令告诉Vue当前内容填充到哪一个具名插槽
注意点: v-slot指令只能用在template标签上,#可以使用#号替代v-slot指令
<div id="app">
<father></father>
</div>
<template id="father">
<div>
<son>
<template #one>
<div>我是追加的内容1</div>
<div>我是追加的内容11</div>
</template>
<template #two>
<div>我是追加的内容2</div>
<div>我是追加的内容22</div>
</template>
</son>
</div>
</template>
<template id="son">
<div>
<div>我是头部</div>
<slot name="one">我是one默认数据</slot>
<slot name="two">我是two默认数据</slot>
<div>我是底部</div>
</div>
</template>
效果:
2..什么是作用域插槽
作用域插槽就是带数据的插槽,就是让父组件在填充子组件插槽内容时也能使用子组件的数据
3.如何使用作用域插槽
3.1在slot中通过v-bind:数据名称='数据名称”方式暴露数据
3.2在父组件中通过<template slot-scope=" 作用域名称">接收数据
3.2.1在父组件中还可以通过<template v-slot:插槽名称=" 作用域名称">接收数据 ; 匿名插槽的名称是default
3.2.2在父组件中也可以通过<template #插槽名称=" 作用域名称">接收数据 ; 在子组件中指定插槽名称 name="插槽名称"
4.作用域插槽的应用场景:子组件提供数据,父组件决定如何渲染
<div id="app">
<father></father>
</div>
<template id="father">
<div>
<son>
<!--slot-scope="abc" 接受子组件插槽暴露的数据-->
<!--
<template slot-scope="abc">
<li v-for="(value,index) in abc.names">{{value}}</li>
</template>
-->
<!--
<template v-slot:default="abc">
<li v-for="(value,index) in abc.names">{{value}}</li>
</template>
-->
<template #one="abc">
<li v-for="(value, index) in abc.names">{{value}}</li>
</template>
</son>
</div>
</template>
<template id="son">
<div>
<div>我是头部{{name}}</div>
<!--将子组件中的names通过names暴露给父组件-->
<slot name="one" v-bind:names="names">我是默认数据{{names}}</slot>
<div>我是底部</div>
</div>
</template>
<script>
// 父组件
Vue.component("father", {
template: "#father",
//子组件
components: {
"son": {
template: "#son",
data:function () {
return{
names:["zs","ls","ww","zl"]
}
}
}
}
});
let vue = new Vue({
el: '#app',
});
</script>
效果: