最新公告
  • 欢迎您光临起源地模板网,本站秉承服务宗旨 履行“站长”责任,销售只是起点 服务永无止境!立即加入钻石VIP
  • 手写DOM库

    正文概述 掘金(饥人谷一言)   2021-02-06   434

    你可以看到

    什么叫封装

    对象风格的-增

    -删

    -改

    -查

    要说的话

       本文从代码、本不应该的大量小白(我)也能看懂的注释和示例结果图来看懂DOM封装。

    --资料来源于饥人谷

    源码所在地

    github.com/woshidw/dom…

    什么叫封装

       可以理解为把一个复杂的东西打包成一个服务,只需要用一些简单的命令就可以操作它。

    • 举例

       电脑笔记本就是CPU、内存、硬盘、主板、显卡的封装,用户只需要接触显示器、键盘、鼠标、触控板等设备即可操作复杂的计算机。

    • 接口

       被封装的东西需要暴露一些功能给外部,这些功能就是接口,如USB接口、HDMI接口。设备只要支持这些接口,即可与被封装的东西通讯,比如键盘、鼠标支持USB接口;显示器支持HDMI接口

    两图对应

    手写DOM库

    手写DOM库

    一些术语

       我们把提供给其他人用的工具代码叫做库

       比如jQuery、Underscore

    • API

       库暴露出来的函数或属性叫做API(应用编程接口,英文Application Programming Interface)

    • 框架

       当你的库变得很大,并且需要学习才能看懂,那么这个库就叫框架,比如Vue / React

    • 注意

       编程界的术语大部分都很随便,没有固定的解释,所以意会即可

    用对象风格封装DOM操作

    • 也叫命名空间风格。

       window.dom是我们提供的全局对象。在html里先添加  

        <script src="dom.js"></script>
        <script src="main.js"></script>
    

    1. dom.create(`<div>hi</div>`) 用于创建节点。
      • 创建一个标签节点

    在创建的dom.js文件里封装DOM编程里的增方法

    window.dom = {
        create (tagName){
            return document.createElement(tagName);
            //封装创建一个标签节点。用DOM编程里增方法,创建这个元素,然后把元素(标签名)return回去
        }
    };
    //window.dom等于一个空对象 
    
    

    main.js里进行调用代码

    //没封装之前就是document.createElement('div')
    let div = dom.create("div");
    console.log(div);
    //在main.js这里调用刚刚封装的创建标签元素 create(tagName)
    

    调用结果 手写DOM库

      • 创建任意元素

      dom.js

    window.dom = {
        create (string){
            const container = document.createElement("template");//template是专门用来容纳所有元素的,不会显示到页面
            container.innerHTML = string.trim();//trim()去掉空格。把字符串变成容器里的内容
            return container.content.firstChild;//用template元素不能通过children拿到
            //把一段html写到标签里,这段html自动变成了html元素
        },
    };
    

    main.js

    //没封装之前就是document.createElement('div')
    const div = dom.create("    <tr><td>hi</td><tr>");
    console.log(div);
    

    结果

    手写DOM库

    1. dom.after(node, node2)用于新增弟弟

       html里加一个id为test,内容为test的div。在test元素后再新增一个元素

    dom.js

        //新增弟弟
        //在node节点后新加node2。
        //没有insertAfter,只有insertBefore.
        //下一节点为空,依然可以插入进来。
        after(node, node2){
            console.log(node.nextSibling);//可以看下一节点是什么
            node.parentNode.insertBefore(node2, node.nextSibling);
           //找到node节点的爸爸,然后调用爸爸的insertBefore方法,把node2插到node下一个节点的前面。
        }
    
    

    main.js调用

    //没封装之前就是document.createElement('div')
    const div = dom.create("<div>newDiv</div>");
    console.log(div);
    
    dom.after(test, div);//把1.创建节点创建的div插入到test元素后面
    

    可以看到插入成功了

    手写DOM库

    1. dom.before(node, node2)用于新增哥哥

       dom.js封装insertBefore

        //新增哥哥
        before(node,node2){
            node.parentNode.insertBefore(node2, node);//node支持的一个接口
        }
        
    
    1. dom.append(parent, child)用于新增儿子

    dom.js

        //新增儿子
        append(parent , node){
            parent.appendChild(node);//直接用appendChild
        }
    
    1. dom.wrap(`<div></div>`)用于新增爸爸

    dom.js

        //新增爸爸
        //在一个节点外面,加一个爸爸。
        wrap(node, parent){
            before(node,parent)
            append(parent,node)
        }
    

    用图来说明关系

       现有div1和儿子div2,现在需要把div3插入两者之间。用封装的dom.wrap(div2,div3),先用dom.before(div2,div3)把div3放到div2前面,两者是兄弟关系,然后用dom.append(div3,div2),把div2append成div3的儿子(append如果插入别的地方,就会在原来的地方移开) 手写DOM库

    main.js

    const div3 = dom.create('<div id="parent"></div>');
    dom.wrap(test,div3);//给test新增一个爸爸div3
    

    成功

    手写DOM库


    • dom.remove(node)用于删除节点

    dom.js

        remove(node){//用跟古老的接口
            //用这个节点的爸爸从树中删除这个儿子节点。
            node.parentNode.removeChild(node)
            return node//还能保留节点的引用,方便操作
        },
    
    • dom.empty parent)用于删除后代

    在html中添加empty元素

        <div id="empty">
          <div id="e1"></div>
          <div id="e2"></div>
          <div id="e3"></div>
        </div>
    

    dom.js

        //删除所有后代
        empty(node){//干掉这个节点的所有儿子,不能出现在树里面。可以调用儿子一个个删
            //node.innerHTML = ''//可以删,但获取不到节点的引用
            const {childNodes} = node//const childNodes = code.childNodes。从node获取到它的childNodes
            const array = []
            let x = node.firstChild
            while(x){//当x存在就把它移除并放到数组里
                array.push(dom.remove(node.firstChild))//dom.remove移除会返回node节点,这直接push掉
                x = node.firstChild  
                //然后把x指向firstChild,上面已经移除了第一个节点,这里firstChild相当于第二个节点
            } 
            return array
        },
    

    main.js中打印出删掉的后代

    const nodes = dom.empty(window.empty)//找到html中empty元素,删掉,然后把它所有儿子都弄出来
    console.log(nodes)//然后打印出所有儿子
    

    移除的东西

    手写DOM库


    1. dom.attr(node, 'title',?)用于读写属性。(attr是attribute的缩写)

    dom.js

       attr(node, name, value){ //重载,根据参数个数写不同的代码
           if(arguments.length === 3){
               //如果参数长度为3,就设置它的属性名和值。写操作
               node.setAttribute(name, value)
           }else if(arguments.length === 2){
               //如果参数长度为2,就相当于读,就返回。读操作
               return node.getAttribute(name)
           }
       },
    

    main.js

    dom.attr(test, 'title', 'Hi, I am dw')//参数长度为3,设置。写
    const title = dom.attr(test, 'title')//参数长度为2,读。获取test元素的title属性,并赋给变量title。读
    console.log(`title: ${title}`)//title值为title
    

    读写结果 手写DOM库

    手写DOM库

    1. dom.text(node,?)用于读写文本内容

    改文本内容 dom.js

      //适配
      text(node, string) {
        //给节点,告诉新传的文本是什么
        if (arguments.length === 2) {
          if ("innerText" in node) {
            node.innerText = string; //IE
          } else {
            node.textContent = string; //Chrome,Firefox等等。
            //但两种方式浏览器都支持,如果想所以浏览器都支持可以用innerText
          }
        } else if (arguments.length === 1) {
          if ("innerText" in node) {
            return node.innerText;
          } else {
            return node.textContent;
          }
        }
      },
    

    main.js。选择改不同内容,可以加个span再改

    dom.text(test, '你好,这是新的内容')
    

    结果

    手写DOM库

    1. dom.html(node,?)用于读写HTML内容

    dom.js

      html(node, string){
          if(arguments.length === 2){
              node.innerHTML = string
          }else if(arguments.length === 1){
              return node.innerHTML
          }
      },
    
    1. dom.style(node, {color: 'red'})用于修改style

    dom.js

      style(node, name, value) {
        if (arguments.length === 3) {
          //如dom.style(div, 'color' , 'red')
          node.style[name] = value;
        } else if (arguments.length === 2) {
          if (typeof name === "string") {
            //如dom.style(div, 'color')
            return node.style[name];
          } else if (name instanceof Object) {
            //dom.style(div,{color: 'red'})
            const object = name;
            for (let key in object) {
              //key: border /color 这个key是个变量,比如可能是border或者color
              //正常代码
              //node.style.border = ...
              //node.style.color = ...
              node.style[key] = object[key]; //不能用.key(这会变成一个字符串)。变量做key的话要用[]
            }
          }
        }
      },
    

       main.js

    dom.style(test,{border: '1px solid red', color: 'blue'})//有一个test节点,里面有属性名,后面是属性值
    console.log(dom.style(test, 'border'))//读。第二个参数可能是对象也可能是字符串。如果是对象就是设置,是字符串就是读
    dom.style(test, 'border', '1px solid black')//也可以三个参数读
    

    手写DOM库

    手写DOM库

    1. dom.class.add(node, 'blue')用于添加class

       dom.js

      class:{
          add(node, className){
              node.classList.add(className)
          },
        }
    

       在html里添加一个red类,比如

          .red{
            background: red;
          }
    

       main.js

    dom.class.add(test, 'red')//在test元素上添加一个类名red
    

    最后添加成功

    手写DOM库

    手写DOM库

    1. dom.class.remove(node, 'blue')用于删除class

    dom.js

     class:{
          remove(node,className){
            node.classList.remove(className)
          },
        }
    

    main.js

    dom.class.remove(test, 'red')//又删除了red类
    

    手写DOM库

    1. dom.class.has(node, className)用于知道node元素有没有指定的className

    dom.js

    class:{
            //要知道node节点元素有没有指定的className
            has(node, className){
              return node.classList.contains(className)
            }
          },
    

    main.js

    console.log(dom.class.has(test,'red'))//检查test元素里有没有red类名
    
    1. dom.on(node, 'click', fn)用于添加事件监听

    dom.js

      on(node, eventName, fn){//告诉节点,事件名,事件处理函数
        node.addEventListener(eventName, fn)
      },
      
    

    main.js

    const fn = ()=>{  
        console.log('点击了')
    }
    dom.on(test, 'click', fn)//点击test这个div,执行打印
    

    手写DOM库

    1. dom.off(node, 'click', fn)用于删除事件监听

    html里添加

        <div>
          <div id="test"><span>test1</span>
            <p class="red">段落标签3</p>test2
          </div>
          <div id="test2">
            <p class="red">段落标签3</p>test2
          </div>
        </div>
    

    dom.js

      //移除这个监听
      off(node, eventName, fn){
        node.removeEventListener(eventName, fn)
      }
    

    main.js

    dom.off(test, 'click' , fn)//移除监听
    

    1. dom.find('选择器')用于获取标签或标签们

    dom.js

      find(selector, scope){//给我一个选择器,在范围里进行查找,返回对应元素
        return (scope || document).querySelectorAll(selector)
        //如果有范围scope,则在scope里调用querySelector,如果没有scope则在document里调用
      },
    

    main.js

    const testDiv = dom.find('#test')[0]//找到id为test的元素,获取第0个
    console.log(testDiv)//没有范围
    
    const test2 = dom.find('#test2')[0]
    console.log(dom.find('.red', test2)[0])//两个参数,指定在找的范围是什么(默认是在document找)
    
    

    打印出了

    手写DOM库

    1. dom.parent(node)用于获取父元素

    dom.js

      parent(node){
        return node.parentNode
      },
    
    1. dom.children(node)用于获取子元素

    dom.js

      children(node){
        return node.children
      },
    
    1. dom.siblings(node)用于获取兄弟姐妹元素

    html 在html里添加

        <div id="siblings">
          <div id="s1"></div>
          <div id="s2"></div>
          <div id="s3"></div>
        </div>
    

    dom.js

      siblings(node){//返回节点的兄弟姐妹(兄弟姐妹不能包括自己)
        //children是伪数组,要变成数组才可以用filter
        return Array.from(node.parentNode.children)
        .filter(n=>n!==node)//在伪数组编程数组后对它进行过滤,只要这个元素不等于当前这个节点就把它放到数组里
    
      },
    

    main.js

    console.log(dom.siblings(dom.find('#s2')[0]))//找到e2,再获取它的兄弟节点
    

    获取到兄弟姐妹 手写DOM库

    1. dom.next(node)用于获取弟弟,nodeType MDN

    dom.js

      next(node){
        let x = node.nextSibling
        while(x && x.nodeType === 3){//看如果是文本,是就下一个。。,如果下一个节点不是就返回
          x = x.nextSibling
        }
        return x
      },
    

    main.js

    const s2 = dom.find('#s2')[0]
    console.log(dom.siblings(s2))
    console.log(dom.next(s2))
    

    手写DOM库

    1. dom.previous(node)用于获取哥哥

    dom.js

      previous(node) {
        let x = node.previousSiblings;
        while (x && x.nodeType === 3) {
          //看如果是文本,是再往前。。,如果不是就返回
          x = x.previousSiblings;
        }
        return x;
      },
    
    1. dom.each(nodes, fn)用于遍历所有节点

    在html里添加

        <div id="travel">
          <div id="t1">t1</div>
          <div id="t2">t2</div>
          <div id="t3">t3</div>
        </div>
    

    dom.js

      each(nodeList, fn) {//给我一个节点列表,函数
        for (let i = 0; i < nodeList.length; i++) {
          fn.call(null, nodeList[i]);
        }
      },
    

    main.js

    const t = dom.find('#travel')[0]//find返回的是一个数组,找到第一个元素
    dom.each(dom.children(t),(n)=>dom.style(n, 'color' ,'red'))
    //遍历它的子元素,对子元素进行一个each操作,每一个用n站位,n的color为red
    

    手写DOM库

    1. dom.index(node)用于获取排行老几

    dom.js

      index(node){
        const list = dom.children(node.parentNode)//用list获取到爸爸的儿子
        let i
        for(i=0;i<list.length;i++){ 
          if(list[i] === node){//每一个与它作对比,看list(i)是否等于node,如果等于就是第i+1个
            break
          }
        }
        return i
      }
    

    main.js

    console.log(dom.index(s2))
    

    从0开始,为第二个

    手写DOM库


    --continue


    起源地下载网 » 手写DOM库

    常见问题FAQ

    免费下载或者VIP会员专享资源能否直接商用?
    本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
    提示下载完但解压或打开不了?
    最常见的情况是下载不完整: 可对比下载完压缩包的与网盘上的容量,若小于网盘提示的容量则是这个原因。这是浏览器下载的bug,建议用百度网盘软件或迅雷下载。若排除这种情况,可在对应资源底部留言,或 联络我们.。
    找不到素材资源介绍文章里的示例图片?
    对于PPT,KEY,Mockups,APP,网页模版等类型的素材,文章内用于介绍的图片通常并不包含在对应可供下载素材包内。这些相关商业图片需另外购买,且本站不负责(也没有办法)找到出处。 同样地一些字体文件也是这种情况,但部分素材会在素材包内有一份字体下载链接清单。
    模板不会安装或需要功能定制以及二次开发?
    请QQ联系我们

    发表评论

    还没有评论,快来抢沙发吧!

    如需帝国cms功能定制以及二次开发请联系我们

    联系作者

    请选择支付方式

    ×
    迅虎支付宝
    迅虎微信
    支付宝当面付
    余额支付
    ×
    微信扫码支付 0 元