Weex 动态Modal设计

来源:互联网 发布:淘宝下架是什么意思 编辑:程序博客网 时间:2024/06/09 13:55

Weex 动态Modal设计

我们在项目中使用了各种自定义的对话框、弹出框等控件,其中各种控件都是在各自的页面中弹出,其中最大的问题就是在tabbar中子页面弹出的modal不能显示全屏。本文的目的即是设计一个动态的Modal放在tabbar外面,通过与子页面的调用方法来开启对应的动态组件。

构建动态组件

Weex中用的组件实际是使用Vue.js生成的代码,由于Vue 2.0之后的代码都是预编译的,以前使用动态template的方法已经不适用,能构建动态组件的方法只有<component>以及render方法创建, 本文暂时先采用<component>来实现, 关于更多的<component>的知识可以参考Vue动态组件文档。

最基本的动态组件(v-modal.vue)如下:

<template>    <div class="cModal" append="tree">        <component v-bind:is="modalCurrentView"></component>    </div></template><style>    .cModal{        width: 750;        background-color: transparent;        display: flex;        justify-content: center;        align-items: center;        position: absolute;        left: 0;        right: 0;        top: 0;        bottom: 0;    }</style><script>    module.exports = {        computed:{            modalCurrentView() {                return this.$store.state.modalCurrentView            }        },        components:{            "pop-call"      : require("../module/personal/mainpage/v-pop-call.vue"),            "pop-head"      : require("../module/personal/mainpage/v-pop-head.vue"),            "pop-version"   : require("../module/personal/mainpage/v-pop-version.vue"),            "action-sheet"  : require("../manage/camera/action_sheet/v-action-sheet.vue"),        }    }</script>

<component>主要是通过动态修改is绑定的modalCurrentView组件来进行切换,可以用此方法来实现类似tabbar切换之类的效果。

其中我们的数据采用的是Vuex进行管理,也就是存储在store.js文件中:

import Vuex from 'vuex'// Vuex is auto installed on the webif (WXEnvironment.platform !== 'Web') {  Vue.use(Vuex)}var store = new Vuex.Store({  state:{      modalIsShow:false,      modalCurrentView:"pop-call"  },  mutations:{      CHANGE_MODAL_SHOW (state, isShow) {          state.modalIsShow = isShow      },      CHANGE_MODAL_VIEW (state, view) {          state.modalCurrentView = view      }  },  actions:{      changeModalShow(context, state) {          context.commit("CHANGE_MODAL_SHOW", state);      },      changeModalView(context, view) {          context.commit("CHANGE_MODAL_VIEW", view);      }  }})export default store

可以从store.js中看出,我们可以用changeModalShow方法来控制Modal的显示和隐藏,用changeModalView方法可以控制切换成那一个组件,不过调用store的方法显得有些麻烦,而且在WebStorm上没有任何提示,我们可以在其中再次封装一个modal.js来进行调用:

import store from './store.js'import Vue from 'vue'export default {    closeModal () {        store.dispatch("changeModalShow", false)    },    openModal (view) {        store.dispatch("changeModalView", view);        store.dispatch("changeModalShow", true)    },}

至此一个简单的动态modal架构就出来了, 我们只需要在最外层的页面增加此动态控件即可:

<template>    <div class="cRoot" @androidback="onClickAndroidBack"                       @viewappear="viewappear"                       @viewdisappear="viewdisappear">        ......        // 添加动态modal        <modal v-if="modalIsShow"></modal>    </div></template><script>    var nav = weex.requireModule('event');    var storage = weex.requireModule("storage");    module.exports = {        ......        components:{            ......            "modal"         : require("./v-modal.vue")        },        computed:{            modalIsShow () {                return this.$store.state.modalIsShow            }        }    }</script>

我们需要调用显示modal就可以使用:

import vModal from '../modal.js';vModal.openModal("pop-head");   //其中"pop-head"是我们再v-modal.vue文件中引入的components;vModal.closeModal();            //需要关闭的时候,只需要调用此方法即可

组件之间传值

Modal的显示和隐藏都没有问题了,但是还有一个问题就是封装的组件点击事件是直接往上传递,也就是传到动态的modal后就直接传到最外面的页面了,类似tabbar子页面就不会接收到事件。此时需要我们使用非父子关系之间的传值,简单的方法有两种, 一种是通过Vuex来实现, 另一种就是使用Vue组件通信, 因为我们定义了单独的modal.js,用第一种方法,调用modal时还要额外多引入文件,因此我们采用第二种方法。

Vue非父子关系之间的通信非常简单,只需要在modal.js加入几行代码即可:

import store from './store.js'import Vue from 'vue'export default {    eventBus:new Vue({}),    //定义一个通用的Vue对象进行通信    closeModal () {        store.dispatch("changeModalShow", false)    },    openModal (view) {        store.dispatch("changeModalView", view);        store.dispatch("changeModalShow", true)    },}

不过我们原来的组件点击的时候不再采用原来的this.$emit("eventName", eventData);,因为此方法只会冒泡到最外面的页面, 而传入不到调用的页面;应该改用如下的方法:

import vModal from '../modal.js'vModal.eventBus.$emit("eventName", eventData);

而接收事件的组件可以mounted方法中进行监听:

mounted:function(){    var that= this;    vModal.eventBus.$on("eventName", (eventData)=> {    });},

通过此方法, 我们就可以在动态modal包括的组件和调用动态modal的组件之间建立了联系。

动态组件的参数传递

动态modal还有一个很大的问题,就是包含的组件如果需要传递参数,怎么办呢?

我们首先定义一个统一的变量作为动态modal的传入参数, 在store.js中进行修改,加入参数:

var store = new Vuex.Store({  state:{      modalIsShow:false,      modalCurrentView:"pop-call",      modalData:{}  },  mutations:{      ...      CHANGE_MODAL_DATA (state, data) {          state.modalData = data      }  },  actions:{      ...       changeModalData(context, data) {          context.commit("CHANGE_MODAL_DATA", data);      }  }})export default store

而在定义的modal.js中修改openModal方法:

openModal (view, data) {    store.dispatch("changeModalData", data);    store.dispatch("changeModalView", view);    store.dispatch("changeModalShow", true)},

定义的modalData可以通过<component>的参数传入

<template>    <div class="cModal" append="tree">        <component v-bind:is="modalCurrentView" :modalData="modalData"></component>    </div></template>......<script>    import Vue from 'vue'    module.exports = {        computed:{            modalCurrentView() {                return this.$store.state.modalCurrentView            },            modalData() {                let data = this.$store.state.modalData;            }        },        ......    }</script>

在自定义的弹出显示的组件内容中我们可以使用props来接收这些参数:

module.exports = {        props:{                modalData:{default:{}}        },}

不过用此方法传递的参数,对子组件的修改比较多, 更好的方法是使用render函数来动态构建一个组件, 通过修改控件的tag来实现,不过在实际使用的时候碰到了一些问题,暂时先用这种不太优雅的方式实现,后续再进行改进吧。

有什么问题可以访问我的简书或者在CSDN博瑞立方终端组中留言交流。

原创粉丝点击