Weex 动态Modal设计

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 web
if (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来实现,不过在实际使用的时候碰到了一些问题,暂时先用这种不太优雅的方式实现,后续再进行改进吧。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 211,194评论 6 490
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,058评论 2 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 156,780评论 0 346
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,388评论 1 283
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,430评论 5 384
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,764评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,907评论 3 406
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,679评论 0 266
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,122评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,459评论 2 325
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,605评论 1 340
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,270评论 4 329
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,867评论 3 312
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,734评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,961评论 1 265
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,297评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,472评论 2 348

推荐阅读更多精彩内容