发布于2021-10-19 22:46 阅读(1142) 评论(0) 点赞(27) 收藏(5)
Vue3源码 第一篇-总览
Vue3源码 第二篇-Reactive API
Vue3源码 第三篇-Vue3是如何实现响应性
setup作为Vue3的组合式API的重要特性,改变了之前OptionAPI的写代码方式,setup函数让Vue3对逻辑的封装更为简单,那么他又是在Vue3上如何挂载,如何访问的呢?我们接下来一起阅读源码,从源码中深入了解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个具体步骤来仔细阅读其中的代码。
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
});
}
}
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 不是该活跃实例的引用
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结果的处理,个人理解有限,若有不好的地方希望大家多多斧正,最后拜托大家给个三连吧~~~
原文链接:https://blog.csdn.net/qq_26626113/article/details/120657470
作者:听说你很拽
链接:http://www.qianduanheidong.com/blog/article/203849/9d41ca4e7a95a8b4c45a/
来源:前端黑洞网
任何形式的转载都请注明出处,如有侵权 一经发现 必将追究其法律责任
昵称:
评论内容:(最多支持255个字符)
---无人问津也好,技不如人也罢,你都要试着安静下来,去做自己该做的事,而不是让内心的烦躁、焦虑,坏掉你本来就不多的热情和定力
Copyright © 2018-2021 前端黑洞网 All Rights Reserved 版权所有,并保留所有权利。 京ICP备18063182号-3
投诉与举报,广告合作请联系vgs_info@163.com或QQ3083709327
免责声明:网站文章均由用户上传,仅供读者学习交流使用,禁止用做商业用途。若文章涉及色情,反动,侵权等违法信息,请向我们举报,一经核实我们会立即删除!