从0学习Vue3(8)

233 阅读1分钟

3.13.3 子组件调用父组件的方法:$parent或$root

除了通过子传父让父组件执行某些操作,我们也可以直接在子组件中执行父组件中的函数,甚至是爷爷的函数,我们直接来演示,在上面的基础上多创建一个grandsonCom.vue 孙子组件哈哈,先分别在App.vue和childCom.vue加函数:

 <!-- App.vue -->
 <template>
   <childCom></childCom>
 </template>
 ​
 <script>
 import childCom from './components/childCom.vue'
 export default {
   name:'App',
   data(){
       return{
           appData:'我是App.vue的数据'
       }
   },
   components:{
     childCom
   },
   methods:{
     appFun(){
       console.log('这是App.vue的函数')
     }
   }
 }
 </script>
 <!-- childCom.vue -->
 <template>
   <grandsonComVue></grandsonComVue>
 </template>
 ​
 <script>
 import grandsonComVue from './grandsonCom.vue';
 export default {
   data(){
       return{
           childData:'我是childCom.vue的数据'
       }
   },
   components:{
     grandsonComVue
   },
   methods:{
     childFun(){
       console.log('这是childCom.vue的函数')
     }
   }
 }
 </script>
 <!-- grandsonComVue -->
 <template>
   <button @click="grandsonFun">按钮</button>
 </template>
 <script>
 export default{
   methods:{
     grandsonFun(){
       this.$parent.childFun()       //一个$parent代表上一层
       this.$parent.$parent.appFun() //这样就可以无限往上找了
       this.$root.appFun()           //$root是直接找到根组件的位置
         
       console.log(this.$parent.childData)       //拿到上一级的数据
       console.log(this.$parent.$parent.appData) //拿到上上级的数据
     }
   }
 }
 </script>

现在在页面上点击按钮,就可以在控制台看到App.vue和childCom.vue中打印的消息了,并且可以看到也可以拿到它们声明的数据。

3.13.4 父组件调用子组件的方法:$refs (vue3没有了$children)

还是使用上面的代码,在App.vue中调用childCom中的函数:

 <!-- App.vue -->
 <template>
     <!-- 使用ref 给这个子组件起一个别名 -->
     <childCom ref="firstChild"></childCom>
     <button @click="appFun">点击调用子组件的函数</button>
 </template>
 <script>
 import childCom from './components/childCom.vue'
 export default {
   name:'App',
   components:{
     childCom
   },
   methods:{
     appFun(){
       //$refs可以找到所有 起了别名的元素,当然也能拿到数据
       this.$refs.firstChild.childFun()
     }
   }
 }
 </script>

3.13.5 插槽slot

  • Vue实现了一套内容分发的API,这套API的设计灵感源自Web Components规范草案,将<slot>元素作为承载分发内容的出口
  • 插槽可以实现组件的扩展性,抽取共性,保留不同

给模板加插槽就类似于给函数加参数。

在通常情况下,我们在组件元素内部写任何东西都不会生效,比如<childCom>耶耶耶</childCom>,这样子中间的“耶耶耶”是不会出现的。但是如果我们在组件中加入插槽,那么我们在中间写的东西就会被放到我们写插槽的位置:

 <template>
   <!-- 只要这样写就可以了,slot内部也可以写东西:表示默认值 -->
   <slot></slot>
 </template>

那么如果我们在组件中写了多个插槽,该怎么精准选择我们要插入哪个插槽呢:

 <!-- childCom.vue -->
 <template>
   <!-- 我们就得给插槽取名字,这里我们留一个不取名字的讲特殊情况 -->
   <slot name='one'></slot>
   <slot></slot>
 </template>
 <!-- App.vue -->
 <template>
   <childCom>
     <!-- 想指定插槽,必须使用模板,也可以把v-slot:one简写为 #one -->  
     <template v-slot:one>
         <p>酱紫使用</p>
     </template>  
   </childCom>
   <childCom>
     <!-- 若不指定,则会默认插入到没有命名的插槽 -->    
     <p>默认位置</p>
   </childCom>
 </template>

由此可以看出,插槽中使用的是在父组件的数据,那么有没有办法在插槽中使用子组件中的数据呢,是有的:

 <!-- 首先在childCom.vue把数据绑定到插槽 -->
 <template>
   <!-- 首先在childCom.vue把数据绑定到插槽,这里引号里面可以随意命名,我起了一个跟数据一样的名字 -->
   <slot :childData="childData"></slot>
 </template>
 ​
 <script>
 export default {
   data(){
       return{
           childData:'我是childCom.vue的数据'
       }
   }
 }
 </script>
 <!-- App.vue -->
 <template>
   <childCom>
   <!-- v-slot绑定default,意思是默认找到没有name的插槽,引号里依然是随意起名,代表这个template -->
   <template v-slot:default="myChild">
     <!-- 通过template拿到插槽中的childData数据 -->
     <p>{{myChild.childData}}</p>
   </template> 
   </childCom>
 </template>
 <script>
 import childCom from './components/childCom.vue'
 export default {
   name:'App',
   components:{
     childCom
   },
 }
 </script>