91超碰碰碰碰久久久久久综合_超碰av人澡人澡人澡人澡人掠_国产黄大片在线观看画质优化_txt小说免费全本

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

Vue 3.0 中如何使用動態組件

發布時間:2021-07-09 11:14:03 來源:億速云 閱讀:308 作者:Leah 欄目:web開發

這篇文章給大家介紹Vue 3.0 中如何使用動態組件,內容非常詳細,感興趣的小伙伴們可以參考借鑒,希望對大家能有所幫助。

一、組件注冊

1.1 全局注冊

在 Vue 3.0 中,通過使用 app 對象的 component 方法,可以很容易地注冊或檢索全局組件。component 方法支持兩個參數:

  • name:組件名稱;

  • component:組件定義對象。

接下來,我們來看一個簡單的示例:

<div id="app">    <component-a></component-a>    <component-b></component-b>    <component-c></component-c> </div> <script>    const { createApp } = Vue    const app = createApp({}); // ①    app.component('component-a', { // ②      template: "<p>我是組件A</p>"    });    app.component('component-b', {      template: "<p>我是組件B</p>"    });    app.component('component-c', {      template: "<p>我是組件C</p>"    });    app.mount('#app') // ③ </script>

在以上代碼中,我們通過 app.component 方法注冊了 3 個組件,這些組件都是全局注冊的  。也就是說它們在注冊之后可以用在任何新創建的組件實例的模板中。

該示例的代碼比較簡單,主要包含 3 個步驟:創建 App 對象、注冊全局組件和應用掛載。其中創建 App  對象的細節,阿寶哥會在后續的文章中單獨介紹,下面我們將重點分析其他 2 個步驟,首先我們先來分析注冊全局組件的過程。

1.2 注冊全局組件的過程

在以上示例中,我們使用 app 對象的 component 方法來注冊全局組件:

app.component('component-a', {   template: "<p>我是組件A</p>" });

當然,除了注冊全局組件之外,我們也可以注冊局部組件,因為組件中也接受一個 components 的選項:

const app = Vue.createApp({   components: {     'component-a': ComponentA,     'component-b': ComponentB   } })

需要注意的是,局部注冊的組件在其子組件中是不可用的。接下來,我們來繼續介紹注冊全局組件的過程。對于前面的示例來說,我們使用的 app.component  方法被定義在 runtime-core/src/apiCreateApp.ts 文件中:

export function createAppAPI<HostElement>(   render: RootRenderFunction,   hydrate?: RootHydrateFunction ): CreateAppFunction<HostElement> {   return function createApp(rootComponent, rootProps = null) {     const context = createAppContext()     const installedPlugins = new Set()     let isMounted = false      const app: App = (context.app = {       // 省略部分代碼       _context: context,        // 注冊或檢索全局組件       component(name: string, component?: Component): any {         if (__DEV__) {           validateComponentName(name, context.config)         }         if (!component) { // 獲取name對應的組件           return context.components[name]         }         if (__DEV__ && context.components[name]) { // 重復注冊提示           warn(`Component "${name}" has already been registered in target app.`)         }         context.components[name] = component // 注冊全局組件         return app       },     })      return app   } }

當所有的組件都注冊成功之后,它們會被保存到 context 對象的 components 屬性中,具體如下圖所示:

Vue 3.0 中如何使用動態組件

顧名思義 context 是表示應用的上下文對象,那么該對象是如何創建的呢?其實,該對象是通過 createAppContext 函數來創建的:

const context = createAppContext()

而 createAppContext 函數被定義在 runtime-core/src/apiCreateApp.ts 文件中:

// packages/runtime-core/src/apiCreateApp.ts export function createAppContext(): AppContext {   return {     app: null as any,     config: { // 應用的配置對象       isNativeTag: NO,       performance: false,       globalProperties: {},       optionMergeStrategies: {},       isCustomElement: NO,       errorHandler: undefined,       warnHandler: undefined     },     mixins: [], // 保存應用內的混入     components: {}, // 保存全局組件的信息     directives: {}, // 保存全局指令的信息     provides: Object.create(null)   } }

分析完 app.component  方法之后,是不是覺得組件注冊的過程還是挺簡單的。那么對于已注冊的組件,何時會被使用呢?要回答這個問題,我們就需要分析另一個步驟 &mdash;&mdash; 應用掛載。

1.3 應用掛載的過程

為了更加直觀地了解應用掛載的過程,阿寶哥利用 Chrome 開發者工具的 Performance 標簽欄,記錄了應用掛載的主要過程:

Vue 3.0 中如何使用動態組件

在上圖中我們發現了一個與組件相關的函數 resolveComponent。很明顯,該函數用于解析組件,且該函數在 render  方法中會被調用。在源碼中,我們找到了該函數的定義:

// packages/runtime-core/src/helpers/resolveAssets.ts const COMPONENTS = 'components'  export function resolveComponent(name: string): ConcreteComponent | string {   return resolveAsset(COMPONENTS, name) || name }

由以上代碼可知,在 resolveComponent 函數內部,會繼續調用 resolveAsset 函數來執行具體的解析操作。在分析  resolveAsset 函數的具體實現之前,我們在 resolveComponent 函數內部加個斷點,來一睹 render 方法的 “芳容”:

Vue 3.0 中如何使用動態組件

在上圖中,我們看到了解析組件的操作,比如 _resolveComponent("component-a")。前面我們已經知道在  resolveComponent 函數內部會繼續調用 resolveAsset 函數,該函數的具體實現如下:

// packages/runtime-core/src/helpers/resolveAssets.ts function resolveAsset(   type: typeof COMPONENTS | typeof DIRECTIVES,   name: string,   warnMissing = true ) {   const instance = currentRenderingInstance || currentInstance   if (instance) {     const Component = instance.type     // 省略大部分處理邏輯     const res =       // 局部注冊       // check instance[type] first for components with mixin or extends.       resolve(instance[type] || (Component as ComponentOptions)[type], name) ||       // 全局注冊       resolve(instance.appContext[type], name)     return res   } else if (__DEV__) {     warn(       `resolve${capitalize(type.slice(0, -1))} ` +         `can only be used in render() or setup().`     )   } }

因為注冊組件時,使用的是全局注冊的方式,所以解析的過程會執行 resolve(instance.appContext[type], name)  該語句,其中 resolve 方法的定義如下:

// packages/runtime-core/src/helpers/resolveAssets.ts function resolve(registry: Record<string, any> | undefined, name: string) {   return (     registry &&     (registry[name] ||       registry[camelize(name)] ||       registry[capitalize(camelize(name))])   ) }

分析完以上的處理流程,我們在解析全局注冊的組件時,會通過 resolve 函數從應用的上下文對象中獲取已注冊的組件對象。

(function anonymous() {     const _Vue = Vue      return function render(_ctx, _cache) {         with (_ctx) {           const {resolveComponent: _resolveComponent, createVNode: _createVNode,              Fragment: _Fragment, openBlock: _openBlock, createBlock: _createBlock} = _Vue              const _component_component_a = _resolveComponent("component-a")             const _component_component_b = _resolveComponent("component-b")             const _component_component_c = _resolveComponent("component-c")              return (_openBlock(),             _createBlock(_Fragment, null, [               _createVNode(_component_component_a),                _createVNode(_component_component_b),                _createVNode(_component_component_c)], 64))         }     } })

在獲取到組件之后,會通過 _createVNode 函數創建 VNode 節點。然而,關于 VNode 是如何被渲染成真實的 DOM  元素這個過程,阿寶哥就不繼續往下介紹了,后續會寫專門的文章來單獨介紹這塊的內容,接下來我們將介紹動態組件的相關內容。

二、動態組件

在 Vue 3 中為我們提供了一個 component 內置組件,該組件可以渲染一個 “元組件” 為動態組件。根據 is 的值,來決定哪個組件被渲染。如果  is 的值是一個字符串,它既可以是 HTML 標簽名稱也可以是組件名稱。對應的使用示例如下:

<!--  動態組件由 vm 實例的 `componentId` property 控制 --> <component :is="componentId"></component>  <!-- 也能夠渲染注冊過的組件或 prop 傳入的組件--> <component :is="$options.components.child"></component>  <!-- 可以通過字符串引用組件 --> <component :is="condition ? 'FooComponent' : 'BarComponent'"></component>  <!-- 可以用來渲染原生 HTML 元素 --> <component :is="href ? 'a' : 'span'"></component>

2.1 綁定字符串類型

介紹完 component 內置組件,我們來舉個簡單的示例:

<div id="app">    <button       v-for="tab in tabs"       :key="tab"       @click="currentTab = 'tab-' + tab.toLowerCase()">       {{ tab }}    </button>    <component :is="currentTab"></component> </div> <script>    const { createApp } = Vue    const tabs = ['Home', 'My']    const app = createApp({      data() {        return {          tabs,          currentTab: 'tab-' + tabs[0].toLowerCase()        }      },    });    app.component('tab-home', {      template: `<div style="border: 1px solid;">Home component</div>`    })    app.component('tab-my', {      template: `<div style="border: 1px solid;">My component</div>`    })    app.mount('#app') </script>

在以上代碼中,我們通過 app.component 方法全局注冊了 tab-home 和 tab-my 2 個組件。此外,在模板中,我們使用了  component 內置組件,該組件的 is 屬性綁定了 data 對象的 currentTab 屬性,該屬性的類型是字符串。當用戶點擊 Tab  按鈕時,會動態更新 currentTab 的值,從而實現動態切換組件的功能。以上示例成功運行后的結果如下圖所示:

Vue 3.0 中如何使用動態組件

看到這里你會不會覺得 component 內置組件挺神奇的,感興趣的小伙伴繼續跟阿寶哥一起,來揭開它背后的秘密。下面我們利用 Vue 3 Template  Explorer 在線工具,看一下模板編譯的結果:

const _Vue = Vue  return function render(_ctx, _cache, $props, $setup, $data, $options) {   with (_ctx) {     const { resolveDynamicComponent: _resolveDynamicComponent, openBlock: _openBlock,        createBlock: _createBlock } = _Vue     return (_openBlock(), _createBlock(_resolveDynamicComponent(currentTab)))   } }

通過觀察生成的渲染函數,我們發現了一個 resolveDynamicComponent  的函數,根據該函數的名稱,我們可以知道它用于解析動態組件,它被定義在 runtime-core/src/helpers/resolveAssets.ts  文件中,具體實現如下所示:

// packages/runtime-core/src/helpers/resolveAssets.ts export function resolveDynamicComponent(component: unknown): VNodeTypes {   if (isString(component)) {     return resolveAsset(COMPONENTS, component, false) || component   } else {     // invalid types will fallthrough to createVNode and raise warning     return (component || NULL_DYNAMIC_COMPONENT) as any   } }

在 resolveDynamicComponent 函數內部,若 component 參數是字符串類型,則會調用前面介紹的 resolveAsset  方法來解析組件:

// packages/runtime-core/src/helpers/resolveAssets.ts function resolveAsset(   type: typeof COMPONENTS | typeof DIRECTIVES,   name: string,   warnMissing = true ) {   const instance = currentRenderingInstance || currentInstance   if (instance) {     const Component = instance.type     // 省略大部分處理邏輯     const res =       // 局部注冊       // check instance[type] first for components with mixin or extends.       resolve(instance[type] || (Component as ComponentOptions)[type], name) ||       // 全局注冊       resolve(instance.appContext[type], name)     return res   } }

對于前面的示例來說,組件是全局注冊的,所以解析過程中會從 app.context 上下文對象的 components 屬性中獲取對應的組件。當  currentTab 發生變化時,resolveAsset 函數就會返回不同的組件,從而實現動態組件的功能。

此外,如果 resolveAsset 函數獲取不到對應的組件,則會返回當前 component 參數的值。比如  resolveDynamicComponent('div') 將返回 'div' 字符串。

// packages/runtime-core/src/helpers/resolveAssets.ts export const NULL_DYNAMIC_COMPONENT = Symbol()  export function resolveDynamicComponent(component: unknown): VNodeTypes {   if (isString(component)) {     return resolveAsset(COMPONENTS, component, false) || component   } else {     return (component || NULL_DYNAMIC_COMPONENT) as any   } }

細心的小伙伴可能也注意到了,在 resolveDynamicComponent 函數內部,如果 component 參數非字符串類型,則會返回  component || NULL_DYNAMIC_COMPONENT 這行語句的執行結果,其中 NULL_DYNAMIC_COMPONENT 的值是一個  Symbol 對象。

2.2 綁定對象類型

了解完上述的內容之后,我們來重新實現一下前面動態 Tab 的功能:

<div id="app">    <button       v-for="tab in tabs"       :key="tab"       @click="currentTab = tab">      {{ tab.name }}    </button>    <component :is="currentTab.component"></component> </div> <script>    const { createApp } = Vue    const tabs = [      {        name: 'Home',        component: {          template: `<div style="border: 1px solid;">Home component</div>`        }      },      {        name: 'My',        component: {          template: `<div style="border: 1px solid;">My component</div>`        }    }]    const app = createApp({      data() {        return {          tabs,          currentTab: tabs[0]        }      },    });    app.mount('#app') </script>

在以上示例中,component 內置組件的 is 屬性綁定了 currentTab 對象的 component 屬性,該屬性的值是一個對象。當用戶點擊  Tab 按鈕時,會動態更新 currentTab 的值,導致 currentTab.component  的值也發生變化,從而實現動態切換組件的功能。需要注意的是,每次切換的時候,都會重新創建動態組件。但在某些場景下,你會希望保持這些組件的狀態,以避免反復重渲染導致的性能問題。

對于這個問題,我們可以使用 Vue 3 的另一個內置組件 &mdash;&mdash; keep-alive,將動態組件包裹起來。比如:

<keep-alive>    <component :is="currentTab"></component> </keep-alive>

keep-alive 內置組件的主要作用是用于保留組件狀態或避免重新渲染,使用它包裹動態組件時,會緩存不活動的組件實例,而不是銷毀它們。關于  keep-alive 組件的內部工作原理,阿寶哥后面會寫專門的文章來分析它,對它感興趣的小伙伴記得關注 Vue 3.0 進階 系列喲。

三、阿寶哥有話說

3.1 除了 component 內置組件外,還有哪些內置組件?

在 Vue 3 中除了本文介紹的 component 和 keep-alive 內置組件之外,還提供了  transition、transition-group 、slot 和 teleport 內置組件。

3.2 注冊全局組件與局部組件有什么區別?

注冊全局組件

const { createApp, h } = Vue const app = createApp({}); app.component('component-a', {   template: "<p>我是組件A</p>" });

使用 app.component 方法注冊的全局的組件,被保存到 app 應用對象的上下文對象中。而通過組件對象 components  屬性注冊的局部組件是保存在組件實例中。

注冊局部組件

const { createApp, h } = Vue const app = createApp({}); const componentA = () => h('div', '我是組件A'); app.component('component-b', {   components: {     'component-a': componentA   },   template: `<div>     我是組件B,內部使用了組件A     <component-a></component-a>       </div>` })

解析全局注冊和局部注冊的組件

// packages/runtime-core/src/helpers/resolveAssets.ts function resolveAsset(   type: typeof COMPONENTS | typeof DIRECTIVES,   name: string,   warnMissing = true ) {   const instance = currentRenderingInstance || currentInstance   if (instance) {     const Component = instance.type     // 省略大部分處理邏輯     const res =       // 局部注冊       // check instance[type] first for components with mixin or extends.       resolve(instance[type] || (Component as ComponentOptions)[type], name) ||       // 全局注冊       resolve(instance.appContext[type], name)     return res   } }

3.3 動態組件能否綁定其他屬性?

component 內置組件除了支持 is 綁定之外,也支持其他屬性綁定和事件綁定:

<component :is="currentTab.component" :name="name" @click="sayHi"></component>

這里阿寶哥使用 Vue 3 Template Explorer 這個在線工具,來編譯上述的模板:

const _Vue = Vue return function render(_ctx, _cache, $props, $setup, $data, $options) {   with (_ctx) {     const { resolveDynamicComponent: _resolveDynamicComponent,        openBlock: _openBlock, createBlock: _createBlock } = _Vue      return (_openBlock(), _createBlock(_resolveDynamicComponent(currentTab.component), {       name: name,       onClick: sayHi     }, null, 8 /* PROPS */, ["name", "onClick"]))   } }

關于Vue 3.0 中如何使用動態組件就分享到這里了,希望以上內容可以對大家有一定的幫助,可以學到更多知識。如果覺得文章不錯,可以把它分享出去讓更多的人看到。

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

vue
AI

佳木斯市| 巴中市| 乐山市| 仲巴县| 甘南县| 宣威市| 上林县| 安吉县| 山丹县| 江门市| 赤城县| 确山县| 桂林市| 台北县| 屏山县| 二手房| 石门县| 林西县| 电白县| 墨脱县| 静宁县| 班玛县| 莎车县| 佛学| 五大连池市| 化州市| 宜城市| 仁怀市| 洪江市| 谢通门县| 苗栗市| 丘北县| 信宜市| 无棣县| 苍山县| 巴林左旗| 保亭| 石首市| 房山区| 中山市| 五常市|