Vue3源码 第四篇-Vue3 setup 浅浅的花香味﹌ 2022-09-14 14:24 284阅读 0赞 # 系列文章目录 # [Vue3源码 第一篇-总览][Vue3_ _-] [Vue3源码 第二篇-Reactive API][Vue3_ _-Reactive API] [Vue3源码 第三篇-Vue3是如何实现响应性][Vue3_ _-Vue3] ### 文章目录 ### * 系列文章目录 * 前言 * 一、源码阅读 * * 1.setup函数的创建 * * 1.1 setup函数上下文(context)创建 * 1.2 setup函数执行 * 1.3 setup函数执行结果处理 * 总结 # 前言 # setup作为Vue3的组合式API的重要特性,改变了之前OptionAPI的写代码方式,setup函数让Vue3对逻辑的封装更为简单,那么他又是在Vue3上如何挂载,如何访问的呢?我们接下来一起阅读源码,从源码中深入了解setup函数。话不多说,直接开冲!!! ![在这里插入图片描述][watermark_type_ZHJvaWRzYW5zZmFsbGJhY2s_shadow_50_text_Q1NETiBA5bCP55av55avMDQxMw_size_10_color_FFFFFF_t_70_g_se_x_16_pic_center] # 一、源码阅读 # ## 1.setup函数的创建 ## 要找到setup的挂载,第一步找到在哪里执行setup函数,我们知道setup函数肯定在组件挂载的时候执行,所以我们在组件挂载的代码中找到了**setupStatefulComponent**函数,该函数中包含了组件各个部分的挂载,自然也包含了setup函数的挂载,我们来阅读下这个函数中setup函数相关的代码。 function setupStatefulComponent(instance, isSSR) { // ...省略其他代码 // 2. call setup() 组件中存在setup函数,挂载过程中,最先开始挂载的就是setup函数,之后才是optionApi的挂载 const { setup } = Component; if (setup) { // 创建setup函数的上下文 const setupContext = (instance.setupContext = setup.length > 1 ? createSetupContext(instance) : null); currentInstance = instance; pauseTracking(); // 获取setup结果,外层包裹函数错误处理函数callWithErrorHandling const setupResult = callWithErrorHandling(setup, instance, 0 /* SETUP_FUNCTION */, [shallowReadonly(instance.props) , setupContext]); resetTracking(); currentInstance = null; // 对不同的结果进行处理 // 如果结果是promise if (isPromise(setupResult)) { if (isSSR) { // 当前是SSR 服务器端渲染 // return the promise so server-renderer can wait on it return setupResult .then((resolvedResult) => { // 等待服务器返回结果在进行处理 handleSetupResult(instance, resolvedResult, isSSR); }) .catch(e => { handleError(e, instance, 0 /* SETUP_FUNCTION */); }); } else { // async setup returned Promise. 如果只是单纯的异步,就直接赋值暂时跳过 // bail here and wait for re-entry. instance.asyncDep = setupResult; } } else { // 如果不是promise,直接处理返回结果 handleSetupResult(instance, setupResult, isSSR); } } else { // 如果不存在setup函数就直接进行下面optionApi的挂载, // 不包括props的执行,在Vue3中,props最先执行,之后是setup,最后是其他optionAPI finishComponentSetup(instance, isSSR); } } 我们先整体的了解的setup的挂载过程,接下来我们仔细将setup函数挂载分为:setup函数上下文的创建,setup的执行,setup返回的处理3个具体步骤来仔细阅读其中的代码。 ### 1.1 setup函数上下文(context)创建 ### **createSetupContext**函数创建setup函数的上下文,包含了一些在setup函数中可能会用到的属性和方法等。 function createSetupContext(instance) { const expose = exposed => { // exopose函数,当setup返回渲染函数时会用到,因为返回渲染函数时无法暴露其他东西,所以可以通过expose函数暴露 // 具体可以查看官网 https://v3.cn.vuejs.org/guide/composition-api-setup.html#使用渲染函数 if (instance.exposed) { warn(`expose() should be called only once per setup().`); } instance.exposed = proxyRefs(exposed); }; { // We use getters in dev in case libs like test-utils overwrite instance // properties (overwrites should not be done in prod) return Object.freeze({ get attrs() { // $attrs 组件上的属性 return new Proxy(instance.attrs, attrHandlers); }, get slots() { // $slots 插槽 return shallowReadonly(instance.slots); }, get emit() { // $emit 触发事件的方法 return (event, ...args) => instance.emit(event, ...args); }, expose }); } } ### 1.2 setup函数执行 ### **callWithErrorHandling**方法在Vue2和3版本中都很常见,主要是对执行函数进行错误处理的封装。对执行的函数进行try-catch处理。 const setupResult = callWithErrorHandling(setup, instance, 0 /* SETUP_FUNCTION */, [shallowReadonly(instance.props) , setupContext]); // 第一个参数是setup函数本身 // 第二个参数是组件实例 // 第三个参数是标志执行函数类型 // 第四个参数是由props和刚才执行的上下文组成的参数 function callWithErrorHandling(fn, instance, type, args) { let res; try { res = args ? fn(...args) : fn(); } catch (err) { handleError(err, instance, type); } return res; } 通过setup函数的执行代码,我们可以知道,在执行setup函数中,我们能获取到的是props和之前提到的上下文参数,有一点也特别重要,我们在执行setup函数的时候并没有传入instance对象,也就是无法获取实例对象,并且在context中也没有传入data,method等信息(其实这里是因为这些的创建在setup函数之后)所以官网也指出: **你将无法在setup函数中访问以下组件选项: data computed methods refs (模板 ref)** 还有一点setup函数的this,也没有绑定instance,所以setup的this无法获取到vue实例。这样就验证了官网所说的: **在 setup() 内部,this 不是该活跃实例的引用** ### 1.3 setup函数执行结果处理 ### **handleSetupResult**处理setup返回结果,将结果绑定到instance上方便其他函数调用 function handleSetupResult(instance, setupResult, isSSR) { // 如果返回的是函数,就是渲染函数,设置实例上的render函数为该函数 if (isFunction(setupResult)) { // setup returned an inline render function { instance.render = setupResult; } } else if (isObject(setupResult)) { // 返回对象 if (isVNode(setupResult)) { warn(`setup() should not return VNodes directly - ` + `return a render function instead.`); } // setup returned bindings. // assuming a render function compiled from template is present. { instance.devtoolsRawSetupState = setupResult; } // 将返回结果转换成reactive对象,并且放入到实例的setupState上 instance.setupState = proxyRefs(setupResult); { exposeSetupStateOnRenderContext(instance); } } else if (setupResult !== undefined) { warn(`setup() should return an object. Received: ${ setupResult === null ? 'null' : typeof setupResult}`); } finishComponentSetup(instance, isSSR); } # 总结 # 今天对setup函数的创建过程进行了源码阅读,包括他的上下文创建,setup函数的执行还有对setup结果的处理,个人理解有限,若有不好的地方希望大家多多斧正,最后拜托大家给个三连吧~~~ ![在这里插入图片描述][watermark_type_ZHJvaWRzYW5zZmFsbGJhY2s_shadow_50_text_Q1NETiBA5bCP55av55avMDQxMw_size_14_color_FFFFFF_t_70_g_se_x_16_pic_center] [Vue3_ _-]: https://blog.csdn.net/qq_26626113/article/details/119169666 [Vue3_ _-Reactive API]: https://blog.csdn.net/qq_26626113/article/details/119837310 [Vue3_ _-Vue3]: https://blog.csdn.net/qq_26626113/article/details/120583561 [watermark_type_ZHJvaWRzYW5zZmFsbGJhY2s_shadow_50_text_Q1NETiBA5bCP55av55avMDQxMw_size_10_color_FFFFFF_t_70_g_se_x_16_pic_center]: /images/20220828/74cfe067dfd14fc6926a1b3b23ba77a6.png [watermark_type_ZHJvaWRzYW5zZmFsbGJhY2s_shadow_50_text_Q1NETiBA5bCP55av55avMDQxMw_size_14_color_FFFFFF_t_70_g_se_x_16_pic_center]: /images/20220828/10c43f34a02d42fea0cec03d759cf726.png
还没有评论,来说两句吧...