Source code analysis-13 global APIs in Vue3

Source code analysis-13 global APIs in Vue3

This article has a total of 5314 words, and the expected reading time is 5-15 minutes.

Preface

Unknowingly , the version of Vue-next has come to 3.1.2. Recently, I learned the global Api of Vue3 against the source code. I sorted it out while learning. I hope I can make progress with everyone.

Let's take a look at them in three dimensions: official definition, usage, and source code analysis.

The following is about the Vue3 global Api. If you have a better understanding and ideas, you can leave a message in the comment area, and I will reply to each one~

Global API

The global API is directly in

Vue
Mount method on
Vue
Among them, there are 13 global APIs. They are:

  • createapp returns an application instance that provides application context;
  • h returns a "virtual node;
  • definecomponent returns the object of options, under TS, the component will be given the correct parameter type inference;
  • defineasynccomponent creates an asynchronous component that will be loaded only when needed;
  • resolvecomponent resolves the component according to the incoming component name;
  • resolvedynamiccomponent returns the resolved Component or newly created VNode;
  • resolvedirective resolves a directive by its name;
  • withdirectives returns a VNode containing application instructions;
  • createrenderer cross-platform custom rendering;
  • Nexttick is to delay the callback function to be called after the next dom update data;
  • mergeprops merges multiple objects containing VNode props into a single object;
  • usecssmodule to access the CSS module;
  • version View the version number of the installed Vue;

createApp

Official definition: Return an application instance that provides application context. The entire component tree mounted by the application instance shares the same context.

As the name suggests, CreateApp, as the startup function of Vue, returns an application instance. Each Vue application first uses the following function to create a new application instance . Most methods exposed by the application instance return the same instance, which can be called in a chain . E.g:

Vue.createApp ({}). Component ( 'SearchInput' , SearchInputComponent) copy the code

usage

  • The first parameter : receive a root component option

  • The second parameter : pass the root prop to the application

Usage Example// Import {createApp, H, nextTick} from 'VUE' const App = createApp ({ Data () { return { ... } }, methods : {...}, computed : {...} ... }, { Username : 'Evan' }) copy the code

Source code analysis

GitHub address:

//Above the source code location [1] export const createApp = ( ( ...args ) => { //Use ensureRenderer().createApp() to create the app object //Above the source code location [2] //-> ensureRenderer method Called createRenderer from runtime-core //Above the source code position [3] //-> createRenderer(HostNode, HostElement), two general parameters HostNode (node in the host environment) and HostElement (element in the host environment), corresponding In the host environment. //-> reateRenderer (Use the (optional) option to create a Renderer instance.), this method returns baseCreateRenderer //Above the source code position [4] //-> The baseCreateRenderer method finally returns three render hydrate createApp Function, the generated render is passed to createAppAPI, hydrate is an optional parameter, which will be used in ssr scenarios; const app = ensureRenderer().createApp(...args) if (__DEV__) { //In the DEV environment, it is used to verify whether the component name is a native tag or an svg attribute tag injectNativeTagCheck(app) //In the DEV environment, check CompilerOptions if there are deprecated properties, and display a warning injectCompilerOptionsCheck(app) } const {mount} = app //Deconstruct the mount from the created app object, rewrite the mount method and return the app instance app.mount = (containerOrSelector: Element | ShadowRoot | string): any => { //container is the real DOM Element, the normalizeContainer method uses document.querySelector to process the incoming <containerOrSelector> parameter. If the element does not exist in the DEV environment or the element is shadow DOM and the mode state is closed, the corresponding warning will be returned const container = normalizeContainer(containerOrSelector) //If it is not a real DOM element, return if (!container) return //The app._component here is actually the first parameter of the createApp of the global API. The source code is at the top [5] const component = app._component //component is not a function and does not contain render and template if (!isFunction(component ) && !component.render && !component.template) { //Unsafe situation //Reason: JS expression may be executed in dom template. //The user must ensure that the inner dom template is trusted. If it is //the template should not contain any user data. //Use innerHTML of DOM as the content of component.template component.template = container.innerHTML //2. Check before mounting to get the collection traversal of element attributes. If the name is not in the v-cloak state and the attribute name contains v-, :, @, the vue document link prompt will be given if (__COMPAT__ && __DEV__) { for ( let i = 0 ; i <container.attributes.length; i++) { const attr = container.attributes[i] if (attr.name !== 'v-cloak' && /^(v-|:|@)/ . test(attr.name)) { compatUtils.warnDeprecation( DeprecationTypes.GLOBAL_MOUNT_CONTAINER, null ) break } } } } //Clear the content before mounting container.innerHTML = '' //Real mount (element, whether to reuse [personal understanding here, for reference only], whether it is an SVG element) const proxy = mount(container, false , container instanceof SVGElement) if (container instanceof Element) { //delete the v-cloak instruction on the element container.removeAttribute( 'v-cloak' ) //set the data-v-app attribute container.setAttribute( 'data-v-app ' , '' ) } return proxy } return app }) as CreateAppFunction<Element> Copy code

h

Official definition: return a "virtual node", usually abbreviated as VNode : an ordinary object that contains information describing to Vue what kind of node it should render on the page, including the description of all child nodes. Its purpose is to be used for manually written rendering functions;

What does h mean? According to the reply from Master Zu, the meaning of h is as follows:

It comes from the term "hyperscript", which is commonly used in many virtual-dom implementations. "Hyperscript" itself stands for "script that generates HTML structures" because HTML is the acronym for "hyper-text markup language".

It comes from the term "hyperscript", which is commonly used in many virtual dom implementations. "Hyperscript" itself stands for "Script that generates HTML structure" because HTML is an acronym for "Hypertext Markup Language."

Reply source: github.com/vuejs/babel...

In fact, the h() function and the createVNode() function both create dom nodes, and their functions are the same, but in VUE3, the createVNode() function has more functions than the h() function and has been optimized for performance. The speed of the rendering node Also faster.

usage

  • The first parameter: HTML tag name, component, asynchronous component or functional component. Using a function that returns null will render a comment. This parameter is required.

  • The second parameter: an object, corresponding to the attributes, props, class, style, and events that we will use in the template. Optional.

  • The third parameter: child VNode, use

    h()
    Generate, or use a string to get a "text VNode", or an object with slots. Optional.

    // h('div', {}, [ 'Some text comes first.', h('h1', 'A headline'), h(MyComponent, { someProp: 'foobar' }) ])

GitHub

// [6] export function h(type: any, propsOrChildren?: any, children?: any): VNode { const l = arguments.length // if (l === 2) { // if (isObject(propsOrChildren) && !isArray(propsOrChildren)) { // VNode __v_isVNode isVNode VNode if (isVNode(propsOrChildren)) { return createVNode(type, null, [propsOrChildren]) } // return createVNode(type, propsOrChildren) } else { // props return createVNode(type, null, propsOrChildren) } } else { if (l > 3) { //Array.prototype.slice.call(arguments, 2), , arguments arguments slice() children = Array.prototype.slice.call(arguments, 2) } else if (l === 3 && isVNode(children)) { // 3 VNode children = [children] } //The main processing logic inside the h function is to perform corresponding processing operations according to the number of parameters and parameter types, but in the end, the VNode object is created by calling the createVNode function return createVNode(type, propsOrChildren, children) } } Copy code

defineComponent

Official definition:

defineComponent
Only return objects passed to it. However, as far as the type is concerned, the returned value has a synthetic type constructor for manual rendering functions, TSX and IDE tool support

DefinComponent is mainly used to help Vue correctly infer the parameter type of the setup() component under TS

Introduce defineComponent() to correctly infer the parameter type of the setup() component;

defineComponent can correctly adapt to forms without props, array props, etc.;

usage

  • **Parameter: **Object with component options or a

    setup
    Function, the function name will be used as the component name

    //Before writing Ts + vue, you need to declare the relevant data type. As follows //declare the data types of props and return interface Data { [key: string]: unknown } //When using, add a declaration when entering the parameters, and also add a declaration for return export default { setup(props: Data): Data { //... return { //... } } } //Very tedious, after using defineComponent, you can omit these type definitions, defineComponent can accept explicit custom props interface or automatically infer from the property verification object; //Example usage. 1: Import {defineComponent} from 'VUE' const MyComponent = defineComponent({ data () { return { count : 1 } }, methods : { increment () { this .count++ } } }) //Usage example 2: //Not only for setup, as long as it is Vue's own API, defineComponent can automatically deduce it for you. Import {defineComponent} from 'VUE' Export default defineComponent ({ setup (props, context) { //... return { //... } } }) Copy code

Source code analysis

GitHub address: source file location

... ... ... //In fact, this api is just the options passed in directly by return, export default defineComponent({}) is a bit equivalent to export default {}. At present, it seems that the biggest effect of this is to limit the type, setup must be a function, and props must be Is undefined or object. export function defineComponent ( options: unknown ) { return isFunction(options)? { setup : options, name : options.name}: options } Copy code

defineAsyncComponent

Official definition: Create an asynchronous component that will be loaded only when needed.

usage

Parameters: accept a return

Promise
Factory function. Promise
resolve
The callback should be called after the server returns the component definition.

//In Vue 2.x, you only need to declare an asynchronous component like this const asyncModal = () => import ( './Modal.vue' ) //Or const asyncModal = { component : () => import ( './Modal.vue' ), delay : 200 , timeout : 3000 , error : ErrorComponent, loading : LoadingComponent } //Now, in Vue 3, since the functional component is defined as a pure function, thus defining the components required by the asynchronous wrapped to explicitly define the new helper method defineAsyncComponent: Import {defineAsyncComponent} from 'VUE' import ErrorComponent from './components/ErrorComponent.vue' import LoadingComponent from './components/LoadingComponent.vue' //Asynchronous component without options const asyncModal = defineAsyncComponent( () => import ( './Modal.vue' )) //Asynchronous component with options. Another change made to 2.x is that the component option is now renamed to loader in order to accurately convey information that cannot directly provide component definitions. Note: defineAsyncComponent cannot be used on Vue Router! const asyncModalWithOptions = defineAsyncComponent({ loader : () => import ( './Modal.vue' ), delay : 200 , timeout : 3000 , errorComponent : ErrorComponent, loadingComponent : LoadingComponent }) Copy code

Source code analysis

GitHub address: Line 41-Line 196

//See above for the source code location export function defineAsyncComponent < T extends Component = { new (): ComponentPublicInstance} >(source: AsyncComponentLoader<T> | AsyncComponentOptions<T>): T { if (isFunction(source)) { source = { loader : source} } //The parameters of the asynchronous component const { loader, loadingComponent, errorComponent, delay = 200 , timeout, //undefined = never times out suspensible = true , onError : userOnError } = source let pendingRequest: Promise <ConcreteComponent> | null = null let resolvedComp: ConcreteComponent | undefined let retries = 0 //Try load again to get the component content const retry = () => { retries++ pendingRequest = null return load() } const load = (): Promise <ConcreteComponent> => { let thisRequest: Promise <ConcreteComponent> return ( //If pendingRequest exists, return, otherwise execute loader() pendingRequest || (thisRequest = pendingRequest = loader() //Handling failure scenarios. catch( err => { err = err instanceof Error ? err: new Error ( String (err)) if (userOnError) { //Corresponding to the failure capture callback function in the document, the user uses return new Promise ( ( resolve, reject ) => { const userRetry = () => resolve(retry()) const userFail = () => reject(err) userOnError(err, userRetry, userFail, retries + 1 ) }) } else { throw err } }) .then ( ( CoMP: the any ) => { //personal understanding: in thisRequest = pendingRequest = loader (), loader () waits for the beginning part of the state, assigned to pendingRequest, at the moment they are equal thisRequest wait state when entering When then pendingRequest has changed, so return pendingRequest if (thisRequest !== pendingRequest && pendingRequest) { return pendingRequest } //If in the DEV environment, warn if (__DEV__ && !comp) { warn( `Async component loader resolved to undefined. ` + `If you are using retry(), make sure to return its return value.` ) } //interop module default if ( comp && (comp.__esModule || comp[ Symbol .toStringTag] === 'Module' ) ) { comp = comp.default } //If in the DEV environment, warn if (__DEV__ && comp && !isObject(comp) && !isFunction(comp)) { throw new Error ( `Invalid async component load result: ${comp} ` ) } resolvedComp = comp return comp })) ) } return defineComponent({ __asyncLoader : load, //Asynchronous component uniform name name : 'AsyncComponentWrapper' , //The component has a setup method to go setup logic setup () { const instance = currentInstance! //already resolved if (resolvedComp) { return () => createInnerComp(resolvedComp!, instance) } const onError = ( err: Error ) => { pendingRequest = null handleError( err, instance, ErrorCodes.ASYNC_COMPONENT_LOADER, !errorComponent /* do not throw in dev if user provided error component */ ) } //suspense-controlled or SSR. //In the corresponding document, if the parent component is a suspense, then only the promise result is returned and the rest of the control is handed over to suspense if ( (__FEATURE_SUSPENSE__ && suspensible && instance.suspense) || (__NODE_JS__ && isInSSRComponentSetup) ) { return load() .then( comp => { return () => createInnerComp(comp, instance) }) .catch( err => { onError(err) return () => errorComponent ? createVNode(errorComponent as ConcreteComponent, { error : err }) : null }) } const loaded = ref( false ) const error = ref() const delayed = ref(!!delay) if (delay) { setTimeout ( () => { delayed.value = false }, delay) } if (timeout != null ) { setTimeout ( () => { if (!loaded.value && !error.value) { const err = new Error ( `Async component timed out after ${timeout} ms.` ) onError(err) error.value = err } }, timeout) } load() .then( () => { //After the promise returns successfully, the trigger is triggered to cause the component to update and re-render the component, but at this time we have got the component content loaded.value = true }) .catch( err => { onError(err) error.value = err }) //The returned function will be treated as the render function of the component instance return () => { //The initial execution of render triggers loaded dependency collection if (loaded.value && resolvedComp) { return createInnerComp(resolvedComp, instance) } else if (error.value && errorComponent) { return createVNode(errorComponent as ConcreteComponent, { error : error.value }) } else if (loadingComponent && !delayed.value) { return createVNode(loadingComponent as ConcreteComponent) } } } }) as any } Copy code

resolveComponent

Official definition: if available in the current application instance, resolution by name is allowed

component
, Returns a
Component
. If not found, return the received parameters
name
.

usage

Parameters: the name of the loaded component

const app = createApp({}) app.component( 'MyComponent' , { /* ... */ }) Import {resolveComponent} from 'VUE' the render () { const MyComponent = resolveComponent( 'MyComponent' ) } Copy code

Source code analysis

GitHub address:

//Receive a name parameter, which is mainly processed in the resolveAsset method. See the source code location above [7] export function resolveComponent ( name: string, maybeSelfReference?: boolean ): ConcreteComponent | string { return resolveAsset(COMPONENTS, name, true , maybeSelfReference) || name } //The resolveAsset source code is at the address above [8] function resolveAsset ( type: AssetTypes, name: string, warnMissing = true , maybeSelfReference = false ) { //Find the current rendering instance, if it does not exist, it will be the current instance const instance = currentRenderingInstance || currentInstance if (instance) { const Component = instance.type //The self name has the highest priority if (type === COMPONENTS) { //getComponentName first determines whether the passed Component parameter is a function, if it is a function, the .displayName attribute is used first, and then .name const selfName = getComponentName( Component) if ( //camelize uses the replace method, regular//(\w)/gname, after matching, toUpperCase() is converted to uppercase //capitalize function: str.charAt(0).toUpperCase() + str.slice(1 ) Initial capitalization + processed characters selfName && (selfName === name || selfName === camelize(name) || selfName === capitalize(camelize(name))) ) { return Component } } const res = //Registration //First check the instance [type], it is resolved as an option API resolve(instance[type] || (Component as ComponentOptions)[type], name) || //Global registration resolve(instance.appContext[type], name) if (!res && maybeSelfReference) { return Component } if (__DEV__ && warnMissing && !res) { warn( `Failed to resolve ${type.slice( 0 , -1 )} : ${name} ` ) } return res } else if (__DEV__) { //If the instance does not exist, and warning in the DEV environment: can only be used in render() or setup() warn( `resolve ${capitalize(type.slice( 0 , -1 ))} ` + `can only be used in render() or setup().` ) } } Copy code

resolveDynamicComponent

Official definition: return parsed

Component
Or newly created
VNode
, Where the component name is used as the node label. If not found
Component
, A warning will be issued.

usage

Parameters: accepts one parameter:

component

Import {resolveDynamicComponent} from 'VUE' render () { const MyComponent = resolveDynamicComponent( 'MyComponent' ) } Copy code

Source code analysis

GitHub address:

//The source code is located at the position above [9] //According to the name of the function, we can know that it is used to resolve dynamic components. Inside the resolveDynamicComponent function, if the component parameter is a string type, the resolveAsset method described earlier will be called To resolve the component, //if the resolveAsset function cannot get the corresponding component, it will return the value of the current component parameter. For example, resolveDynamicComponent('div') will return the string'div' //The source code is shown above [1] address export function resolveDynamicComponent ( component: unknown ): VNodeTypes { if (isString(component)) { return resolveAsset(COMPONENTS, component, false ) || component } else { //Invalid type will cause a warning. If the component parameter is not a string type, it will return the execution result of the statement component || NULL_DYNAMIC_COMPONENT, where the value of NULL_DYNAMIC_COMPONENT is a Symbol object. return (component || NULL_DYNAMIC_COMPONENT) as any } } //For resolveAsset function analysis, please refer to the copy code at [8] above

resolveDirective

If available in the current application instance, it is allowed to resolve one by its name

directive
. Return a
Directive
. If not found, return
undefined
.

usage

  • The first parameter: the name of the loaded instruction.

Source code analysis

GitHub address:

/** * For the source code location, see the location above [10] */ export function resolveDirective ( name: string ): Directive | undefined { //Then call the resolveAsset method introduced earlier to resolve the component. For the resolution of the resolveAsset function, see the position above [8] return resolveAsset(DIRECTIVES, name) } Copy code

withDirectives

Official definition: Allow instructions to be applied to VNode . Return a VNode containing application instructions.

usage

  • The first parameter: a virtual node, usually used

    h()
    create

  • The second parameter: an instruction array, each instruction itself is an array, and up to 4 indexes can be defined.

Import {withDirectives, resolveDirective} from 'VUE' const foo = resolveDirective ( 'foo' ) const bar = resolveDirective ( 'bar' ) return withDirectives(h( 'div' ), [ [foo, this .x], [bar, this .y] ]) Copy code

Source code analysis

GitHub address:

//The source code link is at the position above [11] export function withDirectives < T extends VNode >( vnode: T, directives: DirectiveArguments ): T { //Get the current instance const internalInstance = currentRenderingInstance if (internalInstance === null ) { //If you use withDirectives() outside the render function, an exception will be thrown: __DEV__ && warn( `withDirectives can only be used inside render functions.` ) return vnode } const instance = internalInstance.proxy //Bind the dirs property on the vnode and traverse the incoming directives array const bindings: DirectiveBinding[] = vnode.dirs || (vnode.dirs = []) for ( let i = 0 ; i <directives.length; i++) { let [dir, value, arg, modifiers = EMPTY_OBJ] = directives[i] if (isFunction(dir)) { dir = { mounted : dir, updated : dir } as ObjectDirective } bindings.push({ dir, instance, value, oldValue : void 0 , arg, modifiers }) } return vnode } Copy code

createRenderer

Official definition: The createRenderer function accepts two generic parameters:

HostNode
with
HostElement
, Corresponding to the Node and Element types in the host environment.

usage

  • The first parameter: the node in the HostNode host environment.
  • The second parameter: Element in the host environment.
//For runtime-dom, HostNode will be the DOM Node interface, and HostElement will be the DOM Element interface. //Custom renderers can pass in platform-specific types, as shown below: //createRenderer(HostNode, HostElement), two general parameters HostNode (node in the host environment) and HostElement (element in the host environment), corresponding to the host environment. //reateRenderer (Use the (optional) option to create a Renderer instance.), this method returns baseCreateRenderer export function createRenderer < HostNode = RendererNode , HostElement = RendererElement >( options: RendererOptions<HostNode, HostElement> ) { return baseCreateRenderer<HostNode , HostElement>(options) } Copy code

Source code analysis

export function createRenderer < HostNode = RendererNode , HostElement = RendererElement >( options: RendererOptions<HostNode, HostElement> ) { return baseCreateRenderer<HostNode, HostElement>(options) } //baseCreateRenderer, which is about 2000 lines of code, is not posted here intact. Inside is the core code for rendering. Relevant APIs are taken from the platform feature options to implement patch, processing nodes, processing components, update components, and installation Component instance and other methods eventually return a renderer object. function baseCreateRenderer ( options: RendererOptions, createHydrationFns?: typeof createHydrationFunctions ): any { //compile-time feature flags check if (__ESM_BUNDLER__ && !__TEST__) { initFeatureFlags() } if (__DEV__ || __FEATURE_PROD_DEVTOOLS__) { const target = getGlobalThis() target.__VUE__ = true setDevtoolsHook(target.__VUE_DEVTOOLS_GLOBAL_HOOK__) } const { INSERT : hostInsert, Remove : hostRemove, patchProp : hostPatchProp, forcePatchProp : hostForcePatchProp, the createElement : hostCreateElement, CreateText : hostCreateText, createComment : hostCreateComment, the setText : hostSetText, setElementText : hostSetElementText, the parentNode : hostParentNode, the nextSibling : hostNextSibling, setScopeId : hostSetScopeId = NOOP, cloneNode : hostCloneNode, insertStaticContent: hostInsertStaticContent } = options ... ... ... //Return the three functions of render hydrate createApp, the generated render is passed to createAppAPI, hydrate is an optional parameter, it will be used in the ssr scenario; return { render, hydrate, createApp : createAppAPI(render, hydrate) } } Copy code

nextTick

Official definition: postpone the callback to be executed after the next DOM update cycle. Use it immediately after changing some data to wait for the DOM to update.

Import {createApp, nextTick} from 'VUE' const app = createApp({ setup () { const message = ref( 'Hello!' ) const changeMessage = async newMessage => { message.value = newMessage await nextTick() console .log( 'Now DOM is updated' ) } } }) Copy code

Source code analysis

GitHub address:

//The source code is at the top //Create an asynchronous task directly here, but changing the dom attribute is also an asynchronous strategy. How to ensure that the dom loading is completed //Vue2.x will judge whether the browser supports the promise attribute -> whether it supports MutationObserver -> whether it supports setImmediate -> neither Support the use of setTimeout, Vue3 no longer supports IE11, so nextTick directly uses Promise //Vue performs DOM updates asynchronously. As long as data changes are observed, Vue will open a queue and buffer all data changes that occur in the same event loop. If the same watcher is triggered multiple times, it will only be pushed into the queue once. This removal of duplicate data during buffering is very important to avoid unnecessary calculations and DOM operations. Then, in the next event loop "tick", Vue flushes the queue and performs the actual (deduplicated) work. export function nextTick ( this : ComponentPublicInstance | void , fn?: () => void ): Promise < void > { const p = currentFlushPromise || resolvedPromise return fn? p.then( this ? fn.bind( this ): fn): p } //If you set vm.someData ='new value', the component will not be re-rendered immediately. When the queue is refreshed, the component will be updated at the next "tick" when the event loop queue is emptied. If you want to do something after the DOM state is updated, you can use Vue.nextTick(callback) immediately after the data changes. Copy code

mergeProps

Official definition: Combine multiple objects containing VNode prop into a single object. What it returns is a newly created object, and the object passed as a parameter will not be modified.

usage

Parameters: Unlimited number of objects can be passed

Import {H, mergeProps} from 'VUE' Export default { inheritAttrs : to false , the render () { const props = mergeProps({ //This class will be merged with other classes in $attrs. class : 'active' }, this .$attrs) return h( 'div' , props) } } Copy code

Source code analysis

GitHub address:

export function mergeProps ( ...args: (Data & VNodeProps)[] ) { //extend is the Object.assign method, the first parameter of ret merge is the object const ret = extend({}, args[ 0 ]) //Traverse the args parameter for ( let i = 1 ; i <args.length; i++) { const toMerge = args[i] for ( const key in toMerge) { if (key === 'class' ) { //merge class if (ret.class !== toMerge.class) { ret.class = normalizeClass([ret.class, toMerge.class]) } } else if (key === 'style' ) { //merge style ret.style = normalizeStyle([ret.style, toMerge.style]) } else if (isOn(key)) {, //Determine if const existing = ret[key] const incoming = toMerge[key] if (existing !== incoming) { //If the first parameter Does not exist, merge, otherwise add ret[key] = existing ? [].concat(existing as any, incoming as any) : incoming } } else if (key !== '' ) { //add attribute if key is not empty ret[key] = toMerge[key] } } } return ret } Copy code

useCssModule

Official definition: Allowed in

Access the CSS module in the single-file component function.

usage

  • Parameters: The name of the CSS module. The default is
    '$style'
//useCssModule can only be used in render or setup functions. //The name here can not only fill in $style, /* *<style module="aaa" * ... *</style> */ //In this way, you can use const style = useCssModule('aaa') to get the corresponding content <script> Import {H, useCssModule} from 'VUE' Export default { setup () { const style = useCssModule() return () => h( 'div' , { class : style.success }, 'Task complete!' ) } } </script> < style module > .success { color : #090 ; } </style > //After adding a module to <style>, the calculated properties of $style will be automatically injected into the component. < style module > .six color : red; } .one font-size : 62px ; } </style > //After adding the model, you can directly use the $style binding attribute < template > < div > < p :class = "$style.red" > hello red! </p > </div > </template > Copy code

Source code analysis

GitHub address:

useCssModule() : 1 line-30 lines

import {warn, getCurrentInstance} from '@vue/runtime-core' import {EMPTY_OBJ} from '@vue/shared' //Take out this.$style export function useCssModule ( name = '$style' ): Record < string , string > { /* If it is an istanbul coverage test, then jump out */ if (!__GLOBAL__) { //Get the current instance const instance = getCurrentInstance()! if (!instance) { //useCssModule can only be used in render or setup functions. __DEV__ && warn( `useCssModule must be called inside setup()` ) //EMPTY_OBJ uses Object.freeze() to freeze the object return EMPTY_OBJ } const modules = instance.type.__cssModules //If there is no css module, warn if (!modules) { __DEV__ && warn( `Current instance does not have CSS modules injected.` ) return EMPTY_OBJ } const mod = modules[name] //If there is no css module whose name is not found, warn if (!mod) { __DEV__ && warn( `Current instance does not have CSS module named " ${name} " .` ) return EMPTY_OBJ } return mod as Record<string, string> } else { if (__DEV__) { warn( `useCssModule() is not supported in the global build.` ) } return EMPTY_OBJ } } Copy code

version

Official definition: Provide the version number of the installed Vue in the form of a string.

//The version in vue-next/packages/vue/package.json is 3.1.2, use .split('.')[0] to get 3 const version = Number (Vue.version.split( '.' )[ 0 ]) if (version === 3 ) { //Vue 3 } else if (version === 2 ) { //Vue 2 } else { //Unsupported version of Vue } Copy code

Reference

Vue-next-GitHub

Vue3 official documentation

Vue3 source code analysis

vue3 VNode

end

Well, the above is all the content of this article.

If you encounter problems or have other comments, you can post them in the comment section below!

The code word is not easy. If you think this article is helpful to you, I hope you can leave a comment and like to support it, thank you very much~