navieUI源码学习

前置知识

从 Message 组件开始

首先我们来看一下 NavieUI 文档中对 Message 组件的使用:

1
2
3
<n-message-provider>
<content />
</n-message-provider>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
import { useMessage } from "naive-ui";
import { defineComponent } from "vue";

// content
export default defineComponent({
setup() {
const message = useMessage();
return {
warning() {
message.warning("...");
},
};
},
});

Message 组件中有这样一段代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
const api: MessageApiInjection = {
info(content: string, options: MessageOptions) {
return create(content, { ...options, type: "info" });
},
success(content: string, options: MessageOptions) {
return create(content, { ...options, type: "success" });
},
warning(content: string, options: MessageOptions) {
return create(content, { ...options, type: "warning" });
},
error(content: string, options: MessageOptions) {
return create(content, { ...options, type: "error" });
},
loading(content: string, options: MessageOptions) {
return create(content, { ...options, type: "loading" });
},
};
provide<MessageApiInjection>("message", api);

上面代码中的provide官方文档中的描述为:提供一个值,可以被后代组件注入。
provide 作为值的提供者,需要使用inject来使用值。
所以外层的MessageProvider组件就是provide的提供者,里面包含了Message组件的api属性。

1
2
3
4
5
6
7
export function useMessage(): MessageApiInjection {
const api = inject<MessageApiInjection>("message");
if (api === undefined) {
throwError("use-message", "No out <n-message-provider /> founded.");
}
return api;
}

create函数则是在MessageProvider内部追加了 message 消息:messageListRef.value.push(messageReactive),然后由render函数对消息列表进行遍历渲染。

表单组件

表单验证

第一步:收集表单组件内所有的 FormItem 实例

1
2
3
4
5
6
7
8
9
10
11
const formItemValidationPromises = [];
for (const key of keysOf(formItems)) {
const formItemInstances = formItems[key];
for (const formItemInstance of formItemInstances) {
if (formItemInstance.path) {
formItemValidationPromises.push(
formItemInstance.internalValidate(null, shouldRuleBeApplied)
);
}
}
}

上述代码中formItems是又是通过provide提供给子组件,然后子组件通过inject注入,然后子组件通过useFormItem来使用FormItem的实例。
如果深挖获取获取实例的方式,会看到如下这段代码:const vm = getCurrentInstance()?.proxy;,正如方法名所示,getCurrentInstance获取当前实例。

第二步:调用所有 FormItem 实例的internalValidate方法

internalValidate方法则是基于async-validator库来实现的,具体不做展开。