欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

一文解析Vue h函數(shù)到底是個啥

 更新時間:2025年02月17日 09:49:31   作者:二川bro  
h()函數(shù)是Vue.js中的一個工具函數(shù),用于創(chuàng)建虛擬DOM節(jié)點,具有更高的靈活性和控制力,本文介紹Vue h函數(shù)到底是個啥,感興趣的朋友一起看看吧

h 到底是個啥?


 

對于了解或?qū)W習(xí)Vue高階組件(HOC)的同學(xué)來說,h() 函數(shù)無疑是一個經(jīng)常遇到的概念。

那么,這個h() 函數(shù)究竟如何使用呢,又在什么場景下適合使用呢?


 

一、h 是什么

看到這個函數(shù)你可能會有些許困惑,為什么叫h呢?代表著什么呢?
 

官方定義

返回一個“虛擬節(jié)點” ,通??s寫為 VNode: 一個普通對象,其中包含向 Vue 描述它應(yīng)該在頁面上呈現(xiàn)哪種節(jié)點的信息,包括對任何子節(jié)點的描述。用于手動編寫render

h其實代表的是 hyperscript 。它是 HTML 的一部分,表示的是超文本標(biāo)記語言,當(dāng)我們正在處理一個腳本的時候,在虛擬 DOM 節(jié)點中去使用它進行替換已成為一種慣例。這個定義同時也被運用到其他的框架文檔中

Hyperscript 它本身表示的是 “生成描述 HTML 結(jié)構(gòu)的腳本”

二、語法

h() 函數(shù)的基本語法如下:

h(tag, props, children)
  • tag:可以是字符串或組件,表示要創(chuàng)建的 HTML 標(biāo)簽或 Vue 組件。
  • props:是一個對象,包含要傳遞給標(biāo)簽或組件的屬性,如類名、樣式、事件監(jiān)聽器等。
  • children:可以是字符串、數(shù)組或函數(shù),表示子節(jié)點。子節(jié)點可以是文本、其他 VNode 或一個返回 VNode 的函數(shù)。

以下是一個簡單的代碼示例,展示了如何使用 h() 函數(shù)創(chuàng)建一個包含標(biāo)題和段落的組件:

  <!DOCTYPE html>
  <html>
    <head>
    <meta charset="utf-8">
    <title>h()</title>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/vue/3.0.0-rc.4/vue.global.js"></script>
    </head>
    <body>
       <div id="app">
       </div>
       <script>
        const App = {
          render() {
            return Vue.h('h1', {}, '二川兄弟')
          }
        }
        // console 結(jié)果請在控制臺查看
        console.log(Vue.h('h1', {}, '二川兄弟'))
        Vue.createApp(App).mount('#app')
      </script>
    </body>
  </html>

效果:

打?。?/p>

在這個示例中,我們創(chuàng)建了一個 <h1> 容器,內(nèi)部插入文字 “二川兄弟”。所有這些都是通過 h() 函數(shù)來實現(xiàn)的,而不是使用模板語法。

三、源碼解析

要深入理解 h() 函數(shù),我們需要查看 Vue.js 的源碼。在 Vue.js 的實現(xiàn)中,h() 函數(shù)是一個封裝了 VNode 創(chuàng)建邏輯的工具函數(shù)。它接收標(biāo)簽名、屬性和子節(jié)點作為參數(shù),并返回一個包含這些信息的 VNode 對象。

export function h(type: any, propsOrChildren?: any, children?: any): VNode {
  if (arguments.length === 2) {
    if (isObject(propsOrChildren) && !isArray(propsOrChildren)) {
      // single vnode without props
      if (isVNode(propsOrChildren)) {
        return createVNode(type, null, [propsOrChildren])
      }
      // props without children
      return createVNode(type, propsOrChildren)
    } else {
      // omit props
      return createVNode(type, null, propsOrChildren)
    }
  } else {
    if (isVNode(children)) {
      children = [children]
    }
    return createVNode(type, propsOrChildren, children)
  }
}

VNode 是 Vue.js 對真實 DOM 的一種輕量級表示。它包含了節(jié)點的類型、屬性、子節(jié)點等信息,但不包含具體的 DOM 元素。Vue.js 會在渲染時將 VNode 轉(zhuǎn)換為真實的 DOM 元素。

h() 函數(shù)的源碼中,你會看到大量的邊界情況處理和類型檢查。例如,如果子節(jié)點是一個字符串,它會被轉(zhuǎn)換為一個文本節(jié)點;如果子節(jié)點是一個數(shù)組,它會遍歷數(shù)組并遞歸地創(chuàng)建子節(jié)點的 VNode;如果子節(jié)點是一個函數(shù),它會調(diào)用該函數(shù)并傳遞當(dāng)前上下文來創(chuàng)建子節(jié)點的 VNode。

_createVNode 又做了啥?

function _createVNode(
  type: VNodeTypes | ClassComponent | typeof NULL_DYNAMIC_COMPONENT,
  props: (Data & VNodeProps) | null = null,
  children: unknown = null,
  // 更新標(biāo)志
  patchFlag: number = 0,
  // 自定義屬性
  dynamicProps: string[] | null = null,
  // 是否是動態(tài)節(jié)點,(v-if v-for)
  isBlockNode = false 
): VNode {
  // type必傳參數(shù)
  if (!type || type === NULL_DYNAMIC_COMPONENT) {
    if (__DEV__ && !type) {
      warn(`Invalid vnode type when creating vnode: ${type}.`)
    }
    type = Comment
  }
  // Class 類型的type標(biāo)準(zhǔn)化
  // class component normalization.
  if (isFunction(type) && '__vccOpts' in type) {
    type = type.__vccOpts
  }
  // class & style normalization.
  if (props) {
    // props 如果是響應(yīng)式,clone 一個副本
    if (isProxy(props) || InternalObjectKey in props) {
      props = extend({}, props)
    }
    let { class: klass, style } = props
    // 標(biāo)準(zhǔn)化class, 支持 string , array, object 三種形式
    if (klass && !isString(klass)) {
      props.class = normalizeClass(klass)
    }
    // 標(biāo)準(zhǔn)化style, 支持 array ,object 兩種形式 
    if (isObject(style)) {
      // reactive state objects need to be cloned since they are likely to be
      // mutated
      if (isProxy(style) && !isArray(style)) {
        style = extend({}, style)
      }
      props.style = normalizeStyle(style)
    }
  }
  // encode the vnode type information into a bitmap
  const shapeFlag = isString(type)
    ? ShapeFlags.ELEMENT
    : __FEATURE_SUSPENSE__ && isSuspense(type)
      ? ShapeFlags.SUSPENSE
      : isTeleport(type)
        ? ShapeFlags.TELEPORT
        : isObject(type)
          ? ShapeFlags.STATEFUL_COMPONENT
          : isFunction(type)
            ? ShapeFlags.FUNCTIONAL_COMPONENT
            : 0
  if (__DEV__ && shapeFlag & ShapeFlags.STATEFUL_COMPONENT && isProxy(type)) {
    type = toRaw(type)
    warn(
      `Vue received a Component which was made a reactive object. This can ` +
        `lead to unnecessary performance overhead, and should be avoided by ` +
        `marking the component with \`markRaw\` or using \`shallowRef\` ` +
        `instead of \`ref\`.`,
      `\nComponent that was made reactive: `,
      type
    )
  }
  // 構(gòu)造 VNode 模型
  const vnode: VNode = {
    __v_isVNode: true,
    __v_skip: true,
    type,
    props,
    key: props && normalizeKey(props),
    ref: props && normalizeRef(props),
    scopeId: currentScopeId,
    children: null,
    component: null,
    suspense: null,
    dirs: null,
    transition: null,
    el: null,
    anchor: null,
    target: null,
    targetAnchor: null,
    staticCount: 0,
    shapeFlag,
    patchFlag,
    dynamicProps,
    dynamicChildren: null,
    appContext: null
  }
  normalizeChildren(vnode, children)
  // presence of a patch flag indicates this node needs patching on updates.
  // component nodes also should always be patched, because even if the
  // component doesn't need to update, it needs to persist the instance on to
  // the next vnode so that it can be properly unmounted later.
  // patchFlag 標(biāo)志存在表示節(jié)點需要更新,組件節(jié)點一直存在 patchFlag,因為即使不需要更新,它需要將實例持久化到下一個 vnode,以便以后可以正確卸載它
  if (
    shouldTrack > 0 &&
    !isBlockNode &&
    currentBlock &&
    // the EVENTS flag is only for hydration and if it is the only flag, the
    // vnode should not be considered dynamic due to handler caching.
    patchFlag !== PatchFlags.HYDRATE_EVENTS &&
    (patchFlag > 0 ||
      shapeFlag & ShapeFlags.SUSPENSE ||
      shapeFlag & ShapeFlags.TELEPORT ||
      shapeFlag & ShapeFlags.STATEFUL_COMPONENT ||
      shapeFlag & ShapeFlags.FUNCTIONAL_COMPONENT)
  ) {
    // 壓入 VNode 棧
    currentBlock.push(vnode)
  }
  return vnode
}

四、使用場景

h() 函數(shù)在 Vue.js 中有多種使用場景,以下是一些常見的場景:

渲染函數(shù)

  • 當(dāng)需要完全控制組件的渲染邏輯時,可以使用渲染函數(shù),并在其中使用 h() 函數(shù)來創(chuàng)建 VNode。這種方式提供了比模板語法更高的靈活性和控制力。

以下是一個使用渲染函數(shù)的示例,展示了如何根據(jù)條件動態(tài)渲染不同的內(nèi)容:

import { h } from 'vue';
export default {
  props: ['isLoggedIn'],
  render() {
    return h('div', 
      {}, 
      this.isLoggedIn 
        ? h('p', {}, 'Welcome back!') 
        : h('p', {}, 'Please log in.')
    );
  }
};

高階組件(HOC)

  • 高階組件是一種模式,它接收一個組件作為參數(shù),并返回一個新的組件。在創(chuàng)建新組件的過程中,h() 函數(shù)用于定制或擴展原始組件的渲染邏輯。

以下是一個高階組件的示例,展示了如何為組件添加額外的類名:

function withClassName(WrappedComponent, className) {
  return {
    props: WrappedComponent.props,
    render() {
      return h(WrappedComponent, { ...this.$props, class: className });
    }
  };
}
// 使用高階組件
const MyComponentWithClass = withClassName(MyComponent, 'my-custom-class');

動態(tài)組件

  • 在需要根據(jù)條件動態(tài)渲染不同組件時,h() 函數(shù)可以方便地根據(jù)條件創(chuàng)建不同的 VNode。

以下是一個動態(tài)組件的示例,展示了如何根據(jù)條件渲染不同的組件:

import { h, defineComponent } from 'vue';
import ComponentA from './ComponentA.vue';
import ComponentB from './ComponentB.vue';
export default defineComponent({
  props: ['condition'],
  render() {
    return this.condition 
      ? h(ComponentA, { ...this.$props }) 
      : h(ComponentB, { ...this.$props });
  }
});

手動創(chuàng)建復(fù)雜結(jié)構(gòu)

  • 在某些情況下,可能需要手動創(chuàng)建復(fù)雜的組件結(jié)構(gòu),而不是使用模板語法。這時,h() 函數(shù)就顯得非常有用。

以下是一個手動創(chuàng)建復(fù)雜結(jié)構(gòu)的示例,展示了如何創(chuàng)建一個帶有嵌套子組件的表格:

import { h } from 'vue';
import TableRow from './TableRow.vue';
export default {
  props: ['data'],
  render() {
    return h('table', 
      {}, 
      this.data.map(row => 
        h(TableRow, { key: row.id, row: row })
      )
    );
  }
};

五、其他比較

與模板語法相比,使用 h() 函數(shù)提供了更高的靈活性和控制力。模板語法更適合于簡單的組件和靜態(tài)內(nèi)容,而 h() 函數(shù)則更適合于復(fù)雜的組件和動態(tài)內(nèi)容。

此外,與 JSX 相比,h() 函數(shù)更加簡潔和直接。JSX 是一種語法糖,它允許在 JavaScript 中編寫類似 HTML 的代碼。然而,JSX 需要額外的編譯步驟,并且可能會增加代碼的復(fù)雜性。而 h() 函數(shù)則是 Vue.js 內(nèi)置的工具函數(shù),無需額外的編譯步驟,并且更加符合 Vue.js 的設(shè)計哲學(xué)。

六、最佳實踐

在使用 h() 函數(shù)時,以下是一些最佳實踐:

保持簡潔

  • 盡量避免在渲染函數(shù)中編寫過多的邏輯??梢詫?fù)雜的邏輯拆分成多個函數(shù)或組件,以提高代碼的可讀性和可維護性。

使用輔助函數(shù)

  • 可以編寫一些輔助函數(shù)來簡化 h() 函數(shù)的使用。例如,可以編寫一個函數(shù)來創(chuàng)建帶有特定樣式的節(jié)點,或者一個函數(shù)來創(chuàng)建帶有事件監(jiān)聽器的節(jié)點。

避免過度使用

  • 在大多數(shù)情況下,模板語法已經(jīng)足夠滿足需求。只有在需要更高的靈活性和控制力時,才應(yīng)該考慮使用 h() 函數(shù)。

與模板語法結(jié)合使用

  • 可以將 h() 函數(shù)與模板語法結(jié)合使用。例如,可以在模板中使用 <script setup> 語法來定義渲染函數(shù),并在其中使用 h() 函數(shù)來創(chuàng)建復(fù)雜的節(jié)點結(jié)構(gòu)。

七、總結(jié)

h() 函數(shù)是 Vue.js 框架中一個強大且靈活的工具,用于在渲染函數(shù)中創(chuàng)建虛擬 DOM 節(jié)點。通過深入理解 h() 函數(shù)的語法、源碼和使用場景,開發(fā)者可以更好地掌握 Vue.js 的渲染機制,并在實際開發(fā)中靈活運用這一工具來創(chuàng)建高效、可維護的組件。無論是編寫渲染函數(shù)、實現(xiàn)高階組件,還是處理動態(tài)組件和復(fù)雜結(jié)構(gòu),h() 函數(shù)都是不可或缺的一部分。

到此這篇關(guān)于一文解析Vue h函數(shù)到底是個啥的文章就介紹到這了,更多相關(guān)Vue h函數(shù)內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • Vue?監(jiān)聽視頻播放時長的實例代碼

    Vue?監(jiān)聽視頻播放時長的實例代碼

    本文介紹了如何通過源碼實現(xiàn)對視頻實時時長、播放時長和暫停時長的監(jiān)聽,詳細(xì)闡述了相關(guān)技術(shù)的應(yīng)用方法,幫助開發(fā)者更好地掌握視頻監(jiān)控技術(shù),提高用戶體驗
    2024-10-10
  • vue3如何將html元素變成canvas(海報生成),進行圖片保存/截圖

    vue3如何將html元素變成canvas(海報生成),進行圖片保存/截圖

    這篇文章主要介紹了vue3實現(xiàn)將html元素變成canvas(海報生成),進行圖片保存/截圖,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2022-05-05
  • vue頁面渲染數(shù)組中數(shù)據(jù)文案后添加逗號最后不加

    vue頁面渲染數(shù)組中數(shù)據(jù)文案后添加逗號最后不加

    這篇文章主要為大家介紹了vue頁面渲染數(shù)組中數(shù)據(jù)文案后添加逗號最后不加逗號示例,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2023-08-08
  • vue.js獲得當(dāng)前元素的文字信息方法

    vue.js獲得當(dāng)前元素的文字信息方法

    下面小編就為大家分享一篇vue.js獲得當(dāng)前元素的文字信息方法,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2018-03-03
  • Vue SPA單頁面的應(yīng)用和對比

    Vue SPA單頁面的應(yīng)用和對比

    單頁面是指整個應(yīng)用程序只有一個唯一完整的 HTML 頁面,而其它所謂的頁面,其實都是組件片段而已,切換頁面也只是切換一個 HTML 中顯示不同的組件片段。在今后所有的開發(fā)項目都是單頁面應(yīng)用
    2022-08-08
  • 關(guān)于Vue-cli3煩人的eslint問題

    關(guān)于Vue-cli3煩人的eslint問題

    這篇文章主要介紹了關(guān)于Vue-cli3煩人的eslint問題,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2022-09-09
  • vue通過v-html指令渲染的富文本無法修改樣式的解決方案

    vue通過v-html指令渲染的富文本無法修改樣式的解決方案

    這篇文章主要介紹了vue通過v-html指令渲染的富文本無法修改樣式的解決方案,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2020-05-05
  • 一文搞懂Vue里的過渡和動畫

    一文搞懂Vue里的過渡和動畫

    在Vue中,過渡和動畫是一種用于在組件之間添加平滑過渡效果和動畫效果的高級用法,Vue提供了一些內(nèi)置的過渡和動畫功能,同時也支持自定義過渡和動畫效果,本文就給大家介紹一些Vue中過渡和動畫的高級用法,需要的朋友可以參考下
    2023-06-06
  • vue中的事件觸發(fā)(emit)及監(jiān)聽(on)問題

    vue中的事件觸發(fā)(emit)及監(jiān)聽(on)問題

    這篇文章主要介紹了vue中的事件觸發(fā)(emit)及監(jiān)聽(on)問題,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2022-10-10
  • vue使用SVG實現(xiàn)圓形進度條音樂播放

    vue使用SVG實現(xiàn)圓形進度條音樂播放

    這篇文章主要為大家詳細(xì)介紹了vue使用SVG實現(xiàn)圓形進度條音樂播放,文中示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2022-04-04

最新評論