본문 바로가기

FrontEnd/vue.js

dynamic component Injection Plugin

반응형

페이지별 Vue Instance 생성하여 작업해야하는 환경에서 Store를 사용할수도 없고
메인 페이지가 없다보니 공통 화면 처리하는 부분이 애매한 부분이 있었다
그렇다고 각 페이지별로 매번 간단한 공통 component를 선언해서 사용하기는 싫었다

그래서 component를 동적으로 주입 할수있는 방안을 검토하였고 아래와같이 구현하였다
아래소스는 custom 공통 alert 창을 각 페이지에서 메소드 호출로만 가능하게 하기 위한 plugin 이다.

주 소스 구조는 각 vue 페이지에서 alert 창 요청시
ex) this.$.alert('TEST'); 
해당 common-alert를 동적으로 주입시킨후 해당 alert component를 호출하는 
구조이다.

아래와 같은 plugin을 제공해줌으로서 각 페이지 개발자들에게 this.$alert 사용법만을 가이드하면 되게 되었다
추후 confirm 까지 확장 가능할듯하다.

/**
 * Created by kic(ddori) on 2019. 12. 17..
 */

const alertPlugin = {

    install (Vue, options = {}) {

        if (this.installed) {
            return;
        }

        this.installed = true;

        const createDivInBody = () => {
            const div = document.createElement('div');
            //const mainApp = document.getElementById("app");
            //mainApp.appendChild(div);
            document.body.appendChild(div);
            return div
        }

        /* 동적 component Inject
        */
        const componentInject = (component) =>{
            const container = createDivInBody();
            Vue.prototype.$alertContainer = new Vue({
                parent: Plugin.rootInstance,
                render: h => h(component)
            }).$mount(container)
        }

        /* alert component 객체를 얻는다.
        */
        const getAlertComponent = (root)=> {
            if (Vue.prototype.$alertContainer == null){
                componentInject('common-alert');
            }
            return root._dynamicContainer;
        }

        /* 공통 alert 메소드
        */
        Vue.prototype.$alert = (msg,width,height) =>{

            const root = Plugin.rootInstance;
            const alertComponent = getAlertComponent(root);
            if (!alertComponent) return;

            return alertComponent.alert(false,"알 림",msg,width,height);

        }

        Vue.prototype.$confirm = (msg,width,height) =>{

            const root = Plugin.rootInstance;
            const alertComponent = getAlertComponent(root);
            if (!alertComponent) return;

            return alertComponent.alert(true,"알 림" , msg,width,height);

        }

        Vue.mixin({
            beforeMount () {
                if (Plugin.rootInstance === undefined) {
                    Plugin.rootInstance = this.$root;
                }
            }
        })

        Vue.prototype.$alertContainer = null;
    }

}

 

(Vue=> {
    Vue.component('commonAlert', {
        template: `<modal ref="commonAlert" v-show="isPop" @click="onClose" :title="title" :isTitleBar=false :bodyStyle="bodyStyle" @close="onClose" >
                        <p class="bold pt-30 pb-20 ta-c">{{title}}</p>
                        <div class="container100 ta-c fs-13">
                            {{msg}}
                        </div>                    
                        <div class="container100 pt-40 pb-30 ta-c cf">
                            <button v-show="isConfirm" class="admin-bt wd-90 mr-05" @click="onClickCancel">취소</button>                            
                            <button class="admin-bd-bt wd-80" @click="onClickOk">확인</button>
                        </div>                        
                    </modal>`,
        data() {
            return {
                isPop:false,
                isConfirm:false,
                msg: '',
                title:'',
                bodyStyle:{},
                resolve: null,
                reject: null,
            }
        },
        created(){
            this.$root._dynamicContainer = this;
            //Vue.prototype.$alertContainer = this;
        },
        computed: {
        },
        methods: {
            onClose(){

            },
            onClickCancel(){
                this.isPop = false;
                this.reject(false);
            },
            onClickOk(){
                this.resolve(true);
                this.isPop = false;
            },
            alert(isConfirm,title,msg,width,height){

                let bodyStyle = {};
                if (width !== undefined){
                    bodyStyle.width = width+'px';
                }else{
                    bodyStyle.width = '350px';
                }

                if (height !== undefined){
                    bodyStyle.height = height+'px';
                }
                this.isConfirm = isConfirm;
                this.title = title;
                this.bodyStyle = bodyStyle;
                this.isPop = true;
                this.msg = msg;

                return new Promise((resolve, reject) => {
                    this.resolve = resolve
                    this.reject = reject
                })

            }
        },
        watch: {
            isPop(value){
                if (value){

                }
            }
        }
    });
})(Vue);
반응형

'FrontEnd > vue.js' 카테고리의 다른 글

Vue Transition  (0) 2020.01.19
composition api Test Code  (0) 2019.12.29
Recusive Navigation Component 개발기  (0) 2019.10.17
개발 환경에 따라 다른 환경 변수 값 적용하기  (0) 2019.10.10
lesscss 적용 처리  (0) 2019.09.26