最近在看《javascript dom 高级程序设计》,想着跟着里面的代码敲一遍吧,也算是做一下学习笔记吧,所以这不是重新发明轮子,只是个学习的过程。

1.先确定自己的命名空间,并且加入几个常用的js方法。命名空间很重要啊,保证了自己库里的变量不污染全局空间,不和其他的库的变量名起冲突。命名空间的惯例就是把代码都放在自执行函数(function(){})()里了,然后暴露个方法给window对象了。所以0.1版本的代码就长下面这样了。(这里暂时没有用继承)

  1. function(){
  2. //命名空间
  3. var Lily = {}
  4. if(!window.Lily){
  5. window['Lily'] = Lily
  6. }
  7.  
  8. function isCompatible(other){}
  9. Lily['isCompatible'] = isCompatible;
  10.  
  11. function $(){}
  12. Lily['$'] = $;
  13.  
  14. function addEvent(node, type, listener){}
  15. Lily['addEvent'] = addEvent;
  16.  
  17. function removeEvent(node, type, listener){}
  18. Lily['removeEvent'] = removeEvent;
  19.  
  20. function getElementsByClassName(className, tag, parent){}
  21. Lily['getElementsByClassName'] = getElementsByClassName;
  22.  
  23. function toggleDisplay(node, value){}
  24. Lily['toggleDisplay'] = toggleDisplay;
  25.  
  26. function insertAfter(node, referenceNode){}
  27. Lily['insertAfter'] = insertAfter;
  28.  
  29. function removeChildren(parent){}
  30. Lily['removeChildren'] = removeChildren;
  31.  
  32. function prependChild(parent, newChild){}
  33. Lily['prependChild'] = prependChild;
  34.  
  35. })()

2.开始填充方法了。isCompatible是看浏览器是否能与这个库兼容,这里用能力检测来看浏览器是否能支持库中所使用的方法。

  1. function isCompatible(other){
  2. if(other === false
  3. || !Array.prototype.push
  4. || !Object.hasOwnProperty
  5. || !document.createElment
  6. || !document.getElementsByTagName
  7. ){
  8. return false;
  9. }
  10. return true;
  11. }

3.$是查找dom对象的方法,这个要比jquery的$方法简单许多,只支持代表id的字符串或字符串数组,或者dom对象。支持dom对象是方便库中的方法,当参数为字符串或者dom都可以用$转成dom对象。

  1. function $(){
  2. var elements = new Array();
  3.  
  4. for(var i = 0; i < arguments.length; i++){
  5. var element = arguments[i];
  6.  
  7. if(typeof element == "string"){
  8. element = document.getElementById(element);
  9. }
  10.  
  11. if(arguments.length == 1){
  12. return element;
  13. }
  14. elements.push(element);
  15. }
  16.  
  17. return elements;
  18. }

4.addEvent是支持跨浏览器必须实现的一个方法,ie的事件绑定方法是attachEvent,并且它的方法参数中没有event对象,所以手动将window.event传入到listener中。之前有点困惑为什么没有用匿名函数绑定,查了下用匿名函数的话,就无法解除绑定了。ie6,7,8中用attachEvent绑定的事件中,this指向的是window,所以用node.call修正了this的指向问题。addEventListener的第三个参数指是否使用捕获,默认值是false,而且ie6,7,8中只支持冒泡,所以一般都用false。关于addEvent有个更周全的版本就是Dean Edwards的,jquery中也参考了他的很多方法,目前为了保持简单,先用这个,以后可能会替换成Dean Edwards版本的。

  1. function addEvent(node, type, listener){
  2. if(!isCompatible()) return false;
  3. if(!(node = $(node))) return false;
  4.  
  5. if(node.addEventListener){
  6. node.addEventListener(type, listener, false);
  7. return true;
  8. }else if(node.attachEvent){
  9. node[type + listener] = function(){
  10. listener.call(node, window.event);
  11. };
  12. node.attachEvent('on'+type, node[type + listener]);
  13. return true;
  14. }
  15. return false;
  16. }

5.removeEvent就没什么好说的了,就是detach之后,别忘了把node[type + listener]释放掉。

  1. function removeEvent(node, type, listener){
  2. if(!(node = $(node))) return false;
  3. if(node.removeEventListener){
  4. node.removeEventListener(type, listener, false);
  5. return true;
  6. }else if(node.detachEvent){
  7. node.detachEvent('on'+type, node[type + listener]);
  8. node[type + listener] = null;
  9. return true;
  10. }
  11. return false;
  12. }

6.getElementsByClassName根据class选择dom对象,后两个参数可以不传。parent.all貌似是解决ie5的bug吧,没有细研究,总之满足条件就用document.all吧。正则表达式(^|\\s+)匹配起始位置或者空格。

  1. function getElementsByClassName(className, tag, parent){
  2. var elements = new Array();
  3. parent = parent || document;
  4. tag = tag || "*";
  5. if(!(parent = $(parent))) return false;
  6.  
  7. var allTags = (tag == "*" && parent.all) ? parent.all : parent.getElementsByTagName(tag);
  8. className = className.replace(/\-/g, "\\-");
  9. var regexp = new RegExp("(^|\\s+)" + className + "(\\s+|$)");
  10.  
  11. for(var i = 0; i < allTags.length; i++){
  12. var element = allTags[i];
  13. if(regexp.test(element.className)){
  14. elements.push(element);
  15. }
  16. }
  17.  
  18. return elements;
  19. }

7.toggleDisplay第二个参数也可以不传,但是当元素的display不是空值时(比如display:inline-block),可以传入第二个参数,这样在切换时就保留了原来的值。

  1. function toggleDisplay(node, value){
  2. if(!(node = $(node))) return false;
  3.  
  4. if(node.style.display != "none"){
  5. node.style.display = "none"
  6. }else{
  7. node.style.display = value || '';
  8. }
  9.  
  10. return true;
  11. }

8.insertAfter在referenceNode后插入元素。

  1. function insertAfter(node, referenceNode){
  2. if(!(node = $(node))) return false;
  3. if(!(referenceNode = $(node))) return false;
  4.  
  5. return referenceNode.parentNode.insertBefore(node, referenceNode.nextSibling);
  6. }

9.removeChildren删除所以子节点。

  1. function removeChildren(parent){
  2. if(!(parent = $(parent))) return false;
  3. while(parent.firstChild){
  4. parent.firstChild.parentNode.removeChild(parent.firstChild);
  5. }
  6. return parent;
  7. }

10.prependChild将子节点加入到父节点中的第一个。

  1. function prependChild(parent, newChild){
  2. if(!(parent = $(parent))) return false;
  3. if(!(newChild = $(newChild))) return false;
  4.  
  5. if(parent.firstChild){
  6. parent.insertBefore(newChild, parent.firstChild);
  7. }else{
  8. parent.appendChild(newChild);
  9. }
  10.  
  11. return parent;
  12. }

现在一个简单的框架就搭完了,用下面的代码测试一下啊。以下是改写a标签的默认事件,用弹出事件代替跳转事件。

  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4. <meta charset="UTF-8">
  5. <title>Document</title>
  6. <script src="Lily-0.1.js" type="text/javascript"></script>
  7. <script type="text/javascript">
  8. Lily.addEvent(window, "load", function(){
  9. var aTags = Lily.getElementsByClassName("popup");
  10. for(var i = 0 ; i < aTags.length; i++){
  11. Lily.addEvent(aTags[i], "click", function(){
  12. alert(this.href);
  13. return false;
  14. });
  15. }
  16. });
  17. </script>
  18. </head>
  19. <body>
  20. <ul>
  21. <li><a href="hello.html" class="popup">hello</a></li>
  22. <li><a href="hello.html" class="popup">hello</a></li>
  23. <li><a href="hello.html" class="popup">hello</a></li>
  24. </ul>
  25. </body>
  26. </html>

还未进行浏览器兼容性测试,如有问题,请指正,谢谢~

【写一个自己的js库】 1.搭个架子先的更多相关文章

  1. 【写一个自己的js库】 2.实现自己的调试日志

    还是本着学习的目的,实现一个自己的调试日志,界面很简单,就是将调试信息显示在页面的正中央,用一个ul包裹,每条信息就是一个li. 1.新建一个myLogger.js文件,将需要的方法声明一下.其中va ...

  2. 【写一个自己的js库】 5.添加修改样式的方法

    1.根据id或class或tag修改样式,样式名是-连接格式的. function setStyleById(elem, styles){ if(!(elem = $(elem)) return fa ...

  3. 【写一个自己的js库】 3.添加几个处理字符串的方法

    1.生成重复的字符串 if(!String.repeat){ String.prototype.repeat = function (count){ return new Array(count + ...

  4. 【写一个自己的js库】 4.完善跨浏览器事件操作

    1.阻止冒泡. function stopPropagation(event){ event = event || getEvent(event); if(event.stopPropagation) ...

  5. 仿照jquery封装一个自己的js库(二)

    本篇为完结篇.主要讲述如何造出轮子的高级特性. 一. css方法的高级操作 先看本文第一部分所讲的dQuery css方法 //css方法 dQuery.prototype.css=function( ...

  6. 仿照jquery封装一个自己的js库(一)

    所谓造轮子的好处就是复习知识点,加深对原版jquery的理解. 本文系笔者学习jquery的笔记,记述一个名为"dQuery"的初级版和缩水版jquery库的实现.主要涉及知识点包 ...

  7. 仿照jquery封装一个自己的js库

    所谓造轮子的好处就是复习知识点,加深对原版jquery的理解.本文系笔者学习jquery的笔记,记述一个名为"dQuery"的初级版和缩水版jquery库的实现.主要涉及知识点包括 ...

  8. 自己动手写一个iOS 网络请求库的三部曲[转]

    代码示例:https://github.com/johnlui/Swift-On-iOS/blob/master/BuildYourHTTPRequestLibrary 开源项目:Pitaya,适合大 ...

  9. 如何写一个自定义的js文件

    自定义一个Utils.js文件,在其中写js代码即可.如: (function(w){ function Utils(){} Utils.prototype.getChilds = function( ...

随机推荐

  1. AngularJS如何使用ngRepeat过滤排序

    NG重复指令,带过滤器,像这样: <li ng-repeat="item in items | orderBy:'order_prop' | filter:query | limitT ...

  2. PHP header() http各种状态码大全查询

    PHP header()the function declaration: void header ( string string [, bool replace [, int http_respon ...

  3. 运算符 - PHP手册笔记

    运算符优先级 每种编程语言都有运算符,运算符要学会灵活使用. 运算符拥有不同的优先级和结合方向. <?php var_dump(1 <= 1 == 1); // true var_dump ...

  4. 过河问题--nyoj题目47

    过河问题 时间限制:1000 ms  |  内存限制:65535 KB 难度:5   描述 在漆黑的夜里,N位旅行者来到了一座狭窄而且没有护栏的桥边.如果不借助手电筒的话,大家是无论如何也不敢过桥去的 ...

  5. HDU 4121 Xiangqi

    模拟吧,算是... 被这个题wa到哭,真是什么都不想说了...上代码 #include <iostream> #include <cstring> using namespac ...

  6. TensorFlow深度学习笔记 循环神经网络实践

    转载请注明作者:梦里风林 Github工程地址:https://github.com/ahangchen/GDLnotes 欢迎star,有问题可以到Issue区讨论 官方教程地址 视频/字幕下载 加 ...

  7. [Leetcode][Python]44:Wildcard Matching

    # -*- coding: utf8 -*-'''__author__ = 'dabay.wang@gmail.com' 44:Wildcard Matchinghttps://oj.leetcode ...

  8. linux的7种运行级别<学习笔记>

    Linux系统有7个运行级别(runlevel) 运行级别0:系统停机状态,系统默认运行级别不能设为0,否则不能正常启动 运行级别1:单用户工作状态,root权限,用于系统维护,禁止远程登陆 运行级别 ...

  9. MongoDB C driver API continues

    开篇前 <1,mongoc_init() func> mongoc_init() Synopsis void mongoc_init (void); Description This fu ...

  10. Redmine backlogs 安装

    之前我们一直用IceScrum的免费版本来运作Scrum项目,用GitLab来做做Issue管理,但是出现了一些问题.GitLab的issue不够好用,不能满足我们的需求,同时issue没有办法放在S ...