動態

詳情 返回 返回

[vue-cli3/element-plus] 從菜單渲染淺談動態渲染Vue組件的問題 - 動態 詳情

1. 關於Element-plus的菜單渲染問題

跨過了Element-UI,終於來到了Element-plus。又回到了一個老問題,menu的渲染。
創建一個menu數組,利用v-for來渲染數組,生成menu,非常常規的操作。但是操作的過程中,出現了一個小問題,就是關於icon的渲染。
我們知道,在Element-plus中,渲染一個帶圖標的菜單項,是這麼搞的:

<el-menu-item index="/mypath">
    <template #title>
        <el-icon><Odometer /></el-icon>
        <span>title</span>
    </template>
</el-menu-item>

icon圖標是直接以一個組件的形式進行渲染的。
那麼,當我們企圖利用v-for進行列表渲染的時候,這個圖標的組件怎麼渲染出來,成了個難題。
直接用雙花括號{{}}肯定是不行的,直接會把標籤搞成文本。
v-html也不行,它只能渲染原生的HTML標籤。
WTF?

2. 如何才能動態的把自定義組件渲染出來?

<template></template>裏面搞模版語法是行不通了。
那就只能嘗試走其他的路線了。在搜索引擎愉快的與海量信息搏鬥之後,找到了切入點:render函數。
老實説,其實早就該想到這個了,畢竟組件渲染就這麼兩條路嘛。奈何對render的使用頻率太低了,選擇性的搞忘記了。
那麼來嘗試吧。
寫一個組件,通過props接收到圖標的標籤寫法,然後渲染出來。

//注意在vue3中,render函數中不再有參數了,h函數需要按需加載。
import { h } from 'vue';

export default{
    props: {
        //Odometer
        html: String
    },
    render(){
        return h('el-icon', null, h(this.html));
    }
}

果不其然沒有達到效果。常用vue做開發的小夥伴肯定一眼就發現了一個問題:
h函數生成虛擬DOM節點時,如果要生成的是組件,則第一個參數直接使用導入的組件即可。如果使用字符串,會原封不動的把字符串當做HTML標籤渲染,而不是當作組件渲染。(參考鏈接)

修改一下:

import { h } from 'vue';
import { ElIcon } from 'element-plus';

export default{
    props: {
        //Odometer
        html: String
    },
    components: {
        ElIcon
    },
    render(){
        return h(ElIcon, null, h(this.html));
    }
}

還是不對呀,圖標名稱是傳過來的字符串,沒法直接獲取到導入的組件呀。
嚇得我趕緊又翻了一下文檔,在最後一行找到了這麼一句話:

如果一個組件是用名字註冊的,不能直接導入 (例如,由一個庫全局註冊),可以使用 resolveComponent() 來解決這個問題。

原來如此。。。
好了,給出最終答案:

<el-menu-item :index="item.path">
    <template #title>
        <DynamicIcon :html="item.icon"></DynamicIcon>
        <span>{{item.title}}</span>
    </template>
</el-menu-item>
//DynamicIcon
import { h, resolveComponent } from 'vue';
import { Odometer, ChatDotRound } from '@element-plus/icons-vue';

export default{
    props: {
        //Odometer
        html: String
    },
    components: {
        Odometer,
        ChatDotRound
    },
    render(){
        //ElIcon直接全局全局導入了
        const IconBox = resolveComponent('ElIcon');
        const Icon = resolveComponent(this.html);

        return h(IconBox, null, h(Icon));
    }
}

3. 總結

最後總結一下子吧。
想要動態渲染組件,就需要利用propsrender函數。
在使用h函數的時候,生成組件的虛擬vnode,要直接使用導入的組件。
如果只能獲取一個組件名稱,那麼就用resolveComponent函數手動解析註冊的組件。

Add a new 評論

Some HTML is okay.