JavaScript框架风靡一时。有可能你打开的任何与JavaScript相关的新闻源都会引用ReactJS,AngularJS,MeteorRiotJSBackboneJSjQuery等工具。

任何学习编码的人(甚至是经验丰富的开发人员)都会感受到学习这些新工具的巨大压力。炒作创造了需求。如果您不了解需求,可能会感觉您的服务不受欢迎。

我注意到一种趋势,人们在不知道自己做什么的情况下,首先要学习这些工具更不用说他们是如何做的了。这最终使得调试和概念化所述工具异常困难。有数千个误用的情况,其中整个项目仅为双向数据绑定或动画效果创建,甚至只是为了显示图像滑块。

开发人员忽略了学习DOM本身

DOM文档对象模型是Web浏览器的核心和灵魂。你现在正在看它。为了澄清,DOM不是JavaScript的一个特性 - 它甚至不是用JavaScript编写的 - 它是一个编程接口,一个语言和浏览器之间的API。语言控制计算等,浏览器控件显示和事件。

我将在下面演示如何创建一个简单的类jQuery DOM操作库。这将能够使用着名的$ selector,创建新元素,添加html和控制事件绑定来定位元素。

入门

我们需要创建我们的基础对象。我们称之为domElement。此对象将充当要定向的元素的包装。

var domElement = function(selector){ 
this.selector = selector || 空值; //目标选择器
this.element = null; //实际的DOM元素
};

 

现在我们可以开始添加功能了。

我们将复制的jQuery方法是selector / creator $()。on(),. off(),. val(),. append,.prepend()和  .html()

让我们先了解事件绑定。这是迄今为止我们将创建的最复杂的方法以及最有用的方法。这是双向数据绑定模型中的粘合剂。(当触发更新等事件时,模型会更新其订户,订阅者也会这样做。)

我们将使用发布/订阅设计模式

。对(事件,回调)被称为我们订阅的事件和类似的,当  .off(事件)被称为我们取消从事件。 

事件处理程序将是它自己的对象。

让我们首先创建一个基础对象并用它扩展domElement的原型。

domElement.prototype.eventHandler = { 
events:[] //元素订阅的事件和回调数组。
}

好的,现在让我们创建我们的订阅者方法。我们将其称为bindEvent, 因为它将事件侦听器绑定到我们的DOM元素。

domElement.prototype.eventHandler = { 
events:[],//元素订阅的事件数组。
bindEvent:function(event,callback,targetElement){ 
    //删除任何重复的事件
    this.unbindEvent(event,targetElement); 
    
    //将事件监听器绑定到DOM元素
    targetElement.addEventListener(event,callback,false);
    this.events.push({ 
      type:event,
      event:callback,
      target:targetElement 
    }); //将新事件推送到我们的events数组中。
  }
}

而已!让我们快速打破这个功能

  1. 我们删除元素上具有绑定类型的任何现有事件。这纯粹是个人偏好的问题。我更喜欢保留单个事件处理程序,因为它们更易于管理和调试。删除该行将允许多个相同类型的处理程序。稍后我们将创建unbindEvent函数。
  2. 我们将事件绑定到DOM元素,使其生效。
  3. 我们将事件及其所有信息推送到events数组中,以便元素可以跟踪我们的侦听器。

现在,在我们删除事件之前,我们需要一个方法来查找并从events数组中返回它(如果存在的话)。让我们创建一个快速方法,使用内置的数组过滤器方法按类型查找和返回事件。

domElement.prototype.eventHandler = { 
events:[],//元素订阅的事件数组。
bindEvent:function(event,callback,targetElement){ 
    //删除任何重复的事件
    this.unbindEvent(event,targetElement); 
    
    //将事件监听器绑定到DOM元素
    targetElement.addEventListener(event,callback,false);
    this.events.push({ 
      type:event,
      event:callback,
      target:targetElement 
    }); //将新事件推送到我们的events数组中。
  },
  findEvent:function(event){ 
    return this.events.filter(function(evt){ 
      return(evt.type === event); // if event type is match return 
    },event)[0]; 
  } 
}

现在我们可以添加我们的unbindEvent方法。

domElement.prototype.eventHandler = { 
events:[],//元素订阅的事件数组。
bindEvent:function(event,callback,targetElement){ 
    //删除任何重复的事件
    this.unbindEvent(event,targetElement); 
    
    //将事件监听器绑定到DOM元素
    targetElement.addEventListener(event,callback,false);
this.events.push({ 
      type:event,
      event:callback,
      target:targetElement 
    }); //将新事件推送到我们的events数组中。
  },
findEvent:function(event){ 
    return this.events.filter(function(evt){ 
      return(evt.type === event); // if event type is match return 
    },event)[0]; 
  },
unbindEvent:function(event,targetElement){ 
    //搜索事件
    var foundEvent = this.findEvent(event);
    //如果找到
    则删除事件监听器if (foundEvent!== undefined){ 
      targetElement.removeEventListener(event,foundEvent.event,false); 
    }
    //更新事件数组
    this.events = this.events.filter(function(evt){ 
      return(evt.type!== event); 
    },event); 
  } 
};

这就是我们的事件处理程序!在下面尝试一下......

现在这是一个非常有用的小实用程序,但您可能想知道这与jQuery有什么关系,以及为什么事件处理程序的方法没有命名为“on”和“off”。

这就是我们接下来要做的。因为我们要求事件处理程序是一个对象,并且我们不想调用$('element')。eventHandler.on(..)我们的方法将简单地指向正确的函数。

这是onoff方法的代码:

domElement.prototype.on = function(event,callback){ 
   this.eventHandler.bindEvent(event,callback,this.element); 
} 
domElement.prototype.off = function(event){ 
   this.eventHandler.unbindEvent(event,this.element); 
}

看看它是如何工作的?现在让我们添加其他实用功能......

domElement.prototype.val = function(newVal){ 
return(newVal!== undefined?this.element.value = newVal:this.element.value); 
}; 
domElement.prototype.append = function(html){ 
this.element.innerHTML = this.element.innerHTML + html; 
}; 
domElement.prototype.prepend = function(html){ 
this.element.innerHTML = html + this.element.innerHTML; 
}; 
domElement.prototype.html = function(html){ 
if(html === undefined){ 
return this.element.innerHTML; 
} 
this.element.innerHTML = html; 
};

这些都很直接。唯一需要注意的是 .html()。如果在没有参数的情况下调用此方法,则可以以两种方式调用此方法,它将返回元素的innerHTML,但如果使用参数调用它,则会为元素设置HTML。这通常被称为getter / setter函数。

初始化

在初始化时,我们需要做两件事之一......

  1. 如果选择器以开括号'<'开头,我们将创建一个新元素。
  2. 否则,我们将使用document.querySelector来选择现有元素。

为了简单起见,我只是在创建元素的情况下在验证HTML方面做了最低限度,在选择我正在使用document.querySelector的元素时,意味着它只返回一个元素(第一个匹配) )无论匹配量多少。

通过使用document.querySelectorAll并重构方法来处理元素数组,可以在不费力的情况下更改所有匹配元素。

domElement.prototype.init = function(){ 
switch(this.selector [0]){ 
case'<':
// create element 
var matches = this.selector.match(/ <([\ w  - ] *)> / ); 
if(matches === null || matches === undefined){ 
throw'Invalid Selector / Node'; 
返回虚假; 
} 
var nodeName = matches [0] .replace('<','')。replace('>',''); 
this.element = document.createElement(nodeName); 
打破; 
default:
this.element = document.querySelector(this.selector); 
} 
};

让我们来看看上面的代码。

  1. 我们使用switch语句,并将选择器的第一个字符作为参数传递。
  2. 如果以括号开头,我们会进行快速正则表达式匹配,以查找开括号和近括号之间的文本。如果失败,我们抛出选择器无效的错误。
  3. 如果匹配,我们将删除括号并将文本传递给document.createElement以创建新元素。
  4. 或者,我们使用document.querySelector查找匹配项,如果找不到匹配项,则返回null。
  5. 最后,我们将domElement上的element属性设置为匹配/创建的元素。

使用$引用domElement

最后,我们将分配$符号来初始化一个新的domElement

$ = function(selector){ 
var el = new domElement(selector); // new domElement 
el.init(); //初始化domElement 
return el; //返回domELement 
}

$符号仅仅是一个变量!这是我们完成的类似jQuery的库,以及71行可读,间隔良好的代码。

这是一支运行完整库的笔...使用你的控制台。

接下来做什么?

  1. 为什么不尝试复制您喜欢的实用功能?
  2. 深入了解DOM
  3. 使用事件侦听器绑定双向数据。

重要笔记

此代码是作为一个简单示例编写的,用于说明JavaScript库如何与DOM交互并修改DOM。应该这样对待。

我使用简单明了的语句来帮助读者理解和遵循这些例子,并轻易绕过 - 或完全忽略 - 失败和验证的点。

返回的元素只会将创建的方法绑定到包装器。您可以通过调用$('selector')。element来访问实际的DOM元素及其方法这是为了避免扩展DOM,这是一个需要自己发帖的敏感话题。

如果您正确执行了这些步骤,则应该有一个完整的文件,如下所示:

var domElement = function(selector){ 
this.selector = selector || 空值; 
this.element = null; 
}; 
domElement.prototype.init = function(){ 
switch(this.selector [0]){ 
case'<':
var matches = this.selector.match(/ <([\ w  - ] *)> /); 
if(matches === null || matches === undefined){ 
throw'Invalid Selector / Node'; 
返回虚假; 
} 
var nodeName = matches [0] .replace('<','')。renplace('>',''); 
this.element = document.createElement(nodeName); 
打破; 
default:
this.element = document.querySelector(this.selector); 
} 
}; 
domElement.prototype.on = function(event,callback){
var evt = this.eventHandler.bindEvent(event,callback,this.element); 
} 
domElement.prototype.off = function(event){ 
var evt = this.eventHandler.unbindEvent(event,this.element); 
} 
domElement.prototype.val = function(newVal){ 
return(newVal!== undefined?this.element.value = newVal:this.element.value); 
}; 
domElement.prototype.append = function(html){ 
this.element.innerHTML = this.element.innerHTML + html; 
}; 
domElement.prototype.prepend = function(html){ 
this.element.innerHTML = html + this.element.innerHTML; 
}; 
domElement.prototype.html = function(html){ 
if(html === undefined){ 
return this.element.innerHTML; 
}
this.element.innerHTML = html; 
}; 
domElement.prototype.eventHandler = { 
events:[],
bindEvent:function(event,callback,targetElement){ 
this.unbindEvent(event,targetElement); 
targetElement.addEventListener(event,callback,false); 
this.events.push({ 
type:event,
event:callback,
target:targetElement 
}); 
},
findEvent:function(event){ 
return this.events.filter(function(evt){ 
return(evt.type === event); 
},event)[0]; 
},
unbindEvent:function(event,targetElement){ 
var foundEvent = this.findEvent(event); 
if(foundEvent!== undefined){
targetElement.removeEventListener(event,foundEvent.event,false); 
} 
this.events = this.events.filter(function(evt){ 
return(evt.type!== event); 
},event); 
} 
}; 
$ = function(selector){ 
var el = new domElement(selector); 
el.init(); 
返回; 
}

希望这篇文章很有帮助!如果你喜欢它,请给我一些鼓掌,让更多的人看到它。谢谢!

觉得可用,就经常来吧!jQuery教程 脚本宝典 欢迎评论哦!巧夺天工,精雕玉琢。小宝典献丑了!