手写一个DOM库

手写一个DOM库

原生DOM接口不太好用,所以今天自己来封装一个DOM库
源代码链接:https://gitee.com/kilok/dom-by-hand

提供一个全局的window.dom对象
接下来对“增删改查”进行说明

一、增加元素、节点

dom.create(string)创建节点

原生api需要用createElement(‘div’),div.innerText = 'hello’这两句话

create(string){
        const container = document.createElement('template')
        container.innerHTML = String.prototype.trim.call(string)//去除多余空格
        // console.log(container.content)
        return container.content.firstChild
    },

封装后只需dom.create(’<div>‘hello’</div>’)

after(node,newNode)新增弟弟节点

DOM只提供insertBefore接口,故在node.nextSibling前插入

after(node,newNode){
	return node.parentNode.insertBefore(newNode,node.nextSibling)
}

before(node,newNode)新增哥哥节点

before(node,newNode){
	return node.parentNode.insertBefore(newNode,node)
}

append(parent,node)新增儿子节点

append(parent,node){
	return parent.appendChildren(node)
}

wrap(node,newParent) 用于新增爸爸节点

思路:

  1. 将newparent放到node前
  2. 再将node append到newParent里
wrap(node,newParent){
	node.before.call(node,newParent)
	newParent.append(node)
}

二、删除元素、节点

remove(node)删除节点

remove(node){
	node.parentNode.removeChild(node)
	return node
}

empty(node)删除后代

只要有子节点就不断遍历

empty(node){
	const array = []
	let x = node.firstChild
	while(x){
	array.push(dom.remove(node.firstChild))
	x = node.firstChild
}
}

三、修改、读取属性和文本内容

attr(node,name,value)读写属性

重载:函数名相同,参数类型/数量不同做不一样的处理
当只有两个参数时,就读属性,返回属性
当有三个参数时,就修改属性
这里由于同时可以读写属性,用到了getter和setter设计模式

 attr(node,name,value){
        if(arguments.length === 3){
            node.setAttribute(name,value)
        }else if(arguments.length === 2){
            return node.getAttribute(name)
        }
    }

text(node,string)读写文本内容

text(node,string){
        if(arguments.length === 1){ //读
            if('innerText' in node){//IE
                return node.innerText
            }else{
                return   node.textContent //firefox or chrome
            }
        }else if(arguments.length ===2){ //写
            if('innerText' in node){//IE
                 node.innerText = string
            }else{
                   node.textContent = string //firefox or chrome
            }
        }
    },

html(node,string)读写html内容

html(node,string){
        if(arguments.length ===1 ) {
            return node.innerHTML
        }else if(arguments.length ===2 ){
            node.innerHTML = string
        }
    },

style(node,name,value)修改读取style

大体思路:node.style.color = ‘red’
有三种情况

  1. dom.style(node,‘color’)读取color属性

  2. dom.style(node,‘color’,‘red’)设置color

  3. dom.style(node,{‘color’:‘red’,‘border’:‘1px solid blue’}设置多个style属性
    使用适配器模式

  4. 有3个参数,直接第二种情况dom.style.color = ‘red’

  5. 有2个参数,需要判断第二个参数(typeof xxx === ‘string’)

style(node,name,value){
        if(arguments.length === 3 ){
            // dom.style(node,'color','red')
            node.style[name] = value
        }
        if(arguments.length === 2){
            if(typeof name === 'string'){
                // dom.style(node,'color')
                return node.style[name]
            }else if(name instanceof Object){//instanceof 判断name 是否为Object
                // dom.style(node,{'color':'red','border':'1px,solid,red'})
                let object = name
                for (let key in object){
                    node.style[key] = object[key]
                }
            }
        }
    },

思路node.classList.add(className)

dom.class.add/remove/has()添加,删除,是否包含一个类

class:{
        add(node,className){
            node.classList.add(className)
        },
        remove(node,className){
            node.classList.remove(className)
        },
        has(node,className){
            return node.classList.contains(className)
        }
    },

dom.on(node,eventName,fn)添加事件监听

	on(node,eventName,fn){
	node.addEventListener(eventName,fn)
}

dom.remove()删除事件监听

	off(node,eventName,fn){
	node.removeEventListener(eventName,fn)
}

四、获取标签、元素

dom.find(selector,scope)获取标签或标签们

	find(selector,scope){
	return (scope || document).querySelectorAll(selector)
}

dom.parent(node)获取父元素

	parent(node){
	return node.parentNode
}

dom.children(node)获取子元素

	children(node){
	return node.children
}

dom.siblings(node)获取兄弟元素

思路:找到爸爸节点后删掉自己

 siblings(node){
        return Array.from(node.parentNode.children).filter(n=>n!==node)
    },

dom.next(node)获取弟弟节点

节点包含html标签、文本、注释,需要确保获取到的是html标签

next(node){
        let x = node.nextSibling
        //如果下一个节点不是html元素节点则继续找下一个
        while(x && x.nodeType !== 1){ //nodeType返回值1为元素节点,2为属性节点
            x = x.nextSibling
        }
        return x
    },

dom.prev(node)获取哥哥节点

prev(node){
        let x = node.previousSibling
        while(x && x.nodeType !==1){
            x = x.previousSibling
        }
        return x
    },

dom.each(nodeList,fn)遍历所有节点

 each(nodeList,fn){
            for(let i =0;i<nodeList.length;i++){
                fn.call(null,nodeList[i])
            }
     
    },

index(node)用于获取排行第几

 index(node){
        let nodeList = dom.children(dom.parent(node))
        
        for(let i=0;i<nodeList.length;i++){
            if(nodeList[i] === node){
                return i
            }
        }
        return -1 //没找到
    }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值