略过
后续使用的项目就是新搭建的一个项目
查看《Vue初始化项目加载逻辑》这篇文章即可
父组件
子组件
场景:例如你的购物车,里面有很多商品,每个商品是一个小组件,每个组件都有价钱这个元素,每个组件之间是不清楚其他小组件的价钱的,我现在要算总价,购物车总价是在购物车这个大组件里的,那我现在要把每个小组件的价钱这个值传给购物车这个大组件中来
我们举例子就用新建项目的HelloWorld即可,将一些其他乱七八糟的删除掉
<template>
<div class="hello">
<!--点击按钮,触发方法,方法里有自定义事件-->
<button @click="handler">按钮</button>
</div>
</template>
<script>
export default {
name: 'HelloWorld',
props: {
msg: String
},
data(){
return{
childCount:0 //没有特殊含义,只是用来标识这个值来自于子类,见名知意,后续将这个值传给父组件
}
},
methods:{
handler(){
this.childCount++
this.$emit('child-count-change',this.childCount) //子传父,需要通过自定义事件来处理,这里就是自定义事件设置,通过this.$emit()来触发自定义事件
//第一个参数,我们先随便编造一个事件,就叫child-count-change
//第二个参数,就是事件要传入的数据
//总结一下,就是只要一触发child-count-change事件,就会将this.childCount传入进去
//那这个时间由谁来做一个响应的处理呢,就需要去父组件里进行一个监听
}
}
}
</script>
<style scoped>
h3 {
margin: 40px 0 0;
}
ul {
list-style-type: none;
padding: 0;
}
li {
display: inline-block;
margin: 0 10px;
}
a {
color: #42b983;
}
</style>
<template>
<div class="home">
<img alt="Vue logo" src="../assets/logo.png">
<HelloWorld
msg="Welcome to Your Vue.js App"
@child-count-change="handlerFather"
></HelloWorld>
<!--1、这里的@child-count-change,就是我们在子组件里的自定义实践,绑定到了handlerFather这个方法上,在methods里实现-->
<p>父组件中接受的插值是: {{childData}}</p>
<!--3、用来展示从子组件传递过来的值,只是方便观察-->
</div>
</template>
<script>
import HelloWorld from '@/components/HelloWorld.vue'
export default {
name: 'HomeView',
data(){
return{
childData: 0 //2、定义一个响应式数据,之后用来承接子组件传过来的值
}
},
components: {
HelloWorld
},
methods:{
//4、还记得我们在子组件里将childCount这个值传进来了
handlerFather(childCount){
this.childData=childCount //5、将子组件传进来的值复制给父组件的响应式数据,按常理这里一定是更复杂的操作,例如求和等等,这样写只是为了方便而已
}
}
}
</script>
比如说现在helloworld组件里只有一个按钮了,是它的核心功能,但是比如说我们想要每次在使用这个组件的时候,有不一样的呈现的话
子组件原来的样子
<template>
<div class="hello">
<button @click="handler">按钮</button>
</div>
</template>
父组件的内容
<template>
<div class="home">
<img alt="Vue logo" src="../assets/logo.png">
<HelloWorld
msg="Welcome to Your Vue.js App"
@child-count-change="handlerFather"
></HelloWorld>
<p>{{childData}}</p>
<!--1、多写几个helloworld组件,想要展示有所不同,像下面再双标签中间写的内容就是给插槽的内容,可以在子组件中规定你给插槽的内容在哪里去展示-->
<HelloWorld>这是默认内容1</HelloWorld>
<HelloWorld>这是默认内容2</HelloWorld>
<HelloWorld>这是默认内容3</HelloWorld>
<HelloWorld></HelloWorld>
</div>
</template>
<script>
import HelloWorld from '@/components/HelloWorld.vue'
export default {
name: 'HomeView',
data(){
return{
childData: 0
}
},
components: {
HelloWorld
},
methods:{
handlerFather(childCount){
this.childData=childCount
}
}
}
</script>
接下来在子组件中定义插槽的内容
<template>
<div class="hello">
<!--1、比如我想要将父组件传进来的值放在前面,这个slot并不是一个真正的标签,如果父组件给值了,那就展示父组件的值,没给值,那就展示我们给的默认的-->
<slot>基础的默认内容</slot>
<button @click="handler">按钮</button>
</div>
</template>
<script>
export default {
name: 'HelloWorld',
props: {
msg: String
},
data(){
return{
childCount:0
}
},
methods:{
handler(){
this.childCount++
this.$emit('child-count-change',this.childCount)
}
}
}
</script>
<style scoped>
h3 {
margin: 40px 0 0;
}
ul {
list-style-type: none;
padding: 0;
}
li {
display: inline-block;
margin: 0 10px;
}
a {
color: #42b983;
}
</style>
比props的方式更简单,还可以将“这是默认内容”写成html
除了比prop更方便之外,还意味着子组件的一部分区域是开放给父组件的,而不是全部由子组件定义,更灵活
默认插槽有一个问题,那就是就这一个,如果有多个插槽呢,我们怎么区别从父组件传来的值,是展示在子组件的哪个插槽呢,这就需要具名插槽
子组件的变化
<template>
<div class="hello">
<slot>基础的默认内容</slot>
<button @click="handler">按钮</button>
<!--新建一个插槽,但是插槽带了一个name属性,并且给一个默认值是:footer的默认内容-->
<slot name="footer">footer的默认内容</slot>
</div>
</template>
<script>
export default {
name: 'HelloWorld',
props: {
msg: String
},
data(){
return{
childCount:0
}
},
methods:{
handler(){
this.childCount++
this.$emit('child-count-change',this.childCount)
}
}
}
</script>
<style scoped>
h3 {
margin: 40px 0 0;
}
ul {
list-style-type: none;
padding: 0;
}
li {
display: inline-block;
margin: 0 10px;
}
a {
color: #42b983;
}
</style>
父组件的变化
<template>
<div class="home">
<img alt="Vue logo" src="../assets/logo.png">
<HelloWorld
msg="Welcome to Your Vue.js App"
@child-count-change="handlerFather"
></HelloWorld>
<p>{{childData}}</p>
<HelloWorld>这是默认内容1</HelloWorld>
<HelloWorld>这是默认内容2</HelloWorld>
<HelloWorld>这是默认内容3</HelloWorld>
<HelloWorld></HelloWorld>
<!--新建一个子组件,通过template标签,里面的v-slot:footer(或者#footer也可以)来将标签里的内容绑定给子组件名为footer的插槽,而不是其他插槽-->
<HelloWorld>
<template v-slot:footer>这是专门给子组件footer插槽的内容</template>
</HelloWorld>
<!--或者,将v-slot:替换成#-->
<HelloWorld>
<template #footer>这是专门给子组件footer插槽的内容2</template>
</HelloWorld>
</div>
</template>
<script>
import HelloWorld from '@/components/HelloWorld.vue'
export default {
name: 'HomeView',
data(){
return{
childData: 0
}
},
components: {
HelloWorld
},
methods:{
handlerFather(childCount){
this.childData=childCount
}
}
}
</script>
<template>
<div class="hello">
<slot>基础的默认内容</slot>
<button @click="handler">按钮</button>
<slot name="footer" >footer的默认内容</slot>
</div>
</template>
就以上面这个子组件的插槽来说,这个插槽是属于子组件的而不是父组件的,如果父组件要使用子组件的数据的话,就需要使用作用域插槽方式来做一个设置
子组件
<template>
<div class="hello">
<slot>基础的默认内容</slot>
<button @click="handler">按钮</button>
<!--现在我们在子组件的插槽中,绑定了一个响应式数据-->
<slot name="footer" :childCount="childCount">footer的默认内容</slot>
</div>
</template>
<script>
export default {
name: 'HelloWorld',
props: {
msg: String
},
data(){
return{
childCount:0
}
},
methods:{
handler(){
this.childCount++
this.$emit('child-count-change',this.childCount)
}
}
}
</script>
<style scoped>
h3 {
margin: 40px 0 0;
}
ul {
list-style-type: none;
padding: 0;
}
li {
display: inline-block;
margin: 0 10px;
}
a {
color: #42b983;
}
</style>
父组件
<template>
<div class="home">
<img alt="Vue logo" src="../assets/logo.png">
<HelloWorld
msg="Welcome to Your Vue.js App"
@child-count-change="handlerFather"
></HelloWorld>
<p>{{childData}}</p>
<!-- 我们通过 #footer="dataObj"的方式,获取了从子组件传进来的值,并重命名为dataObj,这个值,定义了就一定要使用,要不然会报错的-->
<!-- 虽然子组件传进来的看起来是一个值,其实是一个对象 -->
<HelloWorld>
<template #footer="dataObj">这是专门给子组件footer插槽的内容{{dataObj }}</template>
</HelloWorld>
</div>
</template>
<script>
import HelloWorld from '@/components/HelloWorld.vue'
export default {
name: 'HomeView',
data(){
return{
childData: 0
}
},
components: {
HelloWorld
},
methods:{
handlerFather(childCount){
this.childData=childCount
}
}
}
</script>
你看,传进来的是
{ “childCount”: 0 }
而不是一个值
0
如果只想用某一个值的话
父组件
<template>
<div class="home">
<img alt="Vue logo" src="../assets/logo.png">
<HelloWorld
msg="Welcome to Your Vue.js App"
@child-count-change="handlerFather"
></HelloWorld>
<p>{{childData}}</p>
<!-- 我们通过 dataObj.字段名的方式来获取某一个值-->
<HelloWorld>
<template #footer="dataObj">这是专门给子组件footer插槽的内容{{dataObj.childCount }}</template>
</HelloWorld>
<!-- 或者,直接在绑定的时候就绑定其中的某一个字段 -->
<HelloWorld>
<template #footer="{childCount}">这是专门给子组件footer插槽的内容二{{childCount }}</template>
</HelloWorld>
</div>
</template>
<script>
import HelloWorld from '@/components/HelloWorld.vue'
export default {
name: 'HomeView',
data(){
return{
childData: 0
}
},
components: {
HelloWorld
},
methods:{
handlerFather(childCount){
this.childData=childCount
}
}
}
</script>