前段時間給項目的無代碼系統(tǒng)做了一個交互預(yù)覽頁面,主要功能是把UI信息的JSON解析渲染為可交互的網(wǎng)頁,其中遇到了不同類型組件渲染的問題
一、為什么需要動態(tài)組件渲染
我們的無代碼系統(tǒng)采用PCB協(xié)議(Page、Container和Block),為了實現(xiàn)交互,Container分為有焦點和無焦點,Block作為最基礎(chǔ)的頁面元素,其種類包含圖片、文本、視頻等16種,如果又要保證頁面結(jié)構(gòu)簡單明晰,又要讓Block有較高的靈活實現(xiàn)的話,就避不開是用動態(tài)組件。
二、動態(tài)組件的實現(xiàn)方式
對于上面所說的情況,實際中針對不同的場景采取了兩種不同的實現(xiàn)方式。
1. JSX結(jié)合if判斷實現(xiàn)
這種方式是用于解決Container的兩種不同組件,即有焦點和無焦點,由于這兩個組件有較大的功能差異,分成了單獨的兩個組件實現(xiàn),同時在props上也有一定區(qū)別,上述情況綜合考慮,使用了JSX結(jié)合if判斷進行條件渲染實現(xiàn),大致實現(xiàn)如下:
<script>
import FocusContainer from "./focus-container.vue";
import NoFocusContainer from "./no-focus-container.vue";
export default {
name: "Container",
components: {
FocusContainer,
NoFocusContainer
},
render() {
const { hasfocus } = this.uiData;
return hasfocus ? (
<FocusContainer
uiData={this.uiData}
isActive={this.isActive}
></FocusContainer>
) : (
<NoFocusContainer
uiData={this.uiData}
></NoFocusContainer>
);
}
};
</script>
總的來說,這種適合組件總數(shù)數(shù)量少、props有差異、沒有后續(xù)改變或頻繁改變的場景。
2. Component is動態(tài)組件實現(xiàn)
第一種方式對于只有兩個類型的Container還相對容易,但是對于實際中類型的Block要是寫起if…else或者switch那也是相當難維護,所以第二種方式是用Vue官方提供的is屬性實現(xiàn)動態(tài)組件,沒有印象的可以先看看組件基礎(chǔ) — Vue.js動態(tài)組件 & 異步組件 — Vue.js,大致實現(xiàn)如下:
<template>
<component
:is="blockType"
:uiData="uiData"
></component>
</template>
<script>
import BlockCommonPropsMixin from "./block-common-props-mixin";
import ImageBlock from "./image/image-block.vue";
import TextBlock from "./text/text-block.vue";
import {
TEXT_BLOCK,
IMAGE_BLOCK
} from "./block-type";
const componentMap = {
[TEXT_BLOCK]: TextBlock,
[IMAGE_BLOCK]: ImageBlock,
};
export default {
name: "Block",
mixins: [BlockCommonPropsMixin],
computed: {
blockType() {
const { type } = this.uiData;
return componentMap[type];
}
}
};
</script>
先將類型和組件對象存儲在一個Map中,然后聲明一個計算屬性返回對應(yīng)的組件對象,將這個作為component的is屬性的值即可,這里有幾點注意的:
1. 將Block的類型放在一個單獨的文件中,方便后續(xù)的維護;
2. Block和其他類型的Block的props可以提取成一個mixin文件;
3. 如果后續(xù)(組件類型)有變化,可以使用keep-alive包裹實現(xiàn)緩存。
總的來說,這種方式適用于組件數(shù)量多、組件props基本一致的情況。