easyform表单校验插件改版源码
改动特性:
1.支持回调,可用于ajax提交
2.提示框样式修改,原版太丑,修改成bootstrap的popover 样式
原版还存在缺陷:被校验的表单元素设置不灵活,还得加上id、name 什么的,建议设置个data-id等属性,有时间再改,效果和jquery-validate差不多,气泡效果提示
效果图:
具体代码作用不做阐述,如有类似需求,请私信。主要源码如下:
(1)easyform.css文件
.easy-black{color:rgba(238,238,238,1);background-color:rgba(75,75,75,0.8);} .easy-blue{color:rgba(255,255,255,1);background-color:rgba(51,153,204,0.8);} .easy-red{color:rgba(255,255,255,1);background-color:rgba(255,102,102,0.9);} .easy-white{color:#ff3636;background-color:rgba(255,255,255,0.9)} .popover { position: absolute; top: 0; left: 0; z-index: 1060; display: none; max-width: 276px; padding: 1px; font-family: "Helvetica Neue",Helvetica,Arial,sans-serif; font-size: 14px; font-style: normal; font-weight: 400; line-height: 1.42857143; text-align: left; text-align: start; text-decoration: none; text-shadow: none; text-transform: none; letter-spacing: normal; word-break: normal; word-spacing: normal; word-wrap: normal; white-space: normal; background-color: #fff; -webkit-background-clip: padding-box; background-clip: padding-box; border: 1px solid #ccc; border: 1px solid rgba(0,0,0,.2); border-radius: 6px; -webkit-box-shadow: 0 5px 10px rgba(0,0,0,.2); box-shadow: 0 5px 10px rgba(0,0,0,.2); line-break: auto; } /***提示框***/ .popover>.arrow { border-width: 11px; } .popover>.arrow, .popover>.arrow:after { position: absolute; display: block; width: 0; height: 0; border-color: transparent; border-style: solid; } .popover>.arrow:after { content: ""; border-width: 10px; } .popover-content { padding: 9px 14px; } .fade.in { opacity: 1; } .fade { opacity: 0; -webkit-transition: opacity .15s linear; -o-transition: opacity .15s linear; transition: opacity .15s linear; } /**右边位置的提示框**/ .popover.right { margin-left: 10px; } .popover.right>.arrow { top: 50%; left: -11px; margin-top: -11px; border-right-color: #999; border-right-color: rgba(0,0,0,.25); border-left-width: 0; } .popover.right>.arrow:after { bottom: -10px; left: 1px; content: " "; border-right-color: #fff; border-left-width: 0; } /***********TODO://下面三个位置的样式需要结合easyform脚本文件调一下******************/ /**左边位置的提示框**/ .popover.left { margin-left: -10px; } .popover.left>.arrow { top: 50%; right: -11px; margin-top: -11px; border-right-width: 0; border-left-color: #999; border-left-color: rgba(0,0,0,.25); } .popover.left>.arrow:after { right: 1px; bottom: -10px; content: " "; border-right-width: 0; border-left-color: #fff; } /**上边位置的提示框**/ .popover.top { margin-top: -10px; } .popover.top>.arrow { bottom: -11px; left: 50%; margin-left: -11px; border-top-color: #999; border-top-color: rgba(0,0,0,.25); border-bottom-width: 0; } .popover.top>.arrow:after { bottom: 1px; margin-left: -10px; content: " "; border-top-color: #fff; border-bottom-width: 0; } /**下边位置的提示框**/ .popover.bottom { margin-top: 10px; } .popover.bottom>.arrow { top: -11px; left: 50%; margin-left: -11px; border-top-width: 0; border-bottom-color: #999; border-bottom-color: rgba(0,0,0,.25); } .popover.bottom>.arrow:after { top: 1px; margin-left: -10px; content: " "; border-top-width: 0; border-bottom-color: #fff; }
(2)easyform.js 脚本文件
/* * 表单验证插件 easyform * 2014-11-5 * 用于表单验证 * 只要在需要验证的控件上添加easyform属性即可,多个属性用[;]连接,语法类似css * 属性列表: * null * email * char-normal 英文、数字、下划线 * char-chinese 中文、英文、数字、下划线、中文标点符号 * char-english 英文、数字、下划线、英文标点符号 * length:1 10 / length:4 能够识别汉字等宽字符长度 * equal:xxx 等于某个对象的值,冒号后是jq选择器语法 * ajax:fun() * real-time 实时检查 * date 2014-10-31 * time 10:30:00 * datetime 2014-10-31 10:30:00 * money 正数,两位小数 * uint :1 100 正整数 , 参数为起始值和最大值 * number 不限长度的数字字符串 * float:7 2 * regex:"^(\\d{4})-(\\d{2})-(\\d{2})$" * mobile 手机 * */ /** * 读取一个控件的指定data属性,并通过:和;来分割成key/value值对 * @id string 控件id * @name string 属性名称 **/ if (typeof(easy_load_options) == "undefined") { // function easy_load_options(id, name) // # by galandeo, fix bug function easy_load_options(obj, name) { var options = $(obj).data(name); // var options = $("#" + id).data(name); //将字符串用;分割 options = (!!options ? options.split(";") : undefined); var data = Object(); if (!!options) { var index; for (index in options) { var temps = options[index]; var p = temps.indexOf(":"); var temp = []; if (-1 == p) { temp[0] = temps; temp[1] = ""; } else { temp[0] = temps.substring(0, p); temp[1] = temps.substring(p + 1); } if (temp[0].length > 0) { data[temp[0]] = temp[1]; } } } return data; } } //easyform (function ($, window, document, undefined) { /* 构造函数 **/ var _easyform = function (ele, opt) { this.form = ele; this.id = Math.random(); if (0 == this.form.length && "form" != this.form[0].localName) { throw new Error("easyform need a form !"); } this.defaults = { easytip: true, //是否显示easytip,可以关闭后,使用自定义的提示信息 success: null, error: null, complete: null, per_validation: null }; this.options = $.extend({}, this.defaults, opt); this.is_submit = true; //是否提交,如果为false,即使验证成功也不会执行提交 //事件定义 this.success = this.options.success; this.error = this.options.error; this.complete = this.options.complete; this.callback = this.options.callback;//所有验证成功的回调 用于ajax提交,默认表单提交 this.per_validation = this.options.per_validation; //在所有验证之前执行 this._check_back = null; }; //方法 _easyform.prototype = { init: function () { this.inputs = []; this.counter_success = []; //已经判断成功的input计数 this.counter = []; //已经判断的input计数 var $this = this; $this._load(); //改写 submit 的属性,便于控制 this.submit_button = this.form.find("input:submit"); this.submit_button.each(function () { var button = $(this); button.attr("type", "button"); //提交前判断 button.click(function () { $this.submit(true); } ); } ); return this; }, _load: function (iterator) { if (!iterator) { iterator = "input:visible, textarea:visible"; } for (var i in this.inputs) { this.inputs[i].destructor(); } //析构旧的easyinput,防止real-time条件下的重复验证。 this._array_empty(this.inputs); var $this = this; this.form.find(iterator).each(function (index, input) { //排除 hidden、button、submit、file if (input.type != "hidden" && input.type != "button" && input.type != "submit" && input.type != "file") { if (input.type == "radio" || input.type == "checkbox") { var name = input.name; for (index in $this.inputs) { if (name == $this.inputs[index].input[0].name) { return; } } } var checker = $(input).easyinput({easytip: $this.options.easytip}); checker.error = function (e, r) { $this.is_submit = false; //$this.result.push(e); if (!!$this.error) //失败事件 { $this.error($this, e, r); } }; checker.complete = function (e) { //记录已经完成检查的input $this._array_add_unique($this.counter, (!!e.id ? e.id : e.name)); if ($this.counter.length == $this.inputs.length) { //$this._array_empty($this.counter_success); //$this._array_empty($this.counter); if (!!$this.complete) //结束事件 { $this.complete($this); } if (!!$this._check_back) { $this._check_back($this._is_success()); $this._check_back = null; } } }; checker.success = function (e) { //记录检查成功的控件 $this._array_add_unique($this.counter_success, (!!e.id ? e.id : e.name)); if ($this._is_success()) { //$this._array_empty($this.counter_success); //$this._array_empty($this.counter); if (!!$this.success) //成功事件 { $this.success($this); } if (!!$this.is_submit) { if($this.callback && $.isFunction($this.callback)){ $this.callback(); return false; } $this.form.submit() } } }; $this.inputs.push(checker); } } ); }, _is_success: function () { return this.inputs.length == this.counter_success.length; }, _array_empty: function (arr) { arr.splice(0, arr.length); }, _array_add_unique: function (arr, value) { if (-1 == arr.indexOf(value)) { arr.push(value); } }, _check: function (submit) { this._array_empty(this.counter_success); this._array_empty(this.counter); this.is_submit = submit; //执行per_validation事件 if (!!this.per_validation) { this.is_submit = this.per_validation(this); } //如果没有需要判断的控件 if (this.inputs.length == 0) { if (!!this.success) //成功事件 { this.success(this); } if (!!this.complete) //结束事件 { this.complete(this); } if (this.is_submit) { if(this.callback && $.isFunction(this.callback)){ this.callback(); return false; } this.form.submit() } } var index; for (index in this.inputs) { this.inputs[index].validation(false); } }, /* * 表单提交函数 * @submit:bool值,用于定义是否真的提交表单 * */ submit: function (submit) { this._load(); //重新载入控件 this._check(submit); //验证并提交 }, check: function (iterator, fun) { this._check_back = fun; this._load(iterator); //重新载入控件 this._check(false); //验证不提交 }, show: function (iterator, msg) { if (!iterator) { iterator = "input:visible, textarea:visible"; } this.form.find(iterator).each(function (index, input) { if (input.type != "hidden" && input.type != "button" && input.type != "submit" && input.type != "file") { $(this).easytip().show(msg); } } ); } }; //添加到jquery $.fn.easyform = function (options) { var validation = new _easyform(this, options); return validation.init(); }; })(jQuery, window, document); //easyinput (function ($, window, document, undefined) { //单个input的检查器构造函数 var _easyinput = function (input, opt) { if (0 == input.length) { throw new Error("easyform need a input object !"); } this.input = input; //绑定的控件 this.rules = []; //规则 //事件 this.error = null; this.success = null; this.complete = null; this.defaults = { "easytip": true, //是否显示easytip "real-time": false }; this.tip = null; //关联的tip //读取 data-easyform属性 // this.rules = easy_load_options(input[0].id, "easyform"); // # by galandeo, fix bug this.rules = easy_load_options(input[0], "easyform"); //处理data-easyform中的配置属性 var o = Object(); for (var index in this.rules) { if (index == "easytip") { o["easytip"] = this.rules[index]; } else if (index == "real-time") { o["real-time"] = true; } } delete this.rules["easytip"]; delete this.rules["real-time"]; this.options = $.extend({}, this.defaults, opt, o); this.counter_success = 0; //计数器,记录已经有多少个条件成功 this.counter = 0; //计数器,记录已经验证了多少条件 this.is_error = false; //错误标志 }; //单个input的检查器 _easyinput.prototype = { init: function () { //初始化easytip if (true === this.options.easytip) { this.tip = $(this.input).easytip(); } var $this = this; //是否实时检查 if (!!this.rules && this.options["real-time"]) { this.input.on("blur", function () { $this.validation(true); } ); } return this; }, /** * 规则判断 * */ validation: function (real_time) { this.value = this.input.val(); this.counter_success = 0; //计数器清零 this.counter = 0; this.is_error = false; if (this.input.attr("type") == "radio" || this.input.attr("type") == "checkbox") { var name = this.input.attr("name"); var v = $('input[name="' + name + '"]:checked').val(); if (false == this._null(this, v, this.rules, {"realtime": real_time})) { if (false == this.is_error) { this._success({"realtime": real_time}); } } } else if (false == this._null(this, this.value, this.rules, {"realtime": real_time})) { delete this.rules.null; for (var index in this.rules) { if (index == undefined) { continue; } //调用条件函数 if (!!this.judge[index]) { this.judge[index](this, this.value, this.rules[index], {"realtime": real_time}); } } } }, show: function (msg) { this.tip.show(msg); }, _error: function (rule, option) { this.counter++; if (!!this.error) { this.error(this.input[0], rule); } $(this.input).trigger("easyform-error", [this.input, rule]); if (!option.realtime && !!this.complete && this.counter == Object.keys(this.rules).length) { this.complete(this.input[0]); } if (false == this.is_error) { var msg = $(this.input).data("message-" + rule); if (!msg) { msg = $(this.input).data("message"); } msg = !msg ? "格式错误" : msg; if (true === this.options.easytip) { this.tip.show(msg); } this.is_error = true; } return false; }, _success: function (option) { if (!!this.success) { $(this.input).trigger("easyform-success", [this.input]); this.success(this.input[0]); } if (!option.realtime && !!this.complete) { this.complete(this.input[0]); } return true; }, _success_rule: function (rule, option) { this.counter++; this.counter_success++; $(this.input).trigger("easyform-success-" + rule, [this.input]); if (!option.realtime && this.counter_success == Object.keys(this.rules).length) { this._success(option); } return true; }, _null: function (ei, v, r, o) { if (!v) { //rule不为空并且含有null if (!!r && typeof(r["null"]) != "undefined") { if (false == o.realtime) { return ei._success(o); } else { return true; } } else { return ei._error("null", o); } } //当控件没有规则,或者只有一个null规则 else if (Object.keys(r).length == 0 || (Object.keys(r).length == 1 && typeof(r["null"]) != "undefined")) { if (!o.realtime && !!this.complete) { this.complete(this.input[0]); } if (!!v) { return ei._success(o); } return false; } else { return false; } }, /* * 按照各种rule进行判断的函数数组 * 通过对judge添加成员函数,可以扩充规则 * */ judge: { "char-normal": function (ei, v, p, o) { if (false == /^\w+$/.test(v)) { return ei._error("char-normal", o); } else { return ei._success_rule("char-normal", o); } }, "char-chinese": function (ei, v, p, o) { if (false == /^([\w]|[\u4e00-\u9fa5]|[ 。,、?¥“”‘’!:【】《》()——.,?!$'":+-])+$/.test(v)) { return ei._error("char-chinese", o); } else { return ei._success_rule("char-chinese", o); } }, "char-english": function (ei, v, p, o) { if (false == /^([\w]|[ .,?!$'":+-])+$/.test(v)) { return ei._error("char-english", o); } else { return ei._success_rule("char-english", o); } }, "email": function (ei, v, p, o) { if (false == /^[\w-]+(\.[\w-]+)*@[\w-]+(\.[\w-]+)+$/.test(v)) { return ei._error("email", o); } else { return ei._success_rule("email", o); } }, "mobile": function (ei, v, p, o) { if (false == /^(0|86|17951)?(1)(3[0-9]|4[0-9]|5[0-9]|7[0-9]|8[0-9])[0-9]{8}$/.test(v)) { return ei._error("mobile", o); } else { return ei._success_rule("mobile", o); } }, "length": function (ei, v, p, o) { var range = p.split(" "); //如果长度设置为 length:6 这样的格式 if (range.length == 1) { range[1] = range[0]; } var len = v.replace(/[^\x00-\xff]/g, "aa").length; if (len < range[0] || len > range[1]) { return ei._error("length", o); } else { return ei._success_rule("length", o); } }, "idcard": function (ei, v, p, o) { /* * 身份证15位编码规则:dddddd yymmdd xx p * dddddd:6位地区编码 * yymmdd: 出生年(两位年)月日,如:910215 * xx: 顺序编码,系统产生,无法确定 * p: 性别,奇数为男,偶数为女 * * 身份证18位编码规则:dddddd yyyymmdd xxx y * dddddd:6位地区编码 * yyyymmdd: 出生年(四位年)月日,如:19910215 * xxx:顺序编码,系统产生,无法确定,奇数为男,偶数为女 * y: 校验码,该位数值可通过前17位计算获得 * * 前17位号码加权因子为 Wi = [ 7, 9, 10, 5, 8, 4, 2, 1, 6, 3, 7, 9, 10, 5, 8, 4, 2 ] * 验证位 Y = [ 1, 0, 10, 9, 8, 7, 6, 5, 4, 3, 2 ] * 如果验证码恰好是10,为了保证身份证是十八位,那么第十八位将用X来代替 * 校验位计算公式:Y_P = mod( ∑(Ai×Wi),11 ) * i为身份证号码1...17 位; Y_P为校验码Y所在校验码数组位置 */ //15位和18位身份证号码的正则表达式 var reg = /^(^[1-9]\d{7}((0\d)|(1[0-2]))(([0|1|2]\d)|3[0-1])\d{3}$)|(^[1-9]\d{5}[1-9]\d{3}((0\d)|(1[0-2]))(([0|1|2]\d)|3[0-1])((\d{4})|\d{3}[Xx])$)$/; //如果通过该验证,说明身份证格式正确,但准确性还需计算 if (reg.test(v)) { if (v.length == 18) { var idCardWi = [7, 9, 10, 5, 8, 4, 2, 1, 6, 3, 7, 9, 10, 5, 8, 4, 2]; //将前17位加权因子保存在数组里 var idCardY = [1, 0, 10, 9, 8, 7, 6, 5, 4, 3, 2]; //这是除以11后,可能产生的11位余数、验证码,也保存成数组 var idCardWiSum = 0; //用来保存前17位各自乖以加权因子后的总和 for (var i = 0; i < 17; i++) { idCardWiSum += v.substring(i, i + 1) * idCardWi[i]; } var idCardMod = idCardWiSum % 11;//计算出校验码所在数组的位置 var idCardLast = v.substring(17);//得到最后一位身份证号码 //如果等于2,则说明校验码是10,身份证号码最后一位应该是X if (idCardMod == 2) { if (idCardLast == "X" || idCardLast == "x") { return ei._success_rule("idcard", o); } else { return ei._error("idcard", o); } } else { //用计算出的验证码与最后一位身份证号码匹配,如果一致,说明通过,否则是无效的身份证号码 if (idCardLast == idCardY[idCardMod]) { return ei._success_rule("idcard", o); } else { return ei._error("idcard", o); } } } } else { return ei._error("idcard", o); } }, "equal": function (ei, v, p, o) { var pair = $(p); if (0 == pair.length || pair.val() != v) { return ei._error("equal", o); } else { return ei._success_rule("equal", o); } }, "ajax": function (ei, v, p, o) { // 为ajax处理注册自定义事件 // HTML中执行相关的AJAX时,需要发送事件 easyform-ajax 来通知 easyinput // 该事件只有一个bool参数,easyinput 会根据这个值判断ajax验证是否成功 ei.input.delegate("", "easyform-ajax", function (e, p) { ei.input.unbind("easyform-ajax"); if (false == p) { return ei._error("ajax", o); } else { return ei._success_rule("ajax", o); } } ); eval(p); }, "date": function (ei, v, p, o) { if (false == /^(\d{4})-(\d{2})-(\d{2})$/.test(v)) { return ei._error("date", o); } else { //Modify by Martin 2016/06/13 return ei._success_rule("date", o); //Modify end //return ei._success_rule("date"); } }, "time": function (ei, v, p, o) { if (false == /^(\d{2}):(\d{2}):(\d{2})$/.test(v)) { return ei._error("time", o); } else { return ei._success_rule("time", o); } }, "datetime": function (ei, v, p, o) { if (false == /^(\d{4})-(\d{2})-(\d{2}) (\d{2}):(\d{2}):(\d{2})$/.test(v)) { return ei._error("datetime", o); } else { return ei._success_rule("datetime", o); } }, "money": function (ei, v, p, o) { if (false == /^([1-9][\d]{0,10}|0)(\.[\d]{1,2})?$/.test(v)) { return ei._error("money", o); } else { return ei._success_rule("money", o); } }, "number": function (ei, v, p, o) { if (false == /^\d{1,}$/.test(v)) { return ei._error("number", o); } else { return ei._success_rule("number", o); } }, "float": function (ei, v, p, o) { var range = p.split(" "); //如果长度设置为 float:6 这样的格式 //必须定义整数和小数的位数 if (range.length != 2) { return ei._error("float", o); } else if (range[0] + range[1] > 16) { console.warn("您的" + ei.input.id + "float规则配置可能不正确!请保证整数位数+小数位数 < 16"); } var pattern = new RegExp("^([1-9][\\d]{0," + range[0] + "}|0)(\\.[\\d]{1," + range[1] + "})?$"); if (false == pattern.test(v)) { return ei._error("float", o); } else { return ei._success_rule("float", o); } }, "uint": function (ei, v, p, o) { v = parseInt(v); var range = p.trim().split(" "); if ("" == p.trim()) { console.warn("您的" + ei.input.id + "uint规则,没有设置值域!"); range[0] = 0; } if (range.length == 1) { range[1] = 999999999999999; } range[0] = parseInt(range[0]); range[1] = parseInt(range[1]); if (isNaN(v) || isNaN(range[0]) || isNaN(range[1]) || v < range[0] || v > range[1] || v < 0) { return ei._error("uint", o); } else { return ei._success_rule("uint", o); } }, "regex": function (ei, v, p, o) { var pattern = new RegExp(p); if (false == pattern.test(v)) { return ei._error("regex", o); } else { return ei._success_rule("regex", o); } }, "empty": function (ei, v, p, o) { if (v.length == 0) { return ei._error("empty", o); } else { return ei._success_rule("empty", o); } } }, destructor: function () { //重置事件 this.error = null; this.success = null; //解除实时验证 this.input.off("blur"); delete this; } }; $.fn.easyinput = function (options) { var check = new _easyinput(this, options); return check.init(); }; })(jQuery, window, document); //easytip (function ($, window, document, undefined) { var _easytip = function (ele, opt) { this.parent = ele; this.is_show = false; if (0 == this.parent.length) { throw new Error("easytip's is null !"); } this.defaults = { left: 0, top: 0, position: "right", //top, left, bottom, right disappear: "other", //self, other, lost-focus, none, N seconds, out speed: "fast", class: "easy-white", arrow: "bottom", //top, left, bottom, right 自动,手动配置无效 onshow: null, //事件 onclose: null, //事件 hover_show: "false" //鼠标移动到绑定目标时,是否自动出现 }; this._fun_cache = Object(); //响应函数缓存,用来保存show里面自动添加的click函数,以便于后面的unbind针对性的一个一个删除 //从控件的 data-easytip中读取配置信息 // var data = easy_load_options(ele[0].id, "easytip"); // # by galandeo, fix bug var data = easy_load_options(ele[0], "easytip"); this.options = $.extend({}, this.defaults, opt, data); this.id = "easytip-div-main-" + ele[0].id; }; _easytip.prototype = { init: function () { var tip = $("#" + this.id); var $this = this; //同一个控件不会多次初始化。 if (tip.length == 0) { $(document.body).append("<div class='popover fade in' id=\"" + this.id + "\"><div class=\"popover-content\"></div></div>"); tip = $("#" + this.id); var text = $("#" + this.id + " .popover-content"); tip.css({ "text-align": "left", "display": "none", "position": "absolute", "z-index": 9000 } ); tip.append("<div class=\"arrow\"></div>"); var arrow = $("#" + this.id + " .arrow"); // arrow.css({ // "padding": "0", // "margin": "0", // "width": "0", // "height": "0", // "position": "absolute", // "border": "10px solid" // } // ); if (this.options.hover_show == "true") { this.options.disappear = "none"; this.options.speed = 1; this.parent.hover(function () { $this.show(); }, function () { $this.close(); } ); } } return this; }, _size: function () { var parent = this.parent; var tip = $("#" + this.id); if (tip.width() > 300) { tip.width(300); } }, _css: function () { var tip = $("#" + this.id); var text = $("#" + this.id + " .popover-content"); var arrow = $("#" + this.id + " .arrow"); text.addClass(this.options.class); //arrow.css("border-color", "transparent transparent transparent transparent"); //tip.css("box-sizing", "content-box"); }, _arrow: function () { var tip = $("#" + this.id); var text = $("#" + this.id + " .popover-content"); var arrow = $("#" + this.id + " .arrow"); switch (this.options.arrow) { case "top": arrow.css({ "left": "25px", "top": -arrow.outerHeight(), "border-bottom-color": '#999' } ); break; case "left": arrow.css({ "left": -arrow.outerWidth(), "top":"50%", //"top": tip.innerHeight() / 2 - arrow.outerHeight() / 2 "border-right-color": '#999' } ); break; case "bottom": arrow.css({ "left": "25px", "top": tip.innerHeight(), "border-top-color": '#999' } ); break; case "right": arrow.css({ "left": tip.outerWidth(), "top":"50%", // "top": tip.innerHeight() / 2 - arrow.outerHeight() / 2, "border-left-color": '#999' } ); break; } }, _position: function () { var tip = $("#" + this.id); var text = $("#" + this.id + " .popover-content"); var arrow = $("#" + this.id + " .arrow"); var offset = $(this.parent).offset(); var size = { width: $(this.parent).outerWidth(), height: $(this.parent).outerHeight() }; switch (this.options.position) { case "top": //tip.css("left", offset.left - this.padding); tip.addClass('top'); tip.css("left", offset.left); tip.css("top", offset.top - tip.outerHeight() - arrow.outerHeight() / 2); this.options.arrow = "bottom"; break; case "left": tip.addClass('left'); tip.css("left", offset.left - tip.outerWidth() - arrow.outerWidth() / 2); tip.css("top", offset.top - (tip.outerHeight() - size.height) / 2); this.options.arrow = "right"; break; case "bottom": tip.addClass('bottom'); //tip.css("left", offset.left - this.padding); tip.css("left", offset.left); tip.css("top", offset.top + size.height + arrow.outerHeight() / 2); this.options.arrow = "top"; break; case "right": tip.addClass('right'); tip.css("left", offset.left + size.width + arrow.outerWidth() / 2); tip.css("top", offset.top - (tip.outerHeight() - size.height) / 2); this.options.arrow = "left"; break; } var left = parseInt(tip.css("left")); var top = parseInt(tip.css("top")); tip.css("left", parseInt(this.options.left) + left); tip.css("top", parseInt(this.options.top) + top); }, close: function (fn) { var tip = $("#" + this.id); var parent = this.parent; var onclose = this.options.onclose; this.is_show = false; //onclose事件 if (!!onclose) { onclose(parent, tip[0]); } tip.fadeOut(this.options.speed, fn); }, _show: function () { var tip = $("#" + this.id); var text = $("#" + this.id + " .popover-content"); var arrow = $("#" + this.id + " .arrow"); var speed = this.options.speed; var disappear = this.options.disappear; var parent = this.parent; var $this = this; this.is_show = true; if (this.options.hover_show == "true") { tip.show(); return; } tip.fadeIn(speed, function () { if (!isNaN(disappear)) { //如果disappear是数字,则倒计时disappear毫秒后消失 setTimeout(function () { $this.close(); }, disappear ); } else if (disappear == "self" || disappear == "other") { $(document).bind('click', $this._fun_cache[tip[0].id] = function (e) { if (disappear == "self" && e.target == text[0]) { $this.close(function () { $(document).unbind("click", $this._fun_cache[tip[0].id]); } ); } else if (disappear == "other" && e.target != tip[0]) { $this.close(function () { $(document).unbind("click", $this._fun_cache[tip[0].id]); } ); } } ); } else if (disappear == "lost-focus") { $(parent).focusout(function () { $this.close(function () { $(parent).unbind("focusout"); } ); } ); } } ); }, show: function (msg) { var tip = $("#" + this.id); var text = $("#" + this.id + " .popover-content"); var arrow = $("#" + this.id + " .arrow"); var speed = this.options.speed; var disappear = this.options.disappear; var parent = this.parent; var $this = this; var onshow = this.options.onshow; if (!msg) { msg = parent.data("easytip-message"); } text.html(msg); this._size(); this._css(); this._position(); this._arrow(); if ("none" == tip.css("display")) { //onshow事件 if (!!onshow) { onshow(parent, tip[0]); } $this._show(); } else { tip.hide(1, function () { if (!!onshow) { onshow(parent, tip[0]); } $this._show(); } ); } } }; $.fn.easytip = function (options) { var tip = new _easytip(this, options); return tip.init(); }; })(jQuery, window, document);