跳到正文

【JavaScript高级进阶】实现事件框架的封装及其源代码分享

/** * Created by xiuxiu on 2018/6/16 */ // 框架的本质 /** * 函数:工具 * 对象:工具包 * 框架:多个工具包 */ /* * V1.0:使用原型的方式实现一个框架 * 实现了对象获取,字符串操作,数据类型的检测等功能【extend, queryString, query是核心功能】 * on函数的封装(事件监听,考虑浏览器的兼容性) * V2.0:使用对象的字面量方式来封装一个框架(JSON格式来封装一个框架) * V3.0:使用Extend方式来封装一个框架 * V4.0: 事件框架的封装 * 事件流机制Dom2.0 * on,un,getEvent, getTarget,delegate等方法 * */ // 框架基础代码 var xframe = function () { } /** * 使用原型方式封装框架 * @type {{$id: xframe.$id, $tag: xframe.$tag, ltrim: xframe.ltrim, rtrim: xframe.rtrim, trim: xframe.trim, formateString: xframe.formateString, isNumber: xframe.isNumber, isBoolean: xframe.isBoolean, isString: xframe.isString, isUndefined: xframe.isUndefined, isObject: xframe.isObject, isNull: xframe.isNull, isArray: xframe.isArray, extend: xframe.extend, queryString: xframe.queryString, query: xframe.query, on: xframe.on}} */ xframe.prototype = { // 先写出接口,不用事先事先这个方法 /** * 给一个对象扩充功能:将一个对象的所有属属性拷贝到另外一个对象上去(如果没有的话,就直接把属性添加进去) * // 将一个对象的方法,拷贝给另外一个对象 * @param target * @param source * @returns {*} */ extend: function (target, source) { // 把source对象的所有属性拷贝到target中去 for (var i in source) { target = source; } return target; }, } // 创建一个我的框架对象实例 var $ = new xframe(); //Extend的好处:可以把框架的功能进行模块化, 实现功能的分类管理 /** * 字符串的操作 */ $.extend($, { // 常用的字符串的操作----------------------------------------------------------------------- /** * 去除字符串左边的空格 * @param str */ ltrim: function (str) { return str.replace(/(^\s*)/g, ""); }, /** * 去除字符串右边的空格 * @param str */ rtrim: function (str) { return str.replace(/(\s*$)/g, ""); }, /** * 去除字符串中的空格 * @param str */ trim: function (str) { return str.replace(/(^\s*)|(\s*$)/g, ""); }, /** * 实现一个简单的数据绑定 * @param str * @param data */ formateString: function (str, data) { return str.replace(/@\((\w+)\)/g, function (match, key) { return typeof data === 'undefined' ? '' : data }) }, }) /** * 查询功能的模块化 */ $.extend($, { /** * 查询地址栏的字符串,用于页面间的传参(通过location.search可以获取查询字符串) * @returns {{}} */ queryString: function () { var str = window.location.search.substring(1); // 获取查询字符串,即"id=1&name=location"的部分 var arr = str.split('&'); // 用&分割数组 var json = {}; // 定义一个临时对象 // 遍历数组 for (var i = 0; i < arr.length; i++) { var c = arr.indexOf("="); // 获取每个参数中的等号=小标的位置 if (c == -1) continue // 如果没有发现等号=的位置,则忽略 var d = arr.substring(0, c); // 截取等号前的参数名称 var e = arr.substring(c + 1); // 截取等号后面的位置 json = e; // 用名称 : 值 的格式存储在json对象中 } return json; // 返回json对象【json中存储数据的时候,key必须是唯一的,否则后面的会覆盖掉前面的内容哈】 }, /** * 页面参数的查询(普通查询) * @returns {string} */ query: function () { var params = window.location.search; // 获取 arams : ? id , date…… var arr = params.substring(1).split(','); return arr; }, }) /** * 常用数据类型的检测 */ $.extend($, { // 常用数据类型检测----------------------------------------------------------------------------- /** * 用于检测一个值是不是数字 * 要点:1.js中的==和!= 比较, 若两者类型不同,会先转换类型,再做值比较,最后返回值比较结果(不严格) * 2.===和!=== 只有在相同类型的情况下,才会比较二者的值,否则直接返回false (比较更严格) * @param val * @returns {boolean} */ isNumber: function (val) { // isFinite()函数是js自带函数,会过滤掉NaN和Infinity类型 return typeof val === 'number' && isFinite(val) }, /** * 是不是布尔类型 * @param val * @returns {boolean} */ isBoolean: function (val) { return typeof val === 'boolean'; }, /** * 是不是字符串类型 * @param val * @returns {boolean} */ isString: function (val) { return typeof val === 'string'; }, /** * 是不是未定义类型 * @param val * @returns {boolean} */ isUndefined: function (val) { return typeof val === 'undefined'; }, /** * 是不是Object类型 * @param str * @returns {boolean} */ isObject: function (str) { if (str == null || typeof str === 'undefined') { return false; } return typeof str === 'object'; }, /** * 是否为null * @param val * @returns {boolean} */ isNull: function (val) { return val === null; }, /** * 是否为数组类型 * @param arr * @returns {boolean} */ isArray: function (arr) { if (arr === null || typeof arr === 'undefined') { return false; } // 这里可以通过两种方式来判断 return arr.constructor === Array || arr.prototype.toString.call(arr) === ''; }, }) /** * 事件监听的核心代码 */ $.extend($, { /** * 实现一个兼容各大浏览器的事件监听方法 * @param id 对象的ID * @param type 事件类型:click, mouseover, mouseout…… * @param fn 事件处理的回调函数 */ on: function (id, type, fn) { //var dom = this.$id(id); // 获取这个dom对象 // 这种写法的好处:(三目运算符的使用,增强框架的健壮性) // 1. 可以直接解析DOM节点 // 2. 可以直接把传过来的ID号码转换为DOM节点 var dom = !$.isString(id) ? id : document.getElementById(id); // 如果浏览器支持addEventlistener方法 if (dom.addEventListener) { // W3C dom.addEventListener(type, fn, false); } else { // 微软公司提供的时间监听方法(不支持事件冒泡的方法) if (dom.attachEvent) { // btn.attachEvent('onclick', fn) dom.attachEvent('on' + type, fn); } } }, /** * 用于解除事件的绑定(兼容浏览器)【使用较少】 * @param id * @param type * @param fn */ un : function (id, type, fn) { // 这里先换一种方式来判断 var dom = !$.isString(id) ? id : document.getElementById(id); // 判断浏览器是否兼容某种特效 if (dom.removeEventListener){ // 标准的W3c方式 dom.removeEventListener(type, fn); } else if (dom.attachEvent){ // 微软的解除方式 dom.detachEvent(type, fn); } }, /** * 鼠标点击事件 * @param id * @param fn */ click : function (id, fn) { this.on(id, 'click', fn); }, /** * 鼠标进入事件 * @param id * @param fn */ mouseover : function (id, fn) { this.on(id, 'mouseover', fn); }, /** * 鼠标移出事件 * @param id * @param fn */ mouseout : function (id, fn) { this.on(id, 'mouseout', fn); }, /** * 鼠标移入移出【鼠标悬浮事件】 * @param id * @param fnOver * @param fnOut */ hover : function (id, fnOver, fnOut) { if (fnOver){ this.on(id, 'mouseover', fnOver); } if (fnOut){ this.on(id, 'mouseout', fnOut); } }, /** * 用于获取Event对象(解决了浏览器的兼容性问题) * @param e * @returns {Event} */ getEvent : function (e) { return e ? e : window.event; }, /** * 使用短路表达式来进行代码优化(尽量少用if语句) * @param e * @returns {*|Event | undefined} */ getEvent : function (e) { return e || window.event; }, /** * 获取事件目标对象(兼容性) * @param e * @returns {Element | any} */ getTarget : function (e) { // 获取事件目标 var e = this.getEvent(e); // 使用短路表达式去获取目标 return e.target || e.srcElement; }, /** * 阻止默认事件的行为(兼容性) * @param e */ preventDefault : function (e) { var ev = this.getEvent(e) // 三木表达式阻止默认事件 ev.preventDefault ? ev.preventDefault() : (ev.returnValue = false); }, /** * 阻止事件冒泡(兼容性) * 防止事件向外传播 * @param e */ stopPropagation : function (e) { // 获取事件Event对象,解除事件冒泡 this.getEvent(e).stopPropagation || (this.getEvent(e).cancelBubble = true); }, /** * 使用委托的方式实现事件 * @param pid * @param eventType * @param selector * @param fn */ delegate: function(pid, eventType, selector, fn) { var parent = $.$id(pid); function handle(e) { var target = $.getTarget(e); // 这里会打印输出nodeName console.log(target.nodeName); // tr // select 这里传过来的是一个选择器, selector == 'tr' if (target.nodeName.toLowerCase() === selector || target.id === selector || target.className.indexOf(selector) != -1){ // 使用call修改了this的指向, 去调用fn传过来的函数, 把当前的这个target对象传过去 fn.call(target); } } parent = handle; } }) /** * 选择器的操作 */ $.extend($, { // 根据ID,Tag获取对象------------------------------------------------------------------------- /** * 根据ID获取对象 * @param id * @returns {HTMLElement | null} */ $id: function (id) { return document.getElementById(id) }, /** * 根据tagName获取对象 * @param tag * @returns {any} */ $tag: function (tag) { return document.getElementsByTagName(tag) }, $class : function () { } })

评论

填写昵称与邮箱即可评论,无需登录。

推荐阅读