封装组件系列-全是技巧,没有感情

115 阅读3分钟

多个emit()自定义事件,两种解决方案

  • 基本方法:通过v-for遍历的时候解构出序号,然后发送自定义事件的时候,作为载荷携带发送给父组件
  <son>
     <button  v-for="(btn,index) in groupBtns" @click="emit('btnClick',index)">{{btn.name}}</button>
  </son>
<father @btnClick="onBtnClick">
    <son :groupBtns="groupBtns"></son>
</father>

<script setup>
    //定义函数
  const patchDelete = ()=>{
      console.log("patchDelete")
  }
  const patchExport = ()=>{
      console.log("patchExport")
  }
  const addPlaying = ()=>{
      console.log("addPlaying")
  }

   /* 定义btnGroup需要的数据 */
  const groupBtns = [
    {
        name: "删除",
    },
    {
        name: "导出",
    },
    {
        name: "添加",
    },
]

//子组件emit上来的(父组件)响应事件
const onBtnClick = (payload) => {
    switch (index) {
        case 0:
            patchDelete()
            break;
        case 1:
            patchExport()
            break;
        case 2:
            addPlaying()
            break;
        default:
            break;
    }
}
  • 方法二:配置一个大对象,对象里面包含着callback:"onEvent"...,再发送自定义事件的时候,以这个callback的值作为载荷传递给父组件
   <son>
       <button  v-for="btn in groupBtns" @click="emit('btnClick',btn.callback)">{{btn.text}}</button>
   </son>
<father @btnClick="onBtnClick">
    <son :groupBtns="groupBtns"></son>
</father>


<script setup>
    //定义函数
  const patchDelete = ()=>{
      console.log("patchDelete")
  }
  const patchExport = ()=>{
      console.log("patchExport")
  }
  const addPlaying = ()=>{
      console.log("addPlaying")
  }

   /* 定义btnGroup需要的数据 */
  const groupBtns = [
    {
        name: "删除",
        callback: "patchDelete"
    },
    {
        name: "导出",
        callback: "patchExport"
    },
    {
        name: "添加",
        callback: "addComing"
    },
]
  //定义按钮组函数
 const groupBtnCallbacks = {
    patchDelete,
    patchExport,
    addPlaying
     }
  
  //子组件emit上来的(父组件)响应事件
 const onBtnClick = (payload)=>{
     groupBtnCallbacks[payload]()
     }
 
</script>

子组件暴露自己便捷式API给父组件

子组件把自己封装好的函数/参数,通过expose暴露出去给父组件使用

Vue2与Vue3写法有些区别
  • Vue2通过 this.$refs.xxxRef 找到组件实例
//Vue2里面的ref都是用于给子组件注册引用信息(个人理解:绑定子组件,方便父组件找到),ref="sonRef",同样是把子组件丢到这个sonRef地址当中,父组件通过this.$refs.xxxRef找到子组件并使用子组件暴露出来的数据
//子组件
export default {
    expose:{
        myname,
        myage,
        sayHelloFn
    }
}

//父组件
<son ref="sonRef"/>
this.$refs.sonRef.sayHelloFn()
  • Vue3通过 xxxRef.value 找到组件实例
//Vue3 通过ref创建一个响应式数据。一般引用数据类型/组件,初始值为空(null),并把子组件丢到这个地址里, ref="sonRef",后面通过 xxxRef.value 访问这个地址的值就可以得到子组件实例且使用子组件暴露出来的数据
//子组件
//引入
import { defineExpose } from "vue";
//定义方法
const defineExposeTest =(value)=>{
    console.log("父组件调用子组件暴露的方法并传入参数",value);
}
//暴露方法
defineExpose({
    defineExposeTest
})

//父组件
import { ref } from "vue";
//把子组件丢入到sonRef地址当中
<son ref="sonRef"></son>

//一开始sonRef为空
const sonRef = ref(null)

//延时2000毫秒去调用子组件暴露出来的函数
setTimeout(() => {
    //通过sonRef的值找到子组件实例且使用子组件暴露出来的数据
    sonRef.value.defineExposeTest(0)
}, 2000)

插槽之间的嵌套使用

应该都还记得具名插槽+作用域插槽吧? 不记得点击这里,回忆回忆 juejin.cn/post/717031…

插槽的嵌套玩法就是在原先已经部署好了一层插槽,我们继续在这个插槽里面,嵌套一层,基于组件库的二次开发这是经常用到的,因为人家封装的组件里面,会预留插槽(具名+作用域),向外暴露数据,我们需求就是拿到这个原先插槽暴露出来的数据,我们可以使用暴露的数据,进行我们自己需求内容的填充,于是乎,就有了插槽的嵌套玩法

  • 这个就是Element的组件库且预留一个默认插槽,(具名+作用域),我们可以使用子组件传上来的数据
  • 我们自己设置了一个 名为propValue的插槽,并且也对外暴露数据,给父组件使用
  • 这里需注意,我们暴露的数据都是要以对象的形式来接收的
<el-table-column>
     <template #default="{ row }" v-if="hasSlot">
        <slot :name="prop" :row="row"></slot>
     </template>
</el-table-column>
  • 这里就是使用我们自己部署的插槽
<EpTable :tableData="tableData" :pageSize="10" :total="tableData.length" :cols="cols" :avgWidth="105">
            <template #poster="{ row }">
                <div style="display: flex; align-items: center">
                    <el-image :src="row.poster" />
                </div>
            </template>

            <template #actors="{ row }">
                <div style="display: flex; align-items: center">
                    <el-image :src="row.actors[0].avatarAddress" />
                </div>
            </template>
</EpTable>
  • 为什么会有嵌套插槽呢?就是人家提高的插槽数不能满足我们自己得业务需求,需要我们进行改良,从而有了二次封装,插槽的嵌套;

Prop传入的值为一个函数

  • 父子通信当中,通过prop注入一个函数:父组件给子组件传递一个函数,参数由子组件内部的数据来注入,父组件可以对子组件数据进行二次修改,然后再重新把返回值传递给子组件
//父组件 部署TestPropFn子组件
<TestPropFn :fatherFn="onTest"></TestPropFn>

const onTest = (a, b, c) => {
  console.log("a", a);
  console.log("b", b);
  console.log("c", c);
  return a + b + c
}
//子组件
<p>sonFn(a, b, c):{{ sonFn(a, b, c) }}  ***这是父组件传入返回值渲染的结果</p>

const a = ref(1)
const b = ref(2)
const c = ref(3)
const prop = defineProps({
    fatherFn: {
        type: Function
    }
})
const sonFn = (a, b, c) => {
    return prop.fatherFn(a, b, c)
}

组件的递归