Weex 动态Modal设计

作者: 前尘如梦 | 来源:发表于2017-10-26 19:16 被阅读187次

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

相关文章

  • Weex 动态Modal设计

    Weex 动态Modal设计 我们在项目中使用了各种自定义的对话框、弹出框等控件,其中各种控件都是在各自的页面中弹...

  • weex-24-modal模块

    本节学习目标 modal组件的四种用法 直接写用法了,比较简单 第一步导入模块 1.提示toast 会在一个小浮层...

  • Weex开发初探

    1、Weex的由来 WEEX前身 Weex的前身是WeApp,一个用JSON配置原生UI组件来实现动态化的框架,W...

  • 性能与动态兼得的Weex

    Weex被阿里定义为“移动端的高性能动态化方案”,并称之为“性能与动态兼得”。听上去似乎很玄乎,那么Weex究竟如...

  • iOS热更新

    技术: Flutter JSPtatch基本用法 Weex React Native Cordova 动态库

  • Weex原理概述

    总览 Weex是跨平台,可扩展的动态化技术. 你能通过在Weex源码中写