BOM / DOM 相关知识点

本文详细介绍了浏览器对象模型(BOM)和文档对象模型(DOM)的概念及其应用,涵盖了BOM和DOM的基本操作、事件模型等内容,并探讨了如何利用事件监听和事件代理优化前端开发。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

0. 什么是BOM和DOM?

BOM指的是浏览器对象模型,它指的是把浏览器当作一个对象来对待,这个对象主要定义了与浏览器进行交互的方法和接口。BOM的核心是window,而window对象具有双重角色,它既是通过js访问浏览器的窗口的一个接口,又是一个全局对象。这意味着在网页中定义的任何对象,变量和函数,都作为全局对象window上的一个属性或方法存在。window对象含有location对象,navigator对象,screen对象等子对象,并且DOM的最根本的document对象也是BOM的window对象的子对象

DOM指的是文档对象模型,它指的是把文档当作一个对象来对待,这个对象主要定义了处理网页内容的方法和接口。

0-1. BOM 对象

BOM对象

0-2. DOM对象

  1. DOM常见的操作:
    • 创建节点
    • 查询节点
    • 更新节点
    • 添加节点
    • 删除节点
      在这里插入图片描述
  • DOM 常见操作

  • 虚拟dom转真实dom

    // 虚拟dom
    const vnode = {
      tag: 'div',
      props: {
        id: 'app'
      },
      children: [
        {
          tag: 'p',
          props: {
            className: 'text'
          },
          children: [
            'hello world!!!'
          ]
        }
      ]
    }
    // 渲染函数
    function _render(vnode) {
      if (typeof vnode === 'string') {
        // 创建一个文本节点 ---- createTextNode
        return document.createTextNode(vnode)
      }
    
      // 创建新元素,接受一个参数,即要创建元素的标签名 ---- document.createElement
      const dom = document.createElement(vnode.tag)
      if (vnode.props) {
        Object.keys(vnode.props).forEach(key => {
          const attr = vnode.props[key]
          // 在指定元素中添加一个属性节点,如果元素中已有该属性改变属性值 ---- setAttribute
          dom.setAttribute(key, attr)
        })
      }
      // 把一个子节点添加到父节点的最后一个子节点 ---- appendChild
      vnode.children.forEach(child => dom.appendChild(_render(child)))
    
      return dom
    }
    
    <div id="app">
      <p class="text">hello world!!!</p>
    </div>
    // 真实dom转化为虚拟dom
    const dom2tree = (node) => {
      const obj = {}
      if(node.tagName) {
        obj.tag = node.tagName
      } else {
        // 文本节点
        return node.data
      }
      obj.props = {}
      // 获取元素的所有属性attributes ---- node.attributes
      let len = node.attributes.length
      for(let i=0;i<len;i++) {
        obj.props[node.attributes[i].nodeName] = node.attributes[i].nodeValue
      }
      obj.children = []
      node.childNodes.forEach(child => {
        obj.children.push(dom2tree(child))
      })
      return obj
    }
    

1. 事件模型

事件绑定/事件监听
概念:某些组件被执行了某些操作后,触发某些代码的执行。	
	* 事件:某些操作。如: 单击,双击...
	* 事件源:组件。如: 按钮、文本输入框...
	* 监听器:回调函数。
	* 常见的事件:
	1. 点击事件:
		1. onclick:单击事件
		2. ondblclick:双击事件
	2. 焦点事件
		1. onblur:失去焦点
		2. onfocus:元素获得焦点。

	3. 加载事件:
		1. onload:一张页面或一幅图像完成加载。

	4. 鼠标事件:
		1. onmousedown	鼠标按钮被按下。
		2. onmouseup	鼠标按键被松开。
		3. onmousemove	鼠标被移动。
		4. onmouseover	鼠标移到某元素之上。
		5. onmouseout	鼠标从某元素移开。
		
	5. 键盘事件:
        1. onkeydown	某个键盘按键被按下。	
        2. onkeyup		某个键盘按键被松开。
        3. onkeypress	某个键盘按键被按下并松开。
        
    6. 选择和改变
		1. onchange	域的内容被改变。
		2. onselect	文本被选中。

	7. 表单事件:
		1. onsubmit	确认按钮被点击。
		2. onreset	重置按钮被点击。

1. 原始事件模型

  1. 绑定方式一:标签内直接绑定

    //例:
    < button type="button" onclick="change()" id="btn">点击< /button>
    
    <script>
    	function change(){
        	var b=document.getElementById('btn');
        	b.innerText='登录';
    	}
    </script>
    
  2. 绑定方式二:使用js动态绑定

    //例:
    < button type="button" id="btn">点击< /button>
    <script>
        var btn=document.getElementById('btn');
        btn.onclick = function(e){
            btn.innerText='登录';
            alert(e.target.value); 
        }
    </script>
    

特性:

  1. 绑定速度快:但由于绑定速度太快,可能页面还未完全加载出来,以至于事件可能无法正常运行;
  2. 只支持冒泡,不支持捕获;
  3. 同一个类型的事件只能绑定一次

2. 标准事件模型

绑定方式:使用addEventListener() 添加事件监听

//例:
< button type="button" id="btn">点击< /button>

<script>
    var b=document.getElementById('btn');
    b.addEventListener('click',function (change) {
        b.innerText='登录';
    },true);
</script>
标准事件模型DOM事件流的三个阶段

标准事件模型DOM事件流的三个阶段包括事件捕获阶段,处于目标阶段,事件冒泡阶段;

(1)事件捕获阶段:当我们在 DOM 树的某个节点发生了一些操作,例如单击,就会有一个事件发射过去。这个事件从 Window 发出,不断经过下级节点直到触发的目标节点,在到达目标节点之前的过程,就是捕获阶段。捕获阶段的任务就是建立这个事件的传递路线,以便后面冒泡阶段顺着这条路线返回 Window。

(2)处于目标阶段:当事件不断的传递直到目标节点的时候,最终在目标节点上触发这个事件,就是处于目标阶段。

(3)事件冒泡阶段:事件冒泡即事件开始时,由事件发生所在的节点开始,然后逐级向上传播。

window.addEventListener监听的是哪个阶段的事件?
// 取决于window.addEventListener的第三个参数,第三个参数默认为false
//例:
//冒泡阶段
window.addEventListener('click',()=>{

},false)
//捕获阶段
window.addEventListener('click',()=>{

},true)

2. 事件冒泡

事件的冒泡:-所谓的冒泡指的是事件的向上传导,当后代元素上的事件(click、keydown…)被触发时,其祖先元素的相同事件会被自动触发

事件冒泡阶段:事件从事件目标(target)开始,往上冒泡直到页面的最上一级标签。

  • 目前不支持冒泡的事件:

    1. UI事件:
      load
      unload
      scroll
      resize
    2. 焦点事件:
      blur
      focus
    3. 鼠标事件
      mouseleave
      mouseenter

    原因是在于:这些事件仅发生于自身上,而它的任何父节点上的事件都不会产生,所有不会冒泡。

  • 取消事件冒泡

    function stopPropagation(event) {
    	//阻止冒泡
    	event = event || window.event;
    	//W3C标准   Propagation/,prɒpə'ɡeɪʃən/
    	if(event.stopPropagation){
    		event.stopPropagation();
    	}else{//IE标准
    		event.cancelBubble = true;
    	}
    
    }
    
  • 阻止浏览器的默认行为

    什么是默认事件?

    1. a 标签 href 属性上的跳转。
    2. 鼠标右键呼出菜单。
    3. form 表单里 button 标签和 type属性为 submit 的 input 标签的提交。
    function cancelHandler(event ){
        var event = event ||window.event;
        //W3C标准
        if(event.preventDefault){
            event.preventDefault();
        }else{//IE标准
            event.returnValue = false;
        }
    }
    

3. 事件代理/事件委托

事件代理就是把一个元素的响应事件函数委托到另一个元素上,就是说本来应该加在子元素身上的事件,我们把事件加在了其父级元素身上。事件代理的原理是DOM元素的事件冒泡。

好处:

  1. 代码简洁,效率高,比如,不用for循环为子元素添加事件
  2. js新生成的子元素也不用新为其添加事件了,程序逻辑上比较方便
  3. 减少浏览器内存占用

5. 自定义一个通用的事件监听函数【包括事件代理】

/**
* elem表示要进行监听的元素
* type表示事件类型
* fn表示事件触发时的操作
* selecter表示事件代理的元素
*/
function bindEvent(el, type, fn, selector) {
	// 普通的事件监听
	if(!selector) {
		el.addEventListener(type, fn);
		return
	}
	// 事件委托
	el.addEventListener(type, event => {
		let element = event.target
		//事件触发的真实元素是否匹配期望的选择器
		if(element.matches(selector)) {
			fn.call(element, event)
		}
	})
}
var parent = document.querySelector('.parent')
var son1 = document.querySelector('.son1')

// 普通点击事件
bindEvent(son1, 'click', e => {
	e.stopPropagation()
	console.log(e.target)//e.target是事件触发的真实元素
	console.log(e.currentTarget)//e.currentTarget是事件绑定的元素
})

// 事件委托
bindEvent(parent, 'click', e => {
	console.log(e.target)
	console.log(e.currentTarget)
}, '.son3')

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值