Semantic UI带你飞——Modal

2024-03-10 1087阅读

温馨提示:这篇文章已超过387天没有更新,请注意相关的内容是否还可用!

Semantic UI是一个逼格很高的前端框架,用了他,可以让你随时啪啪打设计经理、产品经理的脸。

Semantic UI带你飞——Modal
(图片来源网络,侵删)

但Semantic UI也是一个上手难度非常高的框架,尤其是他零散的className,而且这些className各自又能互相组合使用,所以,没有一定的耐性,可能会觉得他是一个巨啰嗦的框架。

虽然,Semantic UI也提供了很多Module View的套路样式封装,然而他的思想和Bootstrap、UIKit等完全不是一路的。这些套路都是又他的基本元素构造而成,你既可以单独将这些元素抽取出来用,也可以将不同的套路混搭使用,呃,真是五花八门。

最大的区别是,Semantic UI对空间、距离、字号,是使用em来处理的,这也是我2年前会看上他的一个重要因素。所以,本质上说,Semantic UI是通过字号来控制空间和距离的。当然其实你具体的去重载他的className,用具体的px,也是可以的。

好吧,多的就不啰嗦了,回到主题,Modal。

弹出层,是一个经常使用的东西,Semantic UI的Modal,样式做得很精致,包括弹出、消失的过度过程也非常流畅、充分,唯独有一样东西不好,就是控制太费解了,我看了老半天,都没闹明白他丫到底要干嘛,比如以下这个官网的例子:

$('.coupled.modal')
  .modal({
    allowMultiple: true
  })
;
// open second modal on first modal buttons
$('.second.modal')
  .modal('attach events', '.first.modal .button')
;// show first immediately
$('.first.modal')
  .modal('show')
;

attach events,好吧,我觉得他的设想可能很好,可是现实中应该不会有人去这么用吧。Modal的按钮点击,一般会直接跟具体的业务操作,比如发起ajax,操作别的什么元素之类的。虽然这里你可以附加一个闭包函数,可是我想吐槽的是,你能不用字符串做为接口或者属性名吗?这样真的让事情变复杂了。好吧我知道你还有API,不过我想说那个也让问题变得好好复杂。

官网的接口文档也没有直接给出如何能直接调用到Modal的实例的方法,只给了几个简单的配置参数,和modal方法访问的常用关键字字符……呃,实在忍不住了,扒拉了一下他的modal.js的源代码,呃,其实问题本来可以很简单,源代码封装得好好的,为啥就不把接口暴露出来呢?你也是够了,故作简易。

简单说,通过jQuery捕获到任意DOM对象,执行modal方法,可以理解为对这个modal进行初始化。

$('#hello_world').modal({
    // ...
});

只要你不调用modal(‘show’),他是不会乱来的。

那么如何取得他内部创建的这个Modal实例呢?其实他有一个默认的namespace,以module为前缀,modal访问名是:module-modal:

var modal = $('#hello_world').data('module-modal');
console.log(modal);

输出一下这个实例看看,其实里面的方法很完善,封装的好极了,可是为什么就是不暴露出来呢?

对于一般的modal的操作,只要知道:

modal.showModal(callback);
modal.hideModal(callback, keepDimmer);
modal.is.active();

其他的方法,说有用也有用,但上层应用一般也不会直接用到了。而他的Modal操作,我个人的看法是,就没必要用他的了,实在不好理解——关键是项目执行时间内,也没时间去理解他为啥要那么蹩脚。

所以,有了以下这么一个简单粗暴的封装:

define('module/UI', ['jquery', 'lodash'], function ($, _) {
   var Modal = function (options) {
      this.options = {
         prefix: 'modal_box_',
         namespace: 'semantic-modal',
         closable: true,
         cls: null,
         // default message
         icon: '',
         header: '',
         content: '',
         actions: {}
      };
      if (_.isObject(options))
         _.merge(this.options, options);
      this.id = _.uniqueId(this.options.prefix);
      this.body = false;
      this.modal = false;
      this.buttons = {};
      this.bodyActionsBox = null;
   };
   Modal.prototype.hasBody = function () {
      if (this.body !== false)
         return true;
      var el = document.getElementById(this.id);
      if (el) {
         this.body = $(el);
         return true;
      }
      return false;
   };
   Modal.prototype.initBody = function () {
      if ($('#' + this.id).get(0))
         return this;
      var closeIcon = !!this.options.closable ? '' : '';
      this.body = $('' + closeIcon + '');
      this.body.modal(this.options);
      if (this.options.cls)
         this.body.addClass(this.options.cls);
      this.initActions(this.options.actions);
      // 先在内存中把整个modal初始化完成了,这样可以不用牺牲页面渲染的性能
      $('body').append(this.body);
      return this;
   };
   Modal.prototype.getBody = function () {
      if (!this.hasBody())
         this.initBody();
      return this.body;
   };
   Modal.prototype.getModal = function () {
      if (!this.modal) {
         this.modal = this.getBody().data('module-' + this.options.namespace);
      }
      return this.modal;
   };
   Modal.prototype.hasActions = function () {
      return !!this.bodyActionsBox;
   };
   Modal.prototype.removeActions = function () {
      if (this.bodyActionsBox) {
         this.bodyActionsBox.remove();
         this.bodyActionsBox = false;
      }
      return this;
   };
   Modal.prototype.initActions = function (actions) {
      if (_.size(actions)  0) {
            _.each(fn, function (item) {
               me.on(event, item, isOne);
            });
         }
      }
      else if (_.isObject(event)) {
         _.forOwn(event, function (value, name) {
            me.on(name, value, isOne);
         });
      }
      return this;
   };
   Modal.prototype.one = function (event, fn) {
      return this.on(event, fn, true);
   };
   Modal.prototype.action = function (name) {
      var isBreak = $(this).triggerHandler(name);
      if (isBreak !== false)
         this.hide();
      return this;
   };
   Modal.prototype.isShow = function () {
      return this.getModal().is.active();
   };
   Modal.prototype.isHide = function () {
      return !this.isShow();
   };
   Modal.prototype.show = function (message) {
      if (_.isFunction(message))
         message = {then: message};
      else if (typeof message !== 'undefined' && (_.isString(message) || _.isObject(message)))
         this.setMessage(message);
      if (this.isHide())
         this.getModal().showModal(message && message.then);
      return this;
   };
   Modal.prototype.hide = function (then, keepDimmer) {
      var me = this;
      if (this.isShow()) {
         this.getModal().hideModal(then, keepDimmer);
      }
      return this;
   };
   Modal.prototype.setMessage = function (message) {
      if (_.isString(message))
         message = {content: message};
      this.setIcon(message.icon || null);
      this.setHeader(message.header || null);
      this.setContent(message.content || null);
      if (message.actions)
         this.on(message.actions, null, true);
      return this;
   };
   Modal.prototype.setIcon = function (icon) {
      var item = this.getBody().find('.header .icon');
      if (!icon || icon == '')
         icon = this.options.icon;
      if (!icon || icon == '')
         item.css('display', 'none');
      else {
         item.css('display', '');
         item.addClass(icon);
      }
      return this;
   };
   Modal.prototype.setHeader = function (content) {
      var item = this.getBody().find('.header .inner');
      if (!content || content.length == '')
         content = this.options.header;
      item.html(content);
      return this;
   };
   Modal.prototype.setContent = function (content) {
      var item = this.getBody().find('.content');
      if (!content || content.length == '')
         content = this.options.content;
      item.html(content);
      return this;
   };
   var globalModals = {};
   var stdModalOptions = [
      {
         access: 'alert',
         closable: false,
         cls: 'small',
         icon: 'comment outline',
         header: '消息提示',
         actions: {
            'ok': {
               text: '好的',
               cls: 'green right',
               icon: 'checkmark'
            }
         }
      },
      {
         access: 'confirm',
         closable: false,
         cls: 'small',
         icon: 'warning',
         header: '请确认',
         content: '你确定吗?',
         actions: {
            'yes': {
               text: '我知道了',
               cls: 'green',
               icon: 'checkmark'
            },
            'no': {
               text: '容我想想',
               cls: 'red',
               icon: 'remove'
            }
         }
      }
   ];
   var exports = {};
   exports.ModalClass = Modal;
   var getModal = exports.modal = function (id, options) {
      if (!globalModals[id])
         globalModals[id] = new Modal(options);
      return globalModals[id];
   };
   _.each(stdModalOptions, function(options) {
      var name = options.access;
      exports[name] = function (message, show) {
         var modal = getModal(name, options).setMessage(message);
         if (typeof show === 'undefined')
            show = true;
         if (!!show)
            modal.show(show);
         return modal;
      }
   });
   return exports;
});

他依赖于jQuery和lodash作为基本。

首先,这个封装,公布了两个标准的Modal,分别为alert和confirm

UI.alert('你好');
UI.alert({
    content: '你不被授权访问以下页面',
    // ok为alert默认的action
    actions: {
        ok: function(event) {
            return false; // 将中断隐藏的操作
        }
    }
});
UI.confirm({
    icon: 'info', // 换一个标题如何
    header: '这是标题',
    content: '这是内容',
    // contrim默认的actions
    actions: {
        yes: [
            function(event) {
            },
            function(event) {
            }
        ],
        no: function(event) {
        }
    }
})
// 不直接显示
UI.confirm('你确定吗?', false).show();
// 绑定自己的action
UI.confirm('你确定吗?', false).on('yes', function() {
    return false;
}).show();

其次,暴露出ModalClass,和modal方法,通过ModalCalss你可以创建自己的modal实例,并且自行对实例进行管理。而modal则是实例托管的调用。

// my_modal是全局访问的名称
// 第二个参数是配置
UI.modal('my_modal', {
   closable: true, // 是否可任意关闭
   cls: 'large', // 给modal附加的class
   icon: 'warning', // 默认的header的icon
   header: '请确认', // 默认的header内容
   content: '你确定吗?', // 默认的content内容
   actions: {
      'confirm': {
         text: '确认', // 按钮显示文字
         cls: 'green', // 按钮附加样式
         icon: 'checkmark' // 按钮的icon
         click: function() { // 绑定初始的事件
         }
      },
      'wait': {
         text: '容我想想',
         cls: 'red',
         icon: 'remove'
      }
   }
});
// 调用实例
UI.modal('my_modal').show();

如果你已经注册了某个Modal,想直接执行他的某个action,可以:

UI.modal('my_modal').action('confirm');

这个函数实际上就是触发事件。

嗯,其实以前使用UIKit的时候,封装过一个类似的,除了上述的操作,还有一个自动加载Ajax或者图片的需求,不过暂时够用了。

忘记说了,Semantic的官网来说,从他的例子来看,是把多个Modal写好,输出在HTML页面中,然后直接捕获这个元素执行modal方法。不过我想说,真的够了,谁没事为了弹个提示写那么多html呢。所以这个Modal的封装,就不需要在页面写个Modal了,直接调用就可以了。

作者:曾建凯

原文地址:https://my.oschina.net/janpoem/blog/626219

喜欢 0
VPS购买请点击我

免责声明:我们致力于保护作者版权,注重分享,被刊用文章因无法核实真实出处,未能及时与作者取得联系,或有版权异议的,请联系管理员,我们会立即处理! 部分文章是来自自研大数据AI进行生成,内容摘自(百度百科,百度知道,头条百科,中国民法典,刑法,牛津词典,新华词典,汉语词典,国家院校,科普平台)等数据,内容仅供学习参考,不准确地方联系删除处理! 图片声明:本站部分配图来自人工智能系统AI生成,觅知网授权图片,PxHere摄影无版权图库和百度,360,搜狗等多加搜索引擎自动关键词搜索配图,如有侵权的图片,请第一时间联系我们,邮箱:ciyunidc@ciyunshuju.com。本站只作为美观性配图使用,无任何非法侵犯第三方意图,一切解释权归图片著作权方,本站不承担任何责任。如有恶意碰瓷者,必当奉陪到底严惩不贷!

目录[+]