The passage contains 5314 words and is expected to take 5-15 minutes to read.

preface

Unconsciously vue-next version has come to 3.1.2, recently compared with the source code to learn the global Api of Vue3, while learning to sort out down, I hope you can progress together.

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

The following is a summary of the Vue3 global Api, if you have a better understanding and ideas, you can leave a comment section, I will reply to each

Global API

Global apis are methods that are mounted directly on Vue. In Vue, there are 13 global apis. Respectively is:

  • Createapp returns an application instance that provides the context for the application;
  • H returns a “virtual node;
  • Definecomponent returns an object with options, under TS, that gives the component the correct argument type inference;
  • Defineasynccomponent creates an asynchronous component that will be loaded only when needed;
  • Resolvecomponent resolves the component by the incoming component name.
  • Resolvedynamiccomponent returns the parsed Component or the newly created VNode;
  • Resolvedirective resolves a directive by its name.
  • Withdirectives Returns a VNode that contains the application directives;
  • Createrenderer cross-platform custom rendering;
  • Nexttick is a callback function that is deferred until after the next DOM update;
  • Mergeprops merges multiple objects containing a VNode Prop into a single object;
  • Usecssmodule accesses the CSS module;
  • Version Displays the version number of the installed Vue.

createApp

Official definition: Returns an application instance that provides context for the application. The entire tree of components that the application instance mounts shares the same context.

As the name suggests, CreateApp acts as the launch function for VUE, returning an application instance. Each VUE application first creates a new application instance using the following function. Most methods exposed by the application instance return the same instance and can be called in chains. Such as:

Vue.createApp({}).component('SearchInput', SearchInputComponent)
Copy the code

usage

  • First parameter: receive a root component option

  • Second parameter: pass the root prop to the application

// Examples of usage
import { createApp, h, nextTick } from 'vue'
const app = createApp({
  data() {
    return{... }},methods: {... },computed: {...}
  ...
},
    { username: 'Evan' })
Copy the code

Source analyses

Making address:

  • CreateApp () : 56 lines – 102 lines of content [1]
  • EnsureRenderer () : ensureRenderer() : ensureRenderer();
  • CreateRenderer () : 419 lines – 424 lines of content [3]
  • BaseCreateRenderer () : 448 lines – 2418 lines [4]
  • App. _component:Line 174[5]
// Source location above [1]
export const createApp = ((. args) = > {
    // To create the app object with ensureRenderer().createApp()
    // Above the source [2]
    -> ensureRenderer; // -> ensureRenderer
    // Above the source [3]
    // -> 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(create a Renderer instance with the (optional) option.) , which returns the baseCreateRenderer
    // Source location above [4]
    // -> baseCreateRenderer returns three functions render hydrate createApp, render to createAppAPI, and hydrate is optional;
  constapp = ensureRenderer().createApp(... args)if (__DEV__) {
     // DEV is used to verify whether the component name is a native tag or an SVG attribute tag
    injectNativeTagCheck(app)
     In // DEV, check CompilerOptions to show warnings if they have deprecated properties
    injectCompilerOptionsCheck(app)
  }

  const { mount } = app
  // Retrieve the mount from the created app object, rewrite the mount method, and return to the app instance
  app.mount = (containerOrSelector: Element | ShadowRoot | string): any= > {
    // Container is a real DOM element. The normalizeContainer method uses document.querySelector to handle the incoming 
      
        parameter. If the element does not exist in the DEV environment, or if the element is a shadow DOM and the mode state is closed, the appropriate warning is returned
      
    const container = normalizeContainer(containerOrSelector)
    // Return if it is not a real DOM element
    if(! container)return
	
     // App._component is the first parameter of the global API createApp, and the source is located at the top [5]
    const component = app._component
    // Component is not a function and does not contain render, template
    if(! isFunction(component) && ! component.render && ! component.template) {// Unsafe situation
      // Cause: It is possible to execute JS expressions in the DOM template.
      // The user must ensure that the internal DOM template is trusted. If it is
      // The template should not contain any user data.
        
       // Use the innerHTML of the DOM as the component. Template content
      component.template = container.innerHTML
      If the cloak attribute name is not in the V-cloak state and the attribute name contains v-, :, and @, the vUE document link will be displayed
      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 = ' '
    // The actual mount (element, whether reuse, whether is SVG element)
    const proxy = mount(container, false, container instanceof SVGElement)
    if (container instanceof Element) {
      // Remove the Cloak directive from the element
      container.removeAttribute('v-cloak')
      // Set the data-v-app property
      container.setAttribute('data-v-app'.' ')}return proxy
  }

  return app
}) as CreateAppFunction<Element>

Copy the code

h

Official definition: Returns a “virtual node”, usually abbreviated as VNode: a common object that contains information to Vue describing what kind of node it should render on the page, including descriptions of all child nodes. It is intended for manually written rendering functions;

What does h stand for? According to the reply, 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 structures,” because HTML is an acronym for hyperText Markup Language.

Reply from: github.com/vuejs/babel…

The h() and createVNode() functions both create dom nodes, so they do the same thing, but in VUE3 the createVNode() function has more functionality than the h() function and has been optimized to render the nodes faster.

usage

  • 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 attribute, prop, class, style, and event we will use in the template. Optional.

  • The third argument, the descendant VNode, is generated using h(), or a string to get a “text VNode”, or an object with a slot. Optional.

    // Examples of usage
    h('div', {},'Some text comes first.',
      h('h1'.'A headline'),
      h(MyComponent, {
        someProp: 'foobar'})])Copy the code

Source analyses

Making address:

  • H:Line 174. – Line 196[6]
// See above for source code location [6]
export function h(type: any, propsOrChildren? : any, children? : any) :VNode {
  const l = arguments.length
  // If the argument is two
  if (l === 2) {
      // Check whether it is an object and not an array
    if(isObject(propsOrChildren) && ! isArray(propsOrChildren)) {// All VNode objects have an __v_isVNode attribute, and the isVNode method uses this attribute to determine whether it is a VNode object.
      if (isVNode(propsOrChildren)) {
        return createVNode(type, null, [propsOrChildren])
      }
      // Contain only attributes but no child elements
      return createVNode(type, propsOrChildren)
    } else {
      // Ignore the props attribute
      return createVNode(type, null, propsOrChildren)
    }
  } else {
    if (l > 3) {
      / / Array. Prototype. Slice. The call (the arguments, 2), the meaning of this sentence to intercept calls the method of parameters, can understand to make the arguments into an Array object, let the arguments have slice () method
      children = Array.prototype.slice.call(arguments.2)}else if (l === 3 && isVNode(children)) {
      // If the length of the argument is 3 and the third argument is a VNode object
      children = [children]
    }
    // The main processing logic inside the h function is to perform the corresponding processing operations based on the number and type of parameters, but ultimately the VNode object is created by calling the createVNode function
    return createVNode(type, propsOrChildren, children)
  }
}
Copy the code

defineComponent

Official definition: defineComponent only returns the objects passed to it. However, in terms of type, the returned value has a synthetic type constructor for manual rendering functions, TSX, and IDE tool support

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

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

DefineComponent can correctly match no props, array props and other forms;

usage

  • ** Arguments: ** An object with component options or a setup function whose name is used as the component name

    // Before you write Ts + vue, you need to declare the related data type. The following
    // Declare the props and return types
    interface Data {
      [key: string]: unknown
    }
    // Return () {return () {return ()
    export default {
      setup(props: Data): Data {
        // ...
        return {
          // ...}}}// defineComponent can accept explicit, custom props interface or automatic inference from attribute validation objects; // defineComponent can accept explicit, custom props interface or automatic inference from attribute validation objects.
    
    // Example 1:
    import { defineComponent } from 'vue'
    
    const MyComponent = defineComponent({
      data() {
        return { count: 1}},methods: {
        increment() {
          this.count++
        }
      }
    })
    
    // Example 2:
    // defineComponent automatically deduces Vue apis for you, not just setup.
    import { defineComponent } from 'vue'
    export default defineComponent({
      setup (props, context) {
        // ...
        
        return {
          // ...}}})Copy the code

Source analyses

GitHub address: source file location

. . .Export default defineComponent({}) is equivalent to export default {}. Setup must be a function, and props must be either undefined or an object.
export function defineComponent(options: unknown) {
  return isFunction(options) ? { setup: options, name: options.name } : options
}
Copy the code

defineAsyncComponent

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

usage

Argument: Accepts a factory function that returns a Promise. The Promise’s resolve callback should be called after the server returns the component definition.

// In Vue 2.x, declaring an asynchronous component only requires 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 functional components are defined as pure functions, the definition of an asynchronous component needs to be explicitly defined by wrapping it in the new defineAsyncComponent helper method:
import { defineAsyncComponent } from 'vue'
import ErrorComponent from './components/ErrorComponent.vue'
import LoadingComponent from './components/LoadingComponent.vue'

// An asynchronous component with no options
const asyncModal = defineAsyncComponent(() = > import('./Modal.vue'))

// Asynchronous components with options. Another change made to 2.x is that the Component option is now renamed loader to accurately convey information that cannot be directly provided by 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 the code

Source analyses

GitHub address: lines 41 to 196

// See above for the source 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 again to load the component content
  const retry = () = > {
    retries++
    pendingRequest = null
    return load()
  }

  const load = (): Promise<ConcreteComponent> => {
    let thisRequest: Promise<ConcreteComponent>
    return (
      // Return if the pendingRequest exists, otherwise implement loader()
      pendingRequest ||
      (thisRequest = pendingRequest = loader()
       // Failure scenario processing
        .catch(err= > {
          err = err instanceof Error ? err : new Error(String(err))
          if (userOnError) {
            // Use the failure capture callback function in the corresponding document
            return new Promise((resolve, reject) = > {
              const userRetry = () = > resolve(retry())
              const userFail = () = > reject(err)
              userOnError(err, userRetry, userFail, retries + 1)})}else {
            throw err
          }
        })
        .then((comp: any) = > {
          // Personal understanding: ThisRequest = pendingRequest = Loader (), loader() is in the wait state at the beginning, and is assigned to the pendingRequest. When we enter the THEN, the pendingRequest has changed, so return the pendingRequest
          if(thisRequest ! == pendingRequest && pendingRequest) {return pendingRequest
          }
          // If in the DEV environment, warning
          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, warning
          if(__DEV__ && comp && ! isObject(comp) && ! isFunction(comp)) {throw new Error(`Invalid async component load result: ${comp}`)
          }
          resolvedComp = comp
          return comp
        }))
    )
  }

  return defineComponent({
    __asyncLoader: load,
    // Uniform name for asynchronous components
    name: 'AsyncComponentWrapper'.// The component has setup logic
    setup() {
      const instance = currentInstance!

      // already resolved
      if (resolvedComp) {
        return () = >createInnerComp(resolvedComp! , instance) }const onError = (err: Error) = > {
        pendingRequest = nullhandleError( err, instance, ErrorCodes.ASYNC_COMPONENT_LOADER, ! errorComponent/* do not throw in dev if user provided error component */)}// suspense-controlled or SSR.
      Suspense only returns promise results if the parent component in the corresponding document is a suspense component and gives the rest of the control 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()
      constdelayed = 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(() = > {
          // When the promise returns successfully, the trigger causes the component to update and rerender the component, except that we already have the component content
          loaded.value = true
        })
        .catch(err= > {
          onError(err)
          error.value = err
        })

      // The returned function is treated as the render function of the component instance
      return () = > {
        // The initial execution of Render triggers the dependency collection of Loaded
        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 the code

resolveComponent

Official definition: Allows resolution of a Component by name, returning a Component, if available in the current application instance. If it is not found, the received parameter name is returned.

usage

Parameter: The name of the loaded component

const app = createApp({})
app.component('MyComponent', {
  / *... * /
})

import { resolveComponent } from 'vue'
render() {
  const MyComponent = resolveComponent('MyComponent')}Copy the code

Source analyses

Making address:

  • ResolveComponent () :Row 21 – row 27 [7]
  • ResolveAsset () :Line 62 minus line 123 [8]
// Receive a name parameter, which is handled mainly in the resolveAsset method. See above for source code [7]
export function resolveComponent(name: string, maybeSelfReference? : boolean) :ConcreteComponent | string {
  return resolveAsset(COMPONENTS, name, true, maybeSelfReference) || name
}

// resolveAsset source at top address [8]
function resolveAsset(
  type: AssetTypes,
  name: string,
  warnMissing = true,
  maybeSelfReference = false
) {
  // Look for the current render instance, if it does not exist
  const instance = currentRenderingInstance || currentInstance
  if (instance) {
    const Component = instance.type

    // The self name has the highest priority
    if (type === COMPONENTS) {
      // getComponentName specifies whether the Component parameter is a function. If it is a function, the.displayName property is used first, followed by the.name property
      const selfName = getComponentName(Component)
      if (
        // camelize uses replace method, re /-(\w)/gname, and convert toUpperCase() toUpperCase after matching
        // Capitalize function: str.charat (0).toupperCase () + str.slice(1) Capitalize the character that has been processed
        selfName &&
        (selfName === name ||
          selfName === camelize(name) ||
          selfName === capitalize(camelize(name)))
      ) {
        return Component
      }
    }

    const res =
      / / register
      // First check the instance [type], which is parsed as the option API
      resolve(instance[type] || (Component as ComponentOptions)[type], name) ||
      // Register globally
      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__) {
    Can only be used in render() or setup() if the instance does not exist and is in the DEV environment
    warn(
      `resolve${capitalize(type.slice(0, -1))} ` +
        `can only be used in render() or setup().`)}}Copy the code

resolveDynamicComponent

Official definition: Returns the parsed Component or newly created VNode with the Component name as the node label. A warning is issued if the Component cannot be found.

usage

Parameters: Take one parameter: Component

import { resolveDynamicComponent } from 'vue'
render () {
  const MyComponent = resolveDynamicComponent('MyComponent')}Copy the code

Source analyses

Making address:

  • ResolveDirective () : Lines 43-48 [9]
  • ResolveAsset () :Line 62 minus line 123
// The source location is at the top [9] location
// If the component argument is a string, then the resolveAsset method is called to resolve the component.
// If the resolveAsset function cannot retrieve the corresponding component, it returns the value of the current Component argument. For example, resolveDynamicComponent('div') will return the string 'div'
// See the [1] address above for the source code
export function resolveDynamicComponent(component: unknown) :VNodeTypes {
  if (isString(component)) {
    return resolveAsset(COMPONENTS, component, false) || component
  } else {
    / / invalid type will trigger a warning, but if the component parameters of type string, will return to the component | | NULL_DYNAMIC_COMPONENT this line statement execution results, The NULL_DYNAMIC_COMPONENT value is a Symbol object.
    return (component || NULL_DYNAMIC_COMPONENT) as any
  }
}

// The resolveAsset function is resolved at [8]
Copy the code

resolveDirective

Allows resolution of a directive by its name if it is available in the current application instance. Return a Directive. If it is not found, undefined is returned.

usage

  • First argument: the name of the loaded instruction.

Source analyses

Making address:

  • ResolveDirective () : lines 43-48 [10]
  • ResolveAsset () :Line 62 minus line 123
/** * see [10] above */
export function resolveDirective(name: string) :Directive | undefined {
  // Then call the resolveAsset method described above to resolve the component, as shown above [8]
  return resolveAsset(DIRECTIVES, name)
}
Copy the code

withDirectives

Official definition: Allows directives to be applied to vNodes. Returns a VNode containing the application directives.

usage

  • The first argument: a virtual node, usually created using h()

  • Second argument: an array of instructions, each of which is itself an array, with up to four indexes 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 the code

Source analyses

Making address:

  • ResolveDirective () : Line 85-114 content [11]
// The source link is at the top [11] position
export function withDirectives<T extends VNode> (vnode: T, directives: DirectiveArguments) :T {
  // Get the current instance
  const internalInstance = currentRenderingInstance
  if (internalInstance === null) {
    // An exception is thrown if you use withDirectives() outside the render function:
    __DEV__ && warn(`withDirectives can only be used inside render functions.`)
    return vnode
  }
  const instance = internalInstance.proxy
  // Bind the dirs property to vNode and iterate through the passed 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 the code

createRenderer

The createRenderer function takes two generic parameters: HostNode and HostElement, corresponding to the Node and Element types in the host environment.

usage

  • The first parameter: HostNode The node in the host environment.
  • The second parameter: Element The Element in the host environment.
// For runtime-dom, HostNode will be the DOM Node interface, and HostElement will be the DOM Element interface.
// A custom renderer can pass in a platform-specific type, as shown below:

// createRenderer(HostNode, HostElement), two general parameters HostNode(the node in the host environment) and HostElement(the element in the host environment), corresponding to the host environment.
// reateRenderer(create a Renderer instance with the (optional) option.) , which returns the baseCreateRenderer
export function createRenderer<
  HostNode = RendererNode.HostElement = RendererElement> (options: RendererOptions<HostNode, HostElement>) {
  return baseCreateRenderer<HostNode, HostElement>(options)
}
Copy the code

The source code parsing

  • CreateRenderer () : 419 lines – 424 lines of content [3]
  • BaseCreateRenderer () : 448 lines – 2418 lines [4]
export function createRenderer<
  HostNode = RendererNode.HostElement = RendererElement> (options: RendererOptions<HostNode, HostElement>) {
  return baseCreateRenderer<HostNode, HostElement>(options)
}

// baseCreateRenderer is about 2000 lines of code, which is the core code of rendering. The API is used to implement patch, process nodes, process components, update components, install component instances, and so on. It returns 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,
    createElement: hostCreateElement,
    createText: hostCreateText,
    createComment: hostCreateComment,
    setText: hostSetText,
    setElementText: hostSetElementText,
    parentNode: hostParentNode,
    nextSibling: hostNextSibling,
    setScopeId: hostSetScopeId = NOOP,
    cloneNode: hostCloneNode,
    insertStaticContent: hostInsertStaticContent } = options ... . .// Return the three functions render hydrate createApp, and send the generated render to createAppAPI, with the hydrate as an optional parameter.
  return {
    render,
    hydrate,
    createApp: createAppAPI(render, hydrate)
  }
}
Copy the code

nextTick

Official definition: defer callback execution until after the next DOM update cycle. Use it immediately after you have changed 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 the code

Source analyses

Making address:

  • NextTick () : 42-48 lines of content
// The source location is at the top

// Create an asynchronous task, but changing the DOM properties is also an asynchronous policy
// If vue2.x does not support the use of setTimeout, Vue3 does not support IE11. If vue2.x does not support the use of setTimeout, Vue3 does not support IE11. If vue2.x does not support the use of setTimeout, Vue3 does not support IE11. So nextTick uses a Promise directly

// Vue performs DOM updates asynchronously. As soon as a data change is observed, Vue opens a queue and buffers all data changes that occur in the same event loop. If the same watcher is fired multiple times, it will only be pushed into the queue once. This removal of duplicate data at buffering time is important to avoid unnecessary computation and DOM manipulation. Then, in the next event loop "tick", Vue refreshes 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 immediately rerender. When refreshing the queue, the component gets the next "tick" update when the event loop queue is empty. If you want to do something after the DOM status update, you can use vue.nexttick (callback) immediately after the data change.
Copy the code

mergeProps

Official definition: Combine multiple objects containing a VNode Prop into a single object. It returns a newly created object, and the object passed as an argument is not modified.

usage

Arguments: An unlimited number of objects can be passed

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

Source analyses

Making address:

  • MergeProps () : line 687 – line 712
export function mergeProps(. args: (Data & VNodeProps)[]) {
  // Extend is the object. assign method, and ret merges the first argument as an Object
  const ret = extend({}, args[0])
  // Iterate over the args parameter
  for (let i = 1; i < args.length; i++) {
    const toMerge = args[i]
    for (const key in toMerge) {
      if (key === 'class') {
        / / 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)),// I'm not going to do this
        const existing = ret[key]
        const incoming = toMerge[key]
        if(existing ! == incoming) {// If the first argument does not exist, merge, otherwise add
          ret[key] = existing
            ? [].concat(existing as any, incoming as any)
            : incoming
        }
      } else if(key ! = =' ') {
        // Add attributes if key is not empty
        ret[key] = toMerge[key]
      }
    }
  }
  return ret
}
Copy the code

useCssModule

Official definition: Allows CSS modules to be accessed from a single file component function of setup.

usage

  • Parameter: Name of the CSS module. The default is'$style'
// useCssModule can only be used in render or setup functions.
$style = '$style';
/*
*<style module="aaa"
* ...
*</style>
*/
// So we can use const style = useCssModule(' aaa') to get the 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>

// When you add a module to 
<style module>
.six
 color: red;
}
.one
 font-size:62px;
}
</style>
// You can use $style to bind properties directly after adding the model
<template>
 <div>
  <p :class="$style.red">
   hello red!
  </p>
 </div>
</template>
Copy the code

The source code parsing

Making address:

UseCssModule () : line 1 – line 30

import { warn, getCurrentInstance } from '@vue/runtime-core'
import { EMPTY_OBJ } from '@vue/shared'

/ / remove this. $style
export function useCssModule(name = '$style') :Record<string.string> {
  /* * * * * * * * * * */
  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 is to freeze objects using object.freeze ()
      return EMPTY_OBJ
    }
    const modules = instance.type.__cssModules
    // If there is no CSS module, warning
    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, warning
    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 the code

version

Official definition: The version number of an installed Vue is provided as a string.

/ / the vue - next/packages/vue/package. The json version for granted, in use. The split ('. ') [0], it is concluded that 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 the code

The resources

Vue-next-GitHub

Vue3 official documentation

Vue3 source analysis

vue3 VNode

At the end

Well, that’s all for this article.

If you have any questions or comments, please post them in the comment section below!

Code words are not easy. If you think this article is helpful to you, I hope you can leave a comment and support, thank you very much ~