zoukankan      html  css  js  c++  java
  • 利用状态模式处理多个模态弹出层的显示隐藏

    使用MVVM架构处理页面的生成与更新的好处是,我们从DOM的桎梏中解放出来,重点转移到数据的处理。数据的组织与维护向来是设计模式的阵地,这让我们亲近设计模式,写出高可维护性的软件。以近日我在公司遇到的弹出层为例吧。

    后台管理界面的特点是多表格多弹出层,这样才方便展现更多数据更多功能。我们项目有一个叫云储存的模块,可以看作是115网盘的微缩版。这模块里有许多弹出层,用于处理分区,文件夹,文件的增删改查。为了防止用户在一个操作不结束时干另一个操作引起混乱,都做成模态对话框。换言之,它们都有浅黑色的半透明遮罩层。由于可能一个弹出层外弹出另一个弹出层,比如删除时的确认面板,因此我又不能让所有弹出层共享一个外框,唯一能共享的是遮罩层。

    再看我的代码,每个弹出层在VM中对应两个方法与一个属性,那个属性用于负责弹出层的显示与隐藏,其他两个方法用于改变这个属性。这是一种非常经典的做法。但遮罩层怎么办呢?它也应该跟弹出层一同显示隐藏。但如何让多个弹出层一起操作它?这时我使用了一个技巧——使用"短路或"!

    <div class="mask" ms-visible="flagCreatePartition || flagNewFolder || flagDeleteFiles || flagUploadFiles">
    
    </div>
    <div class="dialog" ms-if="flagCreatePartition" ms-include-src="'modules/apps/storage/createPartitionDialog.html'">
    
    </div>
    <div class="dialog" ms-if="flagDeleteFiles" ms-include-src="'modules/apps/storage/deleteFilesDialog.html'">
    
    </div>
    <div class="dialog" ms-if="flagNewFolder" ms-include-src="'modules/apps/storage/newFolderDialog.html'">
    
    </div>
    <div class="dialog" ms-if="flagUploadFiles" ms-include-src="'modules/apps/storage/uploadFilesDialog.html'">
    
    </div>
    
      var model =  avalon.define("appstorage", function(vm) {
                            vm.flagCreatePartition = false
                            vm.openCreatePartition = function() {
                                model.flagCreatePartition = true
                            }   
                            vm.closeCreatePartition = function(create) {
                                if (create === true) {
                                   //创建新分区
                                }
                                model.flagCreatePartition = false
                            }
    
    
                            vm.flagNewFolder = false
                            vm.openNewFolder = function() {
                                model.flagNewFolder = true
                            }
                            vm.closeNewFolder = function(create) {
                                if (create === true) {
                                  //创建文件夹
                                }
                                model.flagNewFolder = false
                            }
    
                            vm.flagDeleteFiles = false
                            vm.openDeleteFiles = function() {
                                vm.flagDeleteFiles = true
                            }
                            vm.closeDeleteFiles = function() {
                                vm.flagDeleteFiles = false
                            }
    
    
                            vm.flagUploadFiles = false
                            vm.openUploadFiles = function(create) {
                                if (create === true) {
                                  //上传文件
                                }
                                vm.flagUploadFiles = true
                            }
                            vm.closeUploadFiles = function() {
                                vm.flagUploadFiles = false
                            }
                            //略
                        })
    

    这是一个非常工整划一的结构。当我们想打开某人弹出层时,只要在对应的按钮上绑定ms-click="openUploadFiles", 关闭弹出层,我们在弹出层的关闭按钮上绑定ms-click="closeUploadFiles"。弹出层里存在两种按钮,一种是确认,是存在实际操作,一种是取消,单纯的关闭,我们可以通过传参区分它们。下面是某一个弹出层的内容,它是通过ms-include实现动态加载。

    <div class='wrapper'>
        <div class='title'>{{i18ndeletefile}}<span class='close' ms-click='closeDeleteFiles'></span></div>
        <p>Are you sure to delete seleted files?</p>
        <span class="button" ms-click="closeDeleteFiles(true)"  >{{i18nok}}</span>
    </div>
    
    

    弹出层出现的入口:

    <header>
        <span class="newFolder iconbutton" ms-click="openNewFolder">{{ i18nnewFolder }}</span>   
        <span class="uploadFile iconbutton" ms-click="openUploadFiles">{{ i18nuploadFile }}</span>
    
        <span class="moveBtn fastener">{{ i18nmove }}</span>
    
        <span class="removeBtn fastener" ms-click="openDeleteFiles">{{ i18nremove }}</span>
    
        <span class="renameBtn fastener">{{ i18nrename }}</span>
    </header>
    

    一切是乎很完美,但细看,它是违反“开闭原则”,每添加一个新弹出层都要在VM加三个东西,而且视图上也要遮罩层的ms-visible的值进行修改。这时我们就需要查找重复代码了,把变化的东西封装起来。我们发现所有弹出层与遮罩层都是受某些变量而改变(flagXXXX),它们是一个简单的布尔,如果把它们合并起来做成一个变量更好用些。

                    vm.flagDialog = ""
                    vm.openDialog = function(name) {
                        vm.flagDialog = name
                    }
                    vm.openDialog = function(command, execute) {
                        if (execute) {
                            vm[command]()
                        }
                        vm.flagDialog = ""
                    }
                    vm.createPartition = function() {
                    }
                    vm.newFolder = function() {
                    }
                    vm.deleteFiles = function() {
                    }
                    vm.uploadFiles = function() {
                    }
    

    在JAVA中,它要求每个类都一个控制状态的内部类。在JS这样动态的语言中,我们可以把这个内部类改成对象,这里更进一步,改成一个字符串。然后我们只要控制这个字符串,就能批量控制N个弹出层了。

    打开这些弹出层的HTML代码变成:

    <header>
        <span class="newFolder iconbutton" ms-click="openDialog('newFolder')">{{ i18nnewFolder }}</span>   
        <span class="uploadFile iconbutton" ms-click="openDialog('uploadFiles')">{{ i18nuploadFile }}</span>
    
        <span class="moveBtn fastener">{{ i18nmove }}</span>
    
        <span class="removeBtn fastener" ms-click="openDialog('deleteFiles')">{{ i18nremove }}</span>
    
        <span class="renameBtn fastener">{{ i18nrename }}</span>
    </header>
    

    而弹出层的代码就变成这样了:

    
    <div class="mask" ms-visible="flagDialog">
    
    </div>
      
    <div class="dialog" ms-if="flagDialog === 'createPartition'" 
         ms-include-src="'modules/apps/storage/createPartitionDialog.html'">
    </div>
      
    <div class="dialog" ms-if="flagDialog === 'deleteFiles' "
         ms-include-src="'modules/apps/storage/deleteFilesDialog.html'">
    </div>
      
    <div class="dialog" ms-if="flagDialog === 'newFolder'" 
         ms-include-src="'modules/apps/storage/newFolderDialog.html'">
    </div>
      
    <div class="dialog" ms-if="flagDialog === 'uploadFiles'"
         ms-include-src="'modules/apps/storage/uploadFilesDialog.html'">
    </div>
    

    弹出层的内容大概成为这样:

    <div class='wrapper'>
    
        <div class='title'>{{i18nnewFolder}}<span class='close' ms-click='closeDialog'></span></div>
    
        <input class="partition" ms-duplex="folderName">
    
        <span class="button partitionbtn" ms-click="closeDialog('newFolder',true)" ms-class-blue="folderName.length" >{{i18nok}}</span>
    
    </div>
    
    

    我们发现每一个弹出层的外框都很像,因此可以循环生成

    
    <div ms-each-name="dialogNames">
        <div class="dialog" ms-if="flagDialog === name" 
             ms-include-src="'modules/apps/storage/{{name}}Dialog.html'">
        </div>
    </div>
    

    VM上添加一个dialogNames的数组,里面包含所有弹出层的名字就行了。这样我的HTML与JS就干净多。

    最后附上一张设计模式的图片:

  • 相关阅读:
    linux 系统运维工具13款
    Django2.0 分页的应用
    jvm优化
    SSH-key 在Windows下如何生成公钥和私钥
    申请Let’s Encrypt免费证书,给自己网站增加https访问
    wordpress上传主题以及安装插件 出现ftp的问题解决方案
    php压缩文件
    linux下 如何切换到root用户
    TP3.2.3框架隐藏Home模块以及index.php入口文件的方法
    PHP打开错误提示和关闭错误提示的方法
  • 原文地址:https://www.cnblogs.com/rubylouvre/p/3336184.html
Copyright © 2011-2022 走看看