利用VUE異步組件、動態加載組件,實現自定義組件順序、動態綁定傳入子組件的props、動態綁定監聽子組件的$emit事件

推進我實現這個功能的業務背景

最近接到一個讓我很頭疼的需求:產品要求咱們系統頁面上全部的模塊都支持順序的變更。
好比有 模塊A、B、C、D,能夠無序的展現在頁面上,我剛聽到這個需求的時候我是崩潰的,若是是在項目開發以前提出這個需求,那麼個人前期頁面的架構確定不會直接寫死的。如今,若是想知足這個需求,我只能翻掉以前的頁面從新開發.....
目前項目是有八個模塊,我是每一個模塊封裝一個單獨的組件,而後再index頁面統一引入。css

  • 救命稻草

瀏覽了一番vue的官網,仍是有所收穫的。發現了動態組件 & 異步組件這個東西!!!簡直是救命啊!!!html

API

動態組件:
動態組件vue

異步組件:
圖片描述node

  • 思路分析

有了動態組件這個東西以後,咱們就能夠根據:is綁定不一樣的值來渲染不一樣的組件。好比,拿到後臺給咱們返回的要渲染組件順序的數組,咱們經過循環數組,構建出一個最終咱們想要的數據格式。關鍵點在於動態修改 () => import('')裏面的值。每一個組件要傳給子組件的值和接收子組件emit的事件也能夠動態的綁定上去。好了,廢話很少說了,貼代碼吧!ios

  • 代碼

首先是HTML層:axios

<template>
    <div class="temp">
        <!-- tempList是通過處理後的數組-->
        <div v-for="com in tempList" :key="com.key">
            <component v-bind="com.props" v-on="com.fn" :is="com.app" />
        </div>
    </div>
</template>

js層:
<script>數組

import axios from 'axios';
import Volume from "com/Volume";
import ServiceStatus from "com/ServiceStatus";
import FixStatus from "com/FixStatus";

export default {
    name: 'about',
    props: {
        msg: String
    },
    data() {
        return {
            isShow: false,
            tempList: [],
            tempData: [],
            VolumeOptions: 'VolumeOptionsValueFromParent ',
            ServiceStatusOptions: 'ServiceStatusOptionsValueFromParent',
            FixStatusOptions: 'FixStatusOptionsValueFromParent'
        };
    },
    created() {
        this.createTempData()
    },
    methods: {
        // 獲取組件的順序
        getTempList() {
            //這裏是我本身用nodejs mock的一個接口,返回的數據在下面貼出來
            return axios.get('http://localhost:9999/search/detail').then(res => {
                return res.data.data
            })
        },
        async createTempData() {
            const result = await this.getTempList();
            // 動態修改options綁定的變量
            result.forEach((val) => {
                let key = val.tempName;
                switch (key) {
                    case 'Volume':
                        val.options = this.VolumeOptions
                        break;
                    case 'ServiceStatus':
                        val.options = this.ServiceStatusOptions
                        break;
                    case 'FixStatus':
                        val.options = this.FixStatusOptions
                        break;
                }
            })
            this.tempData = result;
            console.log(this.tempData);
            this.init()
        },
        init() {
            // 構建渲染頁面組件的數組
            this.tempList = this.tempData.map((value, index) => {
                return {
                    app: () => import(`com/${value.tempName}`), //異步組件
                    key: index,
                    props: {
                        options: value.options, //傳給子組件的options
                    },
                    fn: {
                        change: this.changeTest //接收來自子組件的$emit事件
                    }
                };
            });
        },
        changeTest(e) {
            console.log('監聽子組件獲得的值是:' + e)
        }
    }
};

子組件代碼:
1.Volume組件:架構

<template>
    <div id="test">
        Volume page 
        <div @click="$emit('change', 'Volume')">props的值:{{options}}</div>
    </div>
</template>

<script>
    export default {
        name: 'Volume',
        props: {
            options: {
                type: String,
                default: ''
            }
        }
    }
</script>

2.FixStatus組件:app

<template>
    <div id="FixStatus" class="comm">
        組件名:FixStatus page 
        <div @click="$emit('change', 'FixStatus')">props的值:{{options}}</div>
    </div>
</template>

<script>
    export default {
        name: 'FixStatus',
        props: {
            options: {
                type: String,
                default: ''
            }
        }
    }
</script>
<style lang="scss" scoped>
    @import url('../assets/scss/comm.scss');
</style>

3.ServiceStatus組件:異步

<template>
    <div id="ServiceStatus" class="comm">
        組件名:ServiceStatus page
        <div @click="$emit('change', 'ServiceStatus')">props的值:{{options}}</div>
    </div>
</template>

<script>
    export default {
        name: 'ServiceStatus',
        props: {
            options: {
                type: String,
                default: ''
            }
        }
    }
</script>
<style lang="scss" scoped>
    @import url('../assets/scss/comm.scss');
</style>

接口返回的數據:

{"code":"0000","msg":"請求成功!","data":[{"id":0,"tempName":"ServiceStatus","options":"''"},{"id":1,"tempName":"Volume","options":"''"},{"id":2,"tempName":"FixStatus","options":"''"}]}

data的數組就是咱們能夠自定義順序的數組。好了,是否是能夠隨意的玩起來了!下面看一下demo頁面效果吧。

  • 五百萬項目的效果

圖片描述

能夠看到:頁面組件的排列順序就是根據接口返回的順序排列的、每一個子組件props獲得的值也是能夠的、控制檯console是我點擊不一樣組件,emit給父組件的值。這是我目前想到最穩當的方案,若是有巨佬有更好的思路,歡迎指導! 扣扣 602353272。溜了溜了....

相關文章
相關標籤/搜索