# BOM

# 一、DOM 核心

  1. 创建
document.write
innnerHTML
createElement
appendChild
insertBefore
removeChild

  1. (1) 修改元素属性:src、href、title等。
    (2) 修改普通元素:innnerHTML、innerText。
    (3) 修改表单元素:value、type、disabled等。
    (4) 修改元素样式:style、className。

  2. 查 (获取 DOM 的)
    (1) DOM 提供的 API 方法:getElementById、getElementByTagName 古老用法 不太推荐。
    (2) H5提供的新方法:querySelector、querySelectorAll 提倡。
    (3)利用节点操作获取元素:父(parentNode)、子(children)、兄(previousElementSibling、nextElemnentSibling)提倡。

  3. 属性操作
    (1) setAttribute:设置 DOM 的属性值。
    (2) getAttribute:得到 DOM 的属性值。
    (3) removeAttribute:移除属性。

  4. 事件操作 (鼠标事件)

onclick        // 鼠标点击左键触发
onmouseover    // 鼠标经过触发
onmouseout     // 鼠标离开触发
onfocus        // 获得鼠标焦点触发
onblur         // 失去鼠标焦点触发
onmousemove    // 鼠标移动触发
onmouseup      // 鼠标弹起触发
onmousedown    // 鼠标按下触发

# 二、注册事件两种方式

var btns = document.querySelectorAll('button');

  1. 传统方式注册事件 特点:注册事件的唯一性
btns[0].onclick = function() {
    alert('hi');
}
btns[0].onclick = function() {
    alert('hello');
}
  1. 事件监听注册事件 addEventListener (1) 里面的事件类型是字符串 加引号 不带on (2) 同一个元素 同一个事件可以添加多个侦听器(事件处理程序)
btns[1].addEventListener('click', function() {
    alert(22);
})
btns[1].addEventListener('click', function() {
    alert(33);
})
//  eventTarget.addEventListener(type, listener[, useCapture])
// type: 事件类型字符串,比如click、mouseover,注意不加on
// listener: 事件处理函数,事件发生时,会调用该监听函数
// useCapture: 可选函数,是一个布尔值,默认是false。
  1. attachEvent ie9以前的版本支持
btns[2].attachEvent('onclick', function() {
    alert(11);
})

# 三、删除事件(解绑事件)

var divs = document.querySelectorAll('div');
divs[0].onclick = function() {
    alert(11);
// 1. 传统方式删除事件(解绑事件)
    divs[0].onclick = null;
}

// 2. removeEventListener 删除事件
divs[1].addEventListener('click', fn)  // 里面的fn 不需要调用加小括号
function fn() {
    alert(22);
    divs[1].removeEventListener('click', fn);
}

// 3. 
divs[2].attachEvent('onclick', fn1);
function fn1() {
    alert(33);
    divs[2].detachEvent('onclick', fn1);
}

# 四、事件对象、e.target 和 this 区别

# 1. DOM 事件流

事件流描述的是从页面中接受事件的顺序。
事件发生时会在元素节点之间按照特定的顺序传播,这个传播过程即 DOM 事件流。
DOM 事件流分为3个阶段:
①捕获阶段 ②当前目标阶段 ③冒泡阶段

  1. js 代码中只能执行捕获或冒泡其中的一个阶段。
  2. onclick 和 attachEvent(ie) 只能得到冒泡阶段。
  3. 捕获阶段 如果addEventListener 第三个参数是 true 那么则处于捕获阶段 document -> html -> body -> father -> son
  4. 冒泡阶段 如果addEventListener 第三个参数是 false 或者 省略 那么处于冒泡阶段 son -> father -> body -> html -> document

# 2. 事件对象

  1. event就是一个事件对象 写到侦听函数小括号里 当形参来看。
  2. 事件对象只有有了事件才会存在 它是系统自动创建的,不需要我们传递参数。
  3. 事件对象 跟事件相关 比如鼠标点击的坐标,键盘按下了哪个键。
  4. 事件对象可自己命名 如 event、evt、e。
  5. 事件对象也有兼容性问题 ie678 通过 window.event 兼容性的写法 e = e || window.event;

# 3. e.target 和 this 区别

常见事件对象的属性和方法

  1. e.target 返回的是触发事件的对象(元素) , this返回的是绑定事件的对象(元素) 区别: e.target 点击了哪个元素,就返回那个元素, this哪个元素绑定了这个点击事件 就返回谁
var ul = document.querySelector('ul');
ul.addEventListener('click', function(e) {
    // 给ul 绑定事件 那么this 就指向ul 
    console.log(this);
    // e.target 指向的是我们点击的那个对象 
    console.log(e.target);
})

# 4. 阻止默认行为

常见事件对象的属性和方法

  1. 返回事件类型
var div = document.querySelector('div');
div.addEventListener('click', fn);
div.addEventListener('mouseover', fn);
div.addEventListener('mouseout', fn);
function fn(e) {
    console.log(e.type);
}
  1. 阻止默认行为(事件)让链接不跳转 或者 让提交按钮不提交
var a = document.querySelector('a');
a.addEventListener('click', function(e) {
    e.preventDefault();
})
  1. 传统的注册方式
a.onclick = function(e) {
    // 普通浏览器 e.preventDefault();  方法
    e.preventDefault();
    // 低版本浏览器 ie678  returnValue 属性
    e.returnValue;
    // 可以利用 return false 也可以阻止默认行为 没有兼容性问题 特点: return后面的代码不执行 而且只限于传统的注册方式
    return false;
}

# 5. 阻止事件冒泡

阻止冒泡 dom 推荐的标准 stopPropagation()

var son = document.querySelector('.son');
son.addEventListener('click', function(e) {
    alert('son');
    e.stopPropagation(); // stop 停止 Propagation 传播
    // 如果考虑兼容性问题 
    e.cancelBubble = true;  // 非标准 cancel 取消 bubble 泡泡
}, false);
var father = document.querySelector('.father');
father.addEventListener('click', function(e) {
    alert('father');
    e.stopPropagation();
}, false);
document.addEventListener('click', function() {
    alert('document');
})

# 6. 事件委托

事件委托的原理:不是每个子节点单独设置事件监听器,而是事件监听器设置在其父节点上,然后利用冒泡原理影响设置每个子节点。

var ul = document.querySelector('ul');
ul.addEventListener('click', function(e) {
    // alert('hello');
    e.target.style.backguroundColor = 'pink';
})

# 五、禁止选中、键盘事件

# 1. 禁止选中文字和禁止右键菜单

  1. contextmenu 禁用右键菜单
document.addEventListener('contextmenu', function(e) {
    e.preventDefault();
})
  1. 禁止选中文字 selectstart
document.addEventListener('selectstart', function(e) {
    e.preventDefault();
})

# 2. 获得鼠标在页面中的坐标

鼠标事件对象 MouseEvent

document.addEventListener('click', function(e) {
  1. clientX 鼠标在可视区的x和y坐标
    console.log(e.clientX);
    console.log(e.clientY);
    console.log('-------------------');
  1. page 鼠标在页面文档的x和y坐标 (常用)
    console.log(e.pageX);
    console.log(e.pageY);
    console.log('-------------------');
  1. screen 鼠标在电脑屏幕的x和y坐标
    console.log(e.screenX);
    console.log(e.screenY);
})

# 3. 常用的键盘事件

常用的键盘事件 addEventListener 不需要加 on

  1. keyup 按键弹起的时候触发 执行顺序第三
document.addEventListener('keyup', function() {
    console.log('我弹起了');
})
  1. keydown 按键按下的时候触发 执行顺序第一
document.addEventListener('keydown', function() {
    console.log('我按下了1');
})
  1. keypress 按键按下的时候触发 不识别功能键 ctrl shift箭头等 执行顺序第二
document.addEventListener('keypress', function() {
    console.log('我按下了2');
})

# 4. keyCode判断用户按下了哪个键

键盘事件对象中的keyCode属性可以得到相应键的ASCII码值

document.addEventListener('keyup', function(e) {
    console.log(e.keyCode);
    // 1. keyup 和 keydown 事件不区分字母大小写 a 和 A 得到的都是65
    // 2. keypress事件 区分字母大小写 a 和 A 得到的 是97和65
})
document.addEventListener('keypress', function(e) {
    console.log(e.keyCode);
})

# 六、页面加载事件、定时器

# 1. BOM

浏览器对象模型,把浏览器看作一个对象模型来看待,BOM的顶级对象是window, BOM学习的是浏览器窗口交互的一些对象,BOM浏览器厂商在个字浏览器上定义的,兼容性较差。

  1. window是js访问浏览器窗口的一个接口
  2. 是一个全局对象,定义在全局作用域中、函数都会变成window对象的属性和方法。调用时省略window。 window下的一个特殊属性window.name
var num = 10;
console.log(num);
console.log(window.num);

function fn() {
    console.log(20);
}
fn();
window.fn();

console.dir(window);
console.log(window.name);   // 空 

# 2. 页面加载事件

window.onload 传统注册事件方式只写一次, 如有多个,以最后一个为准, 使用addEventListener没有限制。

window.onload = function() {
    var btn = document.querySelector('button');
    btn.addEventListener('click', function() {
        alert('点击我');
    })
}


// 页面所有的内容加载完了再去加载  
window.addEventListener('load', function() {
    var btn = document.querySelector('button');
    btn.addEventListener('click', function() {
        alert('点击我');
    })
})
// load  是等内容全部加载完毕,包含页面dom元素 图片 flash css等
window.addEventListener('load', function() {
    alert(22);
})
// DOMContentLoaded 是DOM 加载完毕,不包含页面dom元素 图片 flash css等就可以执行 加载速度比 load 更快一些
window.addEventListener('DOMContentLoaded', function() {
    alert(33);
})

# 3. 调整窗口大小

window.addEventListener('load', function() {
    var div = document.querySelector('div');
    // resize 只要窗口大小发生变化就会触发这个事件
    window.addEventListener('resize', function() {
        console.log(window.innerWidth);
        console.log('变化了');
        // window.innerWidth  当前屏幕的宽度
        if (window.innerWidth <= 800) {
            div.style.display = 'none';
        } else {
            div.style.display = 'block';
        }
    })
})

# 4. 定时器之 setTimeout

  1. setTimeout 语法规范: window.setTimeout(调用函数, 延时时间); window可省略,延时时间单位是毫秒,如果省略默认0
setTimeout(function() {
    console.log('时间到了');
}, 2000);
// 调用函数可以直接写函数
function callback () {
    console.log('爆炸了');
}
// 页面中可能有很多定时器,我们经常给定时器加标识符(名字)
setTimeout(callback, 3000);
// setTimeout('callback()', 4000);   // 不提倡这个写法

# 5. 清楚定时器 clearTimeout

var btn = document.querySelector('button');
var timer = setTimeout(function() {
    console.log('爆炸了');
}, 5000);
btn.addEventListener('click', function() {
    // 小括号里面的参数就是定时器的标识符
    clearTimeout(timer);
})

# 6. 定时器之 setInterval

定时器之setInterval 可以调用很多次

setInterval(function() {
    console.log('继续输出');
}, 1000);

# 7. 清楚定时器 clearInterval

var begin = document.querySelector('.begin');
var stop = document.querySelector('.stop');
var timer = null;    // 全局变量
begin.addEventListener('click', function() {
    timer = setInterval(function() {
        console.log('ni hao ma');
    }, 1000);
})
stop.addEventListener('click', function() {
    clearInterval(timer);
})  

# 七、this指向问题、location对象和方法

# 1. this 指向问题

  1. 全局作用域或者普通函数中this窒息那个全局对象window(定时器里面的this指向window)
console.log(this);
function fn() {
    console.log(this);
}
fn();
window.setTimeout(function() {
    console.log(this);
})
  1. 方法调用中谁调用this指向谁
var o = {
    sayHi: function() {
        console.log(this);  // this指向o这个对象
    }
}
o.sayHi();
var btn = document.querySelector('button');
btn.onclick = function() {
    console.log(this);    // this指向btn按钮对象
}
btn.addEventListener('click', function() {
    console.log(this);    // this指向btn按钮对象
})
  1. 构造函数中的this指向构造函数的实例
function Fun() {
    console.log(this);
} 
var fun = new Fun();

# 2. js 同步和异步

同步:前一个任务结束后再执行后一个任务。比如等水开了(等10分钟),再去切菜炒菜。 异步:做一件事情时,因为这件事花费很长时间,做这件事的同时,还可以去做别的事情。比如烧水的同时,利用这10分钟去切菜炒菜。 它俩本质区别:这条流水线上各个流程的执行顺序不同。

console.log(1);
setTimeout(function() {
    console.log(3);
}, 1000);
console.log(2);
// 顺序是  先打印1和2,再打印3.

# 3. 同步任务和异步任务的执行过程

js执行机制:
同步任务都在主线程上执行,形成一个执行栈。
异步任务 js的异步是通过回调函数实现的,异步任务有以下几种:

  1. 普通事件,如click、resize等。
  2. 资源加载,如load、error等。
  3. 定时器,包括setInterval、setTimeout等。
    异步任务相关回调函数添加到任务队列中(又称消息队列)。

事件循环 event loop :同步任务执行完了之后会去看异步任务的消息队列,如果有要执行的任务的话就获取过来执行,执行完了之后又去看消息队列,这个循环的过程称为事件循环。 主线程执行栈(同步任务) -> 异步进程处理 -> 任务队列 -> 主线程执行栈(同步任务)

# 4. location 对象

window 对象给我们提供了一个 location 属性用于获取或设置窗体的URL,还可用于解析URL。 URL:统一资源定位符,是互联网上标准资源的地址。 protocol://host[:port]/path/[?query]#fragment http://www.itcast.cn/index.html?name=andy&age=18#link

protocol -> 通信协议 常用的http,ftp,maito等 host -> 主机(域名) www.itheima.com port -> 端口号 可选,省略时使用方案的默认端口 如http的默认端口是80 path -> 路径 由 零或多个'/'符号隔开的字符串,一般用来表示主机上的一个目录或文件地址 query -> 参数 以键值对的形式,通过&符号分隔开来 fragment -> 片段 #后面内容 常见于链接 锚点

location对象属性 返回值 location.href 获取或设置整个URL location.host 返回主机(域名) www.itheima.com location.port 返回端口号 如果未写返回 空字符串 location.pathname 返回路径 location.search 返回参数 location.hash 返回片段 #后面内容 常见于链接 锚点

# 5. 获取 URL 参数

index:

console.log(location.search);   // 得到的是 ?uname=andy
// 1. 先去掉问号?    substr('起始位置',截取几个字符);
var params = location.search.substr(1);   //  uname=andy
console.log(params);
// 2. 利用= 把字符串分割为数组 split('=');
var arr = params.split('=');
console.log(arr);   // ['uname', 'andy']
var div = document.querySelector('div');
// 3. 把数据写入div中
div.innerHTML = arr[1] + '欢迎您!';

login:

    <form action="index.html">
        用户名: <input type="text" name="uname">
        <input type="submit" value="登录">
    </form>

# 6. location常用方法

location.assign('这里写想要跳转的网址');

var btn = document.querySelector('button');
btn.addEventListener('click', function() {

assign 记录浏览历史,所以可以实现后退功能

    location.assign('http://www.baidu.com');

replace 不记录浏览历史,所以不可以实现后退功能

    location.replace('http://www.baidu.com');

相当于重新加载页面 如果参数true 强制刷新ctrl+f5

    location.reload(true);
})

# 八、navigator、history对象,offset和style

# 1. navigator对象

navigator对象包含有关浏览器的信息,它有很多属性,我们最常用的是userAgent,该属性可以返回有客户机发送服务器的user-agent头部的值。

if((navigator.userAgent.match(/(phone|pad|pod|iPhone|iPod|ios|iPad|Android|Mobile|BlackBerry|IEMobile|MQQBrowser|JUC|Fennec|wOSBrowser|BrowserNG|webOS|Symbian|Windows Phone)/i))) {
    window.location.href="";   // 手机
} else {
    window.location.href="";   // 电脑
} 

# 2. history对象

index:

<a href="list.html">点击我去往列表页</a>
<button>前进</button>
// history对象方法    作用
// back()           后退功能
// forward()        前进功能
// go(参数)          前进后退功能 参数如果是1前进1个页面,如果是-1 后退1个页面

var btn = document.querySelector('button');
btn.addEventListener('click', function() {
    history.forward();
    // history.go(1);
})

list: 点击我去往首页

        var btn = document.querySelector('button');
        btn.addEventListener('click', function() {
            // history.back();
            history.go(-1);
        })

# 3. offsetLeft和offsetTop获取元素偏移

offset 系列 offset翻译就是偏移量,使用offset系列相关属性可以动态的得到该元素的位置(偏移)、大小等。

var father = document.querySelector('.father');
var son = document.querySelector('.son');
  1. 可以得到元素的偏移 位置 返回的不带单位的数值
console.log(father.offsetTop);
console.log(father.offsetLeft);
// 它以带有定位的父级为准 如果没有父级或者父级没有定位 则以body为准
console.log(son.offsetLeft);
  1. 可以得到元素的大小 宽度和高度 是包含padding + border + width
var w = document.querySelector('.w');
console.log(w.offsetWidth);
console.log(w.offsetHeight);
  1. 返回带有定位的父元素 否则返回body
console.log(son.offsetParent);
console.log(son.parentNode);  // 返回最近的父级元素 不管它有没有定位

# 4. offset和style的区别

var box = document.querySelector('.box');
console.log(box.offsetWidth);
console.log(box.style.width);
// offsetWidth = '300px';
box.style.width = '300px';

offset style 可以得到任意样式表中的样式值 只能得到行内样式表中的样式值 获得的数值是没有单位的 style.width获得的事带有单位的字符串
offsetWidth包含padding+border+width style.width获得不包含padding和border的值
offsetWidth等是只读属性,只能获取不能赋值 style.width是可读写属性,可以获取也可以赋值
所以,想要获取元素大小位置,用offset更合适 所以,想要给元素赋值,用style改变

# 5. 获取鼠标在盒子内的坐标

var box = document.querySelector('.box');
box.addEventListener('mousemove', function(e) {
    // console.log(e.pageX);
    // console.log(e.pageY);
    // console.log(box.offsetLeft);
    var x = e.pageX - this.offsetLeft;
    var y = e.pageY - this.offsetTop;
    this.innerHTML = 'x坐标是: ' + x + ' y坐标是: ' + y;
})