javascript 封装函数及其示例

本文详细介绍了JavaScript封装函数的实现,包括插件的编写方式、事件监听、拖拽功能以及表单验证插件。通过示例代码展示了如何创建可复用的组件,如拖动元素、弹框验证等,同时讲解了如何利用原型链实现组件的交互性和扩展性。文章还涉及到了性能优化和自定义事件的实现,帮助开发者理解JavaScript组件化的开发流程。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

javascript 封装函数

完整的插件的样子

;(function(window,document){
    var MaskShare = function(){
 
    };
    MaskShare.prototype = {};
 
    window.MaskShare = MaskShare;
}(window,document));
 //前面加;是防止跟其他js压缩时报错
;(function(global){
    //开启严格模式
    "use strict";
    //构造函数定义一个类    传参数
    function Scroll(el,options) {
        //some code
 
    };
 
 
    //原型上提供方法
    Scroll.prototype = {
        //定义方法
        show: function() {
            //some code
        }
        
    };
   
    if (typeof module !== 'undefined' && module.exports) {    //兼容CommonJs规范 
        module.exports = Scroll;
    }else if (typeof define === 'function'){   //兼容AMD/CMD规范
        define(function () {
            return Scroll
        })
    }else {    //注册全局变量,兼容直接使用script标签引入插件
        global.Scroll = Scroll;
    }
    
    
})(this);

// plugin.js

;(function(undefined) {

    "use strict"

    var _global;

    var plugin = {

        add: function(n1,n2){ return n1 + n2; },//加

        sub: function(n1,n2){ return n1 - n2; },//减

        mul: function(n1,n2){ return n1 * n2; },//乘

        div: function(n1,n2){ return n1 / n2; },//除

        sur: function(n1,n2){ return n1 % n2; } //余

    }

    // 最后将插件对象暴露给全局对象

    _global = (function(){ return this || (0, eval)('this'); }());

    if (typeof module !== "undefined" && module.exports) {

        module.exports = plugin;

    } else if (typeof define === "function" && define.amd) {

        define(function(){return plugin;});

    } else {

        !('plugin' in _global) && (_global.plugin = plugin);

    }

}());

表单验证插件

(function(window, document, undefined) {

    // 插件的默认参数

    var defaults = {

        messages: {

            required: 'The %s field is required.',

            matches: 'The %s field does not match the %s field.',

            "default": 'The %s field is still set to default, please change.',

            valid_email: 'The %s field must contain a valid email address.',

            valid_emails: 'The %s field must contain all valid email addresses.',

            min_length: 'The %s field must be at least %s characters in length.',

            max_length: 'The %s field must not exceed %s characters in length.',

            exact_length: 'The %s field must be exactly %s characters in length.',

            greater_than: 'The %s field must contain a number greater than %s.',

            less_than: 'The %s field must contain a number less than %s.',

            alpha: 'The %s field must only contain alphabetical characters.',

            alpha_numeric: 'The %s field must only contain alpha-numeric characters.',

            alpha_dash: 'The %s field must only contain alpha-numeric characters, underscores, and dashes.',

            numeric: 'The %s field must contain only numbers.',

            integer: 'The %s field must contain an integer.',

            decimal: 'The %s field must contain a decimal number.',

            is_natural: 'The %s field must contain only positive numbers.',

            is_natural_no_zero: 'The %s field must contain a number greater than zero.',

            valid_ip: 'The %s field must contain a valid IP.',

            valid_base64: 'The %s field must contain a base64 string.',

            valid_credit_card: 'The %s field must contain a valid credit card number.',

            is_file_type: 'The %s field must contain only %s files.',

            valid_url: 'The %s field must contain a valid URL.',

            greater_than_date: 'The %s field must contain a more recent date than %s.',

            less_than_date: 'The %s field must contain an older date than %s.',

            greater_than_or_equal_date: 'The %s field must contain a date that\'s at least as recent as %s.',

            less_than_or_equal_date: 'The %s field must contain a date that\'s %s or older.'

        },

        callback: function(errors) {

        }

    };

    var ruleRegex = /^(.+?)\[(.+)\]$/,

        numericRegex = /^[0-9]+$/,

        integerRegex = /^\-?[0-9]+$/,

        decimalRegex = /^\-?[0-9]*\.?[0-9]+$/,

        emailRegex = /^[a-zA-Z0-9.!#$%&'*+/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*$/,

        alphaRegex = /^[a-z]+$/i,

        alphaNumericRegex = /^[a-z0-9]+$/i,

        alphaDashRegex = /^[a-z0-9_\-]+$/i,

        naturalRegex = /^[0-9]+$/i,

        naturalNoZeroRegex = /^[1-9][0-9]*$/i,

        ipRegex = /^((25[0-5]|2[0-4][0-9]|1[0-9]{2}|[0-9]{1,2})\.){3}(25[0-5]|2[0-4][0-9]|1[0-9]{2}|[0-9]{1,2})$/i,

        base64Regex = /[^a-zA-Z0-9\/\+=]/i,

        numericDashRegex = /^[\d\-\s]+$/,

        urlRegex = /^((http|https):\/\/(\w+:{0,1}\w*@)?(\S+)|)(:[0-9]+)?(\/|\/([\w#!:.?+=&%@!\-\/]))?$/,

        dateRegex = /\d{4}-\d{1,2}-\d{1,2}/;

    ... //省略后面的代码

})(window,document);

/*

 * Export as a CommonJS module

 */

if (typeof module !== 'undefined' && module.exports) {

    module.exports = FormValidator;

}

onmousedown,onmouseover,onmouseout事件

(function (window, undefined) {
  var dom = {
    //绑定事件
    on: function (node, eventName, handler) {
      if (node.addEventListener) {
        node.addEventListener(eventName, handler);
      } else {
        node.attachEvent("on" + eventName, handler);
      }
    },
    //获取元素的样式
    getStyle: function (node, styleName) {
      var realStyle = null;
      if (window.getComputedStyle) {
        realStyle = window.getComputedStyle(node, null)[styleName];
      } else if (node.currentStyle) {
        realStyle = node.currentStyle[styleName];
      }
      return realStyle;
    },
    //获取设置元素的样式
    setCss: function (node, css) {
      for (var key in css) {
        node.style[key] = css[key];
      }
    },
  };

  //#region 拖拽元素类
  function DragElement(node) {
    this.node = node;
    this.x = 0;
    this.y = 0;
  }
  DragElement.prototype = {
    constructor: DragElement,
    init: function () {
      this.setEleCss({
        left: dom.getStyle(node, "left"),
        top: dom.getStyle(node, "top"),
      }).setXY(node.style.left, node.style.top);
    },
    setXY: function (x, y) {
      this.x = parseInt(x) || 0;
      this.y = parseInt(y) || 0;
      return this;
    },
    setEleCss: function (css) {
      dom.setCss(this.node, css);
      return this;
    },
  };
  //#endregion

  //#region 鼠标元素
  function Mouse() {
    this.x = 0;
    this.y = 0;
  }
  Mouse.prototype.setXY = function (x, y) {
    this.x = parseInt(x);
    this.y = parseInt(y);
  };
  //#endregion

  //拖拽配置
  var draggableConfig = {
    zIndex: 1,
    draggingObj: null,
    mouse: new Mouse(),
  };

  function Drag(ele) {
    this.ele = ele;

    function mouseDown(event) {
      var ele = event.target || event.srcElement;

      draggableConfig.mouse.setXY(event.clientX, event.clientY);

      draggableConfig.draggingObj = new DragElement(ele);
      draggableConfig.draggingObj
        .setXY(ele.style.left, ele.style.top)
        .setEleCss({
          zIndex: draggableConfig.zIndex++,
          position: "relative",
        });
    }

    ele.onselectstart = function () {
      //防止拖拽对象内的文字被选中
      return false;
    };
    dom.on(ele, "mousedown", mouseDown);
  }

  dom.on(document, "mousemove", function (event) {
    if (draggableConfig.draggingObj) {
      var mouse = draggableConfig.mouse,
        draggingObj = draggableConfig.draggingObj;
      draggingObj.setEleCss({
        left: parseInt(event.clientX - mouse.x + draggingObj.x) + "px",
        top: parseInt(event.clientY - mouse.y + draggingObj.y) + "px",
      });
    }
  });

  dom.on(document, "mouseup", function (event) {
    draggableConfig.draggingObj = null;
  });

  window.Drag = Drag;
})(window, undefined);

调用方法:Drag(document.getElementById(“obj”));

注意的一点,为了防止选中拖拽元素中的文字,通过onselectstart事件处理程序return false来处理这个问题。

弹框的顶部是可以进行拖拽操作的,内容区域是不可拖拽的,怎么实现这样的效果呢:

首先优化拖拽元素对象如下,增加一个目标元素target,表示被拖拽对象,在上图的登录框中,就是整个登录窗口。

被记录和设置坐标的拖拽元素就是这个目标元素,但是它并不是整个部分都是拖拽的有效部分。我们在html结构中为拖拽的有效区域添加类draggable表示有效拖拽区域:

<div id="obj1" class="dialog" style="position:relative;left:50px">
	<div class="header draggable">
		拖拽的有效元素
	</div>
	<div class="content">
		拖拽对象1
	</div>
</div>

然后修改Drag方法如下:

function drag(ele) {
  var dragNode = (ele.querySelector(".draggable") || ele);
  dom.on(dragNode, "mousedown", function (event) {
    var dragElement = draggableConfig.dragElement = new DragElement(ele);
    draggableConfig.mouse.setXY(event.clientX, event.clientY);
    draggableConfig.dragElement
      .setXY(dragElement.target.style.left, dragElement.target.style.top)
      .setTargetCss({
        "zIndex": draggableConfig.zIndex++,
        "position": "relative"
      });
  }).on(dragNode, "mouseover", function () {
    dom.setCss(this, draggableStyle.dragging);
  }).on(dragNode, "mouseout", function () {
    dom.setCss(this, draggableStyle.defaults);
  });
}

主要修改的是绑定mousedown的节点变成了包含draggable类的有效元素,如果不含有draggable,则整个元素都是有效元素。

性能优化和总结
由于onmousemove在一直调用,会造成一些性能问题,我们可以通过setTimout来延迟绑定onmousemove事件,改进move函数如下

function move(event) {
  if (draggableConfig.dragElement) {
    var mouse = draggableConfig.mouse,
      dragElement = draggableConfig.dragElement;
    dragElement.setTargetCss({
      left: parseInt(event.clientX - mouse.x + dragElement.x) + "px",
      top: parseInt(event.clientY - mouse.y + dragElement.y) + "px",
    });

    dom.off(document, "mousemove", move);
    setTimeout(function () {
      dom.on(document, "mousemove", move);
    }, 25);
  }
}

编写UI组件

一般情况,如果一个js仅仅是处理一个逻辑,我们称之为插件,但如果与dom和css有关系并且具备一定的交互性,一般叫做组件。当然这没有什么明显的区分,只是一种习惯性叫法。
利用原型链,可以将一些UI层面的业务代码封装在一个小组件中,并利用js实现组件的交互性。
现有一个这样的需求:

  1. 实现一个弹层,此弹层可以显示一些文字提示性的信息;
  2. 弹层右上角必须有一个关闭按扭,点击之后弹层消失;
  3. 弹层底部必有一个“确定”按扭,然后根据需求,可以配置多一个“取消”按扭;
  4. 点击“确定”按扭之后,可以触发一个事件;
  5. 点击关闭/“取消”按扭后,可以触发一个事件。

根据需求,我们先写出dom结构:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>index</title>
    <link rel="stylesheet" type="text/css" href="index.css">
</head>
<body>
    <div class="mydialog">
        <span class="close">×</span>
        <div class="mydialog-cont">
            <div class="cont">hello world!</div>
        </div>
        <div class="footer">
            <span class="btn">确定</span>
            <span class="btn">取消</span>
        </div>
    </div>
    <script src="index.js"></script>
</body>
</html>
* { padding: 0; margin: 0; }
.mydialog { background: #fff; box-shadow: 0 1px 10px 0 rgba(0, 0, 0, 0.3); overflow: hidden; width: 300px; height: 180px; border: 1px solid #dcdcdc; position: absolute; top: 0; right: 0; bottom: 0; left: 0; margin: auto; }
.close { position: absolute; right: 5px; top: 5px; width: 16px; height: 16px; line-height: 16px; text-align: center; font-size: 18px; cursor: pointer; }
.mydialog-cont { padding: 0 0 50px; display: table; width: 100%; height: 100%; }
.mydialog-cont .cont { display: table-cell; text-align: center; vertical-align: middle; width: 100%; height: 100%; }
.footer { display: table; table-layout: fixed; width: 100%; position: absolute; bottom: 0; left: 0; border-top: 1px solid #dcdcdc; }
.footer .btn { display: table-cell; width: 50%; height: 50px; line-height: 50px; text-align: center; cursor: pointer; }
.footer .btn:last-child { display: table-cell; width: 50%; height: 50px; line-height: 50px; text-align: center; cursor: pointer; border-left: 1px solid #dcdcdc; }

接下来,我们开始编写我们的交互插件。
我们假设组件的弹出层就是一个对象。则这个对象是包含了我们的交互、样式、结构及渲染的过程。于是我们定义了一个构造方法:

function MyDialog(){} // MyDialog就是我们的组件对象了

对象MyDialog就相当于一个绳子,我们只要往这个绳子上不断地挂上钩子就是一个组件了。于是我们的组件就可以表示为:

function MyDialog(){}
MyDialog.prototype = {
    constructor: this,
    _initial: function(){},
    _parseTpl: function(){},
    _parseToDom: function(){},
    show: function(){},
    hide: function(){},
    css: function(){},
    ...
}

然后就可以将插件的功能都写上。不过中间的业务逻辑,需要自己去一步一步研究。无论如何写,我们最终要做到通过实例化一个MyDialog对象就可以使用我们的插件了。
在编写的过程中,我们得先做一些工具函数:

对象合并函数
// 对象合并
function extend(o,n,override) {
    for(var key in n){
        if(n.hasOwnProperty(key) && (!o.hasOwnProperty(key) || override)){
            o[key]=n[key];
        }
    }
    return o;
}
自定义模板引擎解释函数
// 自定义模板引擎
function templateEngine(html, data) {
    var re = /<%([^%>]+)?%>/g,
        reExp = /(^( )?(if|for|else|switch|case|break|{|}))(.*)?/g,
        code = 'var r=[];\n',
        cursor = 0;
    var match;
    var add = function(line, js) {
        js ? (code += line.match(reExp) ? line + '\n' : 'r.push(' + line + ');\n') :
            (code += line != '' ? 'r.push("' + line.replace(/"/g, '\\"') + '");\n' : '');
        return add;
    }
    while (match = re.exec(html)) {
        add(html.slice(cursor, match.index))(match[1], true);
        cursor = match.index + match[0].length;
    }
    add(html.substr(cursor, html.length - cursor));
    code += 'return r.join("");';
    return new Function(code.replace(/[\r\t\n]/g, '')).apply(data);
}
查找class获取dom函数
// 通过class查找dom
if(!('getElementsByClass' in HTMLElement)){
    HTMLElement.prototype.getElementsByClass = function(n, tar){
        var el = [],
            _el = (!!tar ? tar : this).getElementsByTagName('*');
        for (var i=0; i<_el.length; i++ ) {
            if (!!_el[i].className && (typeof _el[i].className == 'string') && _el[i].className.indexOf(n) > -1 ) {
                el[el.length] = _el[i];
            }
        }
        return el;
    };
    ((typeof HTMLDocument !== 'undefined') ? HTMLDocument : Document).prototype.getElementsByClass = HTMLElement.prototype.getElementsByClass;
}

结合工具函数,再去实现每一个钩子函数具体逻辑结构:

// plugin.js
;(function(undefined) {
    "use strict"
    var _global;

    ...

    // 插件构造函数 - 返回数组结构
    function MyDialog(opt){
        this._initial(opt);
    }
    MyDialog.prototype = {
        constructor: this,
        _initial: function(opt) {
            // 默认参数
            var def = {
                ok: true,
                ok_txt: '确定',
                cancel: false,
                cancel_txt: '取消',
                confirm: function(){},
                close: function(){},
                content: '',
                tmpId: null
            };
            this.def = extend(def,opt,true);
            this.tpl = this._parseTpl(this.def.tmpId);
            this.dom = this._parseToDom(this.tpl)[0];
            this.hasDom = false;
        },
        _parseTpl: function(tmpId) { // 将模板转为字符串
            var data = this.def;
            var tplStr = document.getElementById(tmpId).innerHTML.trim();
            return templateEngine(tplStr,data);
        },
        _parseToDom: function(str) { // 将字符串转为dom
            var div = document.createElement('div');
            if(typeof str == 'string') {
                div.innerHTML = str;
            }
            return div.childNodes;
        },
        show: function(callback){
            var _this = this;
            if(this.hasDom) return ;
            document.body.appendChild(this.dom);
            this.hasDom = true;
            document.getElementsByClass('close',this.dom)[0].onclick = function(){
                _this.hide();
            };
            document.getElementsByClass('btn-ok',this.dom)[0].onclick = function(){
                _this.hide();
            };
            if(this.def.cancel){
                document.getElementsByClass('btn-cancel',this.dom)[0].onclick = function(){
                    _this.hide();
                };
            }
            callback && callback();
            return this;
        },
        hide: function(callback){
            document.body.removeChild(this.dom);
            this.hasDom = false;
            callback && callback();
            return this;
        },
        modifyTpl: function(template){
            if(!!template) {
                if(typeof template == 'string'){
                    this.tpl = template;
                } else if(typeof template == 'function'){
                    this.tpl = template();
                } else {
                    return this;
                }
            }
            // this.tpl = this._parseTpl(this.def.tmpId);
            this.dom = this._parseToDom(this.tpl)[0];
            return this;
        },
        css: function(styleObj){
            for(var prop in styleObj){
                var attr = prop.replace(/[A-Z]/g,function(word){
                    return '-' + word.toLowerCase();
                });
                this.dom.style[attr] = styleObj[prop];
            }
            return this;
        },
        width: function(val){
            this.dom.style.width = val + 'px';
            return this;
        },
        height: function(val){
            this.dom.style.height = val + 'px';
            return this;
        }
    }

    _global = (function(){ return this || (0, eval)('this'); }());
    if (typeof module !== "undefined" && module.exports) {
        module.exports = MyDialog;
    } else if (typeof define === "function" && define.amd) {
        define(function(){return MyDialog;});
    } else {
        !('MyDialog' in _global) && (_global.MyDialog = MyDialog);
    }
}());

到这一步,我们的插件已经达到了基础需求了。我们可以在页面这样调用:

<script type="text/template" id="dialogTpl">
    <div class="mydialog">
        <span class="close">×</span>
        <div class="mydialog-cont">
            <div class="cont"><% this.content %></div>
        </div>
        <div class="footer">
            <% if(this.cancel){ %>
            <span class="btn btn-ok"><% this.ok_txt %></span>
            <span class="btn btn-cancel"><% this.cancel_txt %></span>
            <% } else{ %>
            <span class="btn btn-ok" style="width: 100%"><% this.ok_txt %></span>
            <% } %>
        </div>
    </div>
</script>
<script src="index.js"></script>
<script>
    var mydialog = new MyDialog({
        tmpId: 'dialogTpl',
        cancel: true,
        content: 'hello world!'
    });
    mydialog.show();
</script>

插件的监听
弹出框插件我们已经实现了基本的显示与隐藏的功能。不过我们在怎么时候弹出,弹出之后可能进行一些操作,实际上还是需要进行一些可控的操作。就好像我们进行事件绑定一样,只有用户点击了按扭,才响应具体的事件。那么,我们的插件,应该也要像事件绑定一样,只有执行了某些操作的时候,调用相应的事件响应。
这种js的设计模式,被称为 订阅/发布模式,也被叫做 观察者模式。我们插件中的也需要用到观察者模式,比如,在打开弹窗之前,我们需要先进行弹窗的内容更新,执行一些判断逻辑等,然后执行完成之后才显示出弹窗。在关闭弹窗之后,我们需要执行关闭之后的一些逻辑,处理业务等。这时候我们需要像平时绑定事件一样,给插件做一些“事件”绑定回调方法。
我们jquery对dom的事件响应是这样的:

$(<dom>).on("click",function(){})

我们照着上面的方式设计了对应的插件响应是这样的:

mydialog.on('show',function(){})

则,我们需要实现一个事件机制,以达到监听插件的事件效果。关于自定义事件监听,可以参考一篇博文:漫谈js自定义事件、DOM/伪DOM自定义事件。在此不进行大篇幅讲自定义事件的问题。
最终我们实现的插件代码为:

// plugin.js
;(function(undefined) {
    "use strict"
    var _global;

    // 工具函数
    // 对象合并
    function extend(o,n,override) {
        for(var key in n){
            if(n.hasOwnProperty(key) && (!o.hasOwnProperty(key) || override)){
                o[key]=n[key];
            }
        }
        return o;
    }
    // 自定义模板引擎
    function templateEngine(html, data) {
        var re = /<%([^%>]+)?%>/g,
            reExp = /(^( )?(if|for|else|switch|case|break|{|}))(.*)?/g,
            code = 'var r=[];\n',
            cursor = 0;
        var match;
        var add = function(line, js) {
            js ? (code += line.match(reExp) ? line + '\n' : 'r.push(' + line + ');\n') :
                (code += line != '' ? 'r.push("' + line.replace(/"/g, '\\"') + '");\n' : '');
            return add;
        }
        while (match = re.exec(html)) {
            add(html.slice(cursor, match.index))(match[1], true);
            cursor = match.index + match[0].length;
        }
        add(html.substr(cursor, html.length - cursor));
        code += 'return r.join("");';
        return new Function(code.replace(/[\r\t\n]/g, '')).apply(data);
    }
    // 通过class查找dom
    if(!('getElementsByClass' in HTMLElement)){
        HTMLElement.prototype.getElementsByClass = function(n){
            var el = [],
                _el = this.getElementsByTagName('*');
            for (var i=0; i<_el.length; i++ ) {
                if (!!_el[i].className && (typeof _el[i].className == 'string') && _el[i].className.indexOf(n) > -1 ) {
                    el[el.length] = _el[i];
                }
            }
            return el;
        };
        ((typeof HTMLDocument !== 'undefined') ? HTMLDocument : Document).prototype.getElementsByClass = HTMLElement.prototype.getElementsByClass;
    }

    // 插件构造函数 - 返回数组结构
    function MyDialog(opt){
        this._initial(opt);
    }
    MyDialog.prototype = {
        constructor: this,
        _initial: function(opt) {
            // 默认参数
            var def = {
                ok: true,
                ok_txt: '确定',
                cancel: false,
                cancel_txt: '取消',
                confirm: function(){},
                close: function(){},
                content: '',
                tmpId: null
            };
            this.def = extend(def,opt,true); //配置参数
            this.tpl = this._parseTpl(this.def.tmpId); //模板字符串
            this.dom = this._parseToDom(this.tpl)[0]; //存放在实例中的节点
            this.hasDom = false; //检查dom树中dialog的节点是否存在
            this.listeners = []; //自定义事件,用于监听插件的用户交互
            this.handlers = {};
        },
        _parseTpl: function(tmpId) { // 将模板转为字符串
            var data = this.def;
            var tplStr = document.getElementById(tmpId).innerHTML.trim();
            return templateEngine(tplStr,data);
        },
        _parseToDom: function(str) { // 将字符串转为dom
            var div = document.createElement('div');
            if(typeof str == 'string') {
                div.innerHTML = str;
            }
            return div.childNodes;
        },
        show: function(callback){
            var _this = this;
            if(this.hasDom) return ;
            if(this.listeners.indexOf('show') > -1) {
                if(!this.emit({type:'show',target: this.dom})) return ;
            }
            document.body.appendChild(this.dom);
            this.hasDom = true;
            this.dom.getElementsByClass('close')[0].onclick = function(){
                _this.hide();
                if(_this.listeners.indexOf('close') > -1) {
                    _this.emit({type:'close',target: _this.dom})
                }
                !!_this.def.close && _this.def.close.call(this,_this.dom);
            };
            this.dom.getElementsByClass('btn-ok')[0].onclick = function(){
                _this.hide();
                if(_this.listeners.indexOf('confirm') > -1) {
                    _this.emit({type:'confirm',target: _this.dom})
                }
                !!_this.def.confirm && _this.def.confirm.call(this,_this.dom);
            };
            if(this.def.cancel){
                this.dom.getElementsByClass('btn-cancel')[0].onclick = function(){
                    _this.hide();
                    if(_this.listeners.indexOf('cancel') > -1) {
                        _this.emit({type:'cancel',target: _this.dom})
                    }
                };
            }
            callback && callback();
            if(this.listeners.indexOf('shown') > -1) {
                this.emit({type:'shown',target: this.dom})
            }
            return this;
        },
        hide: function(callback){
            if(this.listeners.indexOf('hide') > -1) {
                if(!this.emit({type:'hide',target: this.dom})) return ;
            }
            document.body.removeChild(this.dom);
            this.hasDom = false;
            callback && callback();
            if(this.listeners.indexOf('hidden') > -1) {
                this.emit({type:'hidden',target: this.dom})
            }
            return this;
        },
        modifyTpl: function(template){
            if(!!template) {
                if(typeof template == 'string'){
                    this.tpl = template;
                } else if(typeof template == 'function'){
                    this.tpl = template();
                } else {
                    return this;
                }
            }
            this.dom = this._parseToDom(this.tpl)[0];
            return this;
        },
        css: function(styleObj){
            for(var prop in styleObj){
                var attr = prop.replace(/[A-Z]/g,function(word){
                    return '-' + word.toLowerCase();
                });
                this.dom.style[attr] = styleObj[prop];
            }
            return this;
        },
        width: function(val){
            this.dom.style.width = val + 'px';
            return this;
        },
        height: function(val){
            this.dom.style.height = val + 'px';
            return this;
        },
        on: function(type, handler){
            // type: show, shown, hide, hidden, close, confirm
            if(typeof this.handlers[type] === 'undefined') {
                this.handlers[type] = [];
            }
            this.listeners.push(type);
            this.handlers[type].push(handler);
            return this;
        },
        off: function(type, handler){
            if(this.handlers[type] instanceof Array) {
                var handlers = this.handlers[type];
                for(var i = 0, len = handlers.length; i < len; i++) {
                    if(handlers[i] === handler) {
                        break;
                    }
                }
                this.listeners.splice(i, 1);
                handlers.splice(i, 1);
                return this;
            }
        },
        emit: function(event){
            if(!event.target) {
                event.target = this;
            }
            if(this.handlers[event.type] instanceof Array) {
                var handlers = this.handlers[event.type];
                for(var i = 0, len = handlers.length; i < len; i++) {
                    handlers[i](event);
                    return true;
                }
            }
            return false;
        }
    }

    // 最后将插件对象暴露给全局对象
    _global = (function(){ return this || (0, eval)('this'); }());
    if (typeof module !== "undefined" && module.exports) {
        module.exports = MyDialog;
    } else if (typeof define === "function" && define.amd) {
        define(function(){return MyDialog;});
    } else {
        !('MyDialog' in _global) && (_global.MyDialog = MyDialog);
    }
}());

然后调用的时候就可以直接使用插件的事件绑定了。

var mydialog = new MyDialog({
    tmpId: 'dialogTpl',
    cancel: true,
    content: 'hello world!'
});
mydialog.on('confirm',function(ev){
    console.log('you click confirm!');
    // 写你的确定之后的逻辑代码...
});
document.getElementById('test').onclick = function(){
    mydialog.show();
}

给出此例子的demo,有需要具体实现的同学可以去查阅。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值