首页 > 其他分享 >彻底搞清楚vue3的defineExpose宏函数是如何暴露方法给父组件使用

彻底搞清楚vue3的defineExpose宏函数是如何暴露方法给父组件使用

时间:2024-05-28 09:22:18浏览次数:21  
标签:__ vue defineExpose expose vue3 组件 validate 方法 给父

前言

众所周知,当子组件使用setup后,父组件就不能像vue2那样直接就可以访问子组件内的属性和方法。这个时候就需要在子组件内使用defineExpose宏函数来指定想要暴露出去的属性和方法。这篇文章来讲讲defineExpose宏函数是如何暴露出去这些属性和方法给父组件使用。注:本文中使用的vue版本为3.4.19

看个demo

父组件index.vue的代码如下:

<template>
  <ChildDemo ref="child" />
  <button @click="handleClick">调用子组件的validate方法</button>
</template>

<script setup lang="ts">
import ChildDemo from "./child.vue";
import { ref } from "vue";

const child = ref();

function handleClick() {
  console.log(child.value.validate);
  child.value.validate?.();
}
</script>

上面的代码很简单,通过ref拿到子组件的实例赋值给child变量。然后在按钮的click事件中打印出子组件的validate方法和执行validate方法。

再来看看子组件child.vue不使用defineExpose宏的例子,代码如下:

<template></template>

<script setup>
function validate() {
  console.log("执行子组件validate方法");
}
</script>

在浏览器中点击父组件的button按钮,可以看到控制台中打印的是undefined,并且子组件内的validate方法也没有执行。因为子组件使用了setup,默认是不会暴露setup中定义的属性和方法。如下图:
no-defineExpose

我们再来看看子组件child.vue使用defineExpose宏的例子,代码如下:

<template></template>

<script setup>
function validate() {
  console.log("执行子组件validate方法");
}

defineExpose({
  validate,
});
</script>

在浏览器中点击父组件的button按钮,可以看到控制台中打印的不再是undefined,子组件内的validate方法也执行了。如下图:
has-defineExpose

关注公众号:【前端欧阳】,给自己一个进阶vue的机会

加我微信heavenyjj0012回复「666」,免费领取欧阳研究vue源码过程中收集的源码资料,欧阳写文章有时也会参考这些资料。同时让你的朋友圈多一位对vue有深入理解的人。

编译后的代码

首先需要在浏览器中找到编译后的使用defineExpose宏的child.vue文件,在network面板中找到child.vue,然后右键点击Open in Sources panel就可以在source面板中找到编译后的child.vue。如下图:
network

为了要在浏览器中debug,我们还需要在设置中关闭浏览器的javascript source map,如下图:
source-map

现在我们来看看编译后的child.vue文件,代码如下:

const _sfc_main = {
  __name: "child",
  setup(__props, { expose: __expose }) {
    function validate() {
      console.log("执行子组件validate方法");
    }
    __expose({
      validate,
    });
    const __returned__ = { validate };
    return __returned__;
  },
};

function _sfc_render(_ctx, _cache, $props, $setup, $data, $options) {
  return null;
}
_sfc_main.render = _sfc_render;
export default _sfc_main;

从上面可以看到_sfc_main对象中的setup对应的就是我们源代码<script setup>中的内容,并且defineExpose宏函数也不在了,变成了一个__expose方法(defineExpose宏函数如何编译成__expose方法我们会在下一篇文章讲)。如下图:
convert

expose方法

__expose方法打个断点,刷新页面此时断点停留在__expose方法上面。点击step into进入到__expose方法内部,如下图:
step-into

进入到__expose方法内部,我们发现__expose方法是在一个createSetupContext函数中定义的。在我们这个场景中createSetupContext函数简化后的代码如下:

function createSetupContext(instance) {
  const expose = (exposed) => {
    instance.exposed = exposed || {};
  };

  return Object.freeze({
    // ...省略
    expose,
  });
}

我们先来看看函数中的instance变量,我想你通过名字应该已经猜到了他就是当前vue实例对象。如下图:
instance

在vue实例对象中有我们熟悉的data方法、directives和componens属性等。

expose函数内部做的事情也很简单,将子组件需要暴露的属性或者方法组成的对象赋值给vue实例上的exposed属性。

父组件访问子组件的validate方法

在vue3中想要访问子组件需要使用特殊的 ref attribute,在我们这个例子中就是使用<ChildDemo ref="child" />。这样使用后就可以使用child变量访问子组件,其实在这里child变量的值就是一个名为getExposeProxy函数的返回值(后面的文章中会去详细讲解ref attribute是如何访问子组件)。

getExposeProxy函数的代码如下:

function getExposeProxy(instance) {
  if (instance.exposed) {
    return (
      instance.exposeProxy ||
      (instance.exposeProxy = new Proxy(proxyRefs(markRaw(instance.exposed)), {
        get(target, key) {
          if (key in target) {
            return target[key];
          } else if (key in publicPropertiesMap) {
            return publicPropertiesMap[key](instance);
          }
        },
        has(target, key) {
          // ...省略
        },
      }))
    );
  }
}

前面我们讲过了defineExpose宏函数中定义了想要暴露出来的属性和方法,经过编译后defineExpose宏函数变成了__expose方法。执行__expose方法后会将子组件想要暴露的属性或者方法组成的对象赋值给vue实例上的exposed属性,也就是instance.exposed

在上面的getExposeProxy函数中就是返回了instance.exposedProxy对象,当我们使用child.value.validate访问子组件的validate方法,其实就是访问的是instance.exposed对象中的validate方法,而instance.exposed中的validate方法就是defineExpose宏函数暴露的validate方法。如下图:
full-progress

总结

父组件想要访问子组件暴露的validate方法主要分为下面四步:

  • 子组件使用defineExpose宏函数声明想要暴露validate方法。

  • defineExpose宏函数经过编译后变成__expose方法。

  • 执行__expose方法将子组件需要暴露的属性或者方法组成的对象赋值给子组件vue实例上的exposed属性,也就是instance.exposed

  • 父组件使用ref访问子组件的validate方法,也就是访问child.value.validate。其实访问的就是上一步的instance.exposed.validate方法,最终访问的就是defineExpose宏函数中暴露的validate方法。

关注(图1)公众号:【前端欧阳】,解锁我更多vue原理文章。
加我(图2)微信回复「666」,免费领取欧阳研究vue源码过程中收集的源码资料,欧阳写文章有时也会参考这些资料。同时让你的朋友圈多一位对vue有深入理解的人。
公众号微信

标签:__,vue,defineExpose,expose,vue3,组件,validate,方法,给父
From: https://www.cnblogs.com/heavenYJJ/p/18216501

相关文章

  • Vue3实战笔记(46)—Vue 3高效开发定制化Dashboard的权威手册
    文章目录前言Dashboard开发总结前言后台管理系统中的Dashboard是一种图形化的信息显示工具,通常用于提供一个特定领域或系统的概况。它可以帮助用户监控和分析数据,快速获取重要信息。可以帮助用户监控业务状况、分析数据、获取关键信息和管理资源。通过合理的设计和......
  • Vue3实战笔记(47)— 一探emit奥秘——组件间通信的艺术与实践
    文章目录前言一、Vue2中的emti二、Vue3的emit总结前言Vue封装了自定义组件之后,如果子组件想要向父组件传递数据该怎么办?Vue.js中的emit方法就是主要用于组件间的通信,特别是父组件与子组件之间的通信机制。它是Vue组件内部触发自定义事件并向父级组件传递数......
  • vue3计算属性
    基础示例模板中的表达式虽然方便,但也只能用来做简单的操作。如果在模板中写太多逻辑,会让模板变得臃肿,难以维护。比如说,我们有这样一个包含嵌套数组的对象:我们想根据author是否已有一些书籍来展示不同的信息:这里的模板看起来有些复杂。我们必须认真看好一会儿才能明白......
  • 升鲜宝供应链管理系统重构版发布(技术点:Java8、mysql8.0 uniapp、vue、android、web 框
    升鲜宝供应链管理系统重构版发布(技术点:Java8、mysql8.0uniapp、vue、android、web框架:Vue3+SpringBoot3),界面功能(一)  升鲜宝供应链管理系统重构版发布(技术点:Java8、mysql8.0uniapp、vue、android、web框架:Vue3+SpringBoot3),界面功能(一) 1.登录与申请试用界......
  • Vue3.4+版本中的 defineModel 宏的用法示例
    关于defineModel,Vue官方给出了较为详细的解释,具体请看文档说明下面是整理出的一个简易示例:子元素代码://Comp.vue<scriptsetup>constmsg=defineModel('msg',{type:String,default:''});constscore=defineModel('score',{type:Number,default:0})......
  • Vue3标签组件绘制--自定义按钮组件
    不知道怎么的,突然想绘制一个标签,比如el-button什么的。今天研究一下吧,不知道能不能整出来以后就可以绘制自己的组件,弄自己的组件库了。不知道有朝一日能不能让越组件青史留名?嘻嘻,百日梦做差不多了,接着去查查资料。文章分为三个部分:1.按钮组件实现(根据查阅的一个文章实现基......
  • Vue3源码解析--收集的依赖是什么?怎么收集的?什么时候收集的?
    从Vue开始较大范围在前端应用开始,关于Vue一些基础知识的讨论和面试问题就在开发圈子里基本上就跟前几年的股票和基金一样,楼下摆摊卖酱香饼的阿姨都能说上几句那种。找过前端开发工作或者正在找开发工作的前端都知道,面试官基本上都有那么几个常问的问题,而网上呢也有那么一套可以用......
  • 【wiki知识库】01.wiki知识库前后端项目搭建(SpringBoot+Vue3)
      ......
  • Vue3实战笔记(45)—VUE3封装一些echarts常用的组件,附源码
    文章目录前言一、柱状图框选二、折线图堆叠总结前言日前使用hooks的方式封装组件,在我使用复杂的图标时候遇到了些问题,预想在onMounted中初始化echarts,在使用hooks的时候,组件没有渲染完,使用实例会出现各种各样的问题,并且在hooks中使用一些外部属性也属实遇到了些麻烦......
  • uniapp-vue3-oadmin|vite5.x手机后台实例多端仿ios管理系统
    uniapp-vue3-oadmin手机后台实例|vite5.x+uniapp多端仿ios管理系统 原创vue3+uniapp+uni-ui跨端仿ios桌面后台OA管理模板Uni-Vue3-WeOS。uniapp-vue3-os一款基于uni-app+vite5.x+pinia等技术开发的仿ios手机桌面OA管理系统。实现了自定义桌面栅格磁贴布局、多分屏滑动管理、......