JS (1)
js的一些方法
console.dir() 可以显示一个对象的所有属性和方法
innerHTML 和 innerText:
innerHTML获取内容时,如果内容有标签,会把标签获取到。原封不动获取。设置内容如果有标签,会解析;
innerText获取内容时,如果内容有标签,会过滤。会把前后空白换行也去掉
innerText和textContent:
可能有浏览器兼容问题,旧版可能不支持innerText
自定义属性
<div id='tt' age="12"></div>
普通的如id可以直接.id形式调用,自定义属性的话,调用方式为:
var s = document.getElementById('tt'); console.log(s.getAttribute('age'));
设置自定义属性:
s.setAttribute('sex','male');
删除属性:
s.removeAttribute('id');
构造函数
function node(options) { this.className = options.className ? options.className : ''; } var o = new node({ className: 'cls' });
||运算符:
如果两边是其他类型,会先转换布尔,如果第一个是true,直接返回这个的值,如果是false,返回第二个的值
那上面的方法可以改下:
this.className = options.className || '';
接上文,构造dom节点
function Node(options) { this.className = options.className || ''; this.nodeName = options.nodeName || ''; //节点的名称 如果是元素节点,是标签的名称 this.nodeType = options.nodeType || 1; //节点的类型 元素节点1 属性节点2 文本节点3 this.nodeValue = options.nodeValue || null; //记录节点的值,元素节点始终是null this.children = options.children || []; //记录子节点 }
子节点 方法
.childNodes 所有子节点
.children 所有子元素
.hasChildNodes 判断是否有子节点(注意 空白也算文本节点)
.firstChild 第一个子节点(没有返回 null)
.lastChild 最后一个子节点
.firstElementChild 第一个子元素 (兼容性,从IE9开始支持)
a标签不跳转
<a href="javascript:void(0)"></a>
void是运算符,执行void后面的表达式,并始终返回undefined
兄弟节点
.nextSibling 下一个节点
.previousSibling 上一个节点
.nextElementSibling 下一个兄弟元素
.previousElementSibling
动态生成元素
document.write() 点击按钮时用此方法输出内容,会把之前整个页面覆盖掉,所有只能在一开始用,不能在事件中用
element.innerHTML = ‘
‘;动态生成列表:
btn.onclick = function(){ var box = document.getElementById('box'); box.innerHTML = '<ul>'; for (var i = 0; i<data.length;i++) { box.innerHTML += '<li>' + data[i] + '</li>'; } box.innerHTML += '</ul>'; };
但是每次使用innerHTML,页面就会重绘DOM树,会有性能问题。
优化:
btn.onclick = function(){ var box = document.getElementById('box'); var html = '<ul>'; for (var i = 0; i<data.length;i++) { html += '<li>' + data[i] + '</li>'; } html += '</ul>'; box.innerHTML = html; };
由于字符串不可变,大量拼接字符串也会有问题。继续优化:
btn.onclick = function(){ var box = document.getElementById('box'); var arr = []; arr.push('<ul>'); for (var i = 0; i<data.length;i++) { arr.push('<li>' + data[i] + '</li>'); } arr.push('</ul>'); box.innerHTML = arr.join(''); };
动态创建
var p = document.createElement('p'); //内存中创建一个DOM对象 var box = document.getElementById('box'); box.appendChild(p);
动态创建列表
<body> <select name="" id="all" multiple> <option value="">1</option> <option value="">2</option> <option value="">3</option> <option value="">4</option> </select> <select name="" id="new" multiple></select> </body>
把列表1的插入到列表2中:
var al = document.getElementById('all'); var ne = document.getElementById('new'); var num = al.children.length; for(var i = 0;i<num;i++){ ne.appendChild(al[0]); }
也可以用new.innerHTML = al.innerHTML; 再 al.innerHTML = ‘’; 代码很简单
但是如果注册了事件,innerHTML不会把事件移动过去。需要用appendChild。
注册事件
如果用btn.onclick, 写两个的话后一个会覆盖前一个,无法给同一对象的同一事件注册多个事件处理函数
这时候可以用addEventListener
btn.addEventListener('click', function () { alert(); }); btn.addEventListener('click', function () { alert(); });
(但是这个有点兼容性问题,老版本IE用attachEvent(eventNameWithOn, callback) IE特有)
移除事件
btn.onclick = function () { btn.onclick = null; };
function btnCk() { alert('hello'); btn.removeEventListener('click',btnCk); } btn.addEventListener('click',btnCk); //用这种方法,注册事件的时候就不能使用匿名函数
function btnCk() { alert('hello'); btn.detachEvent('onclick',btnCk); //旧版本IE }
addEventListener有三个参数。第三个参数为false时,事件冒泡,从里向外执行
为true时,事件捕获,顺序为相反
事件的三个阶段
- 事件捕获
- 执行当前点击的元素
- 事件冒泡
事件冒泡的作用
事件委托:事件会传递到父元素,可以让父元素去执行。
var ul1 = document.getElementById('u'); ul1.onclick = function (e) { //e 是事件参数(事件对象),当事件发生的时候可以获取一些和事件相关的数据 //获取当前点击的li, e.target是真正触发事件的对象,真正点击的标签 console.log(e.target); }; //考虑兼容性:e = e || window.event
<ul id="u"> <li>1</li> <li>2</li> <li>3</li> </ul>
另外还有个 e.currentTarget,事件处理函数所属的对象(this)
e.eventPhase 事件的阶段
e.type 获取事件名
e.clientX 和 e.clientY 获取鼠标在可视区域内的坐标
e.pageX 和 e.pageY 获取相对整个页面的坐标 page = client + 页面滚动出去的距离
document.onclick = function () { console.log(document.body.scrollLeft); //输出页面滚动出去的距离。 console.log(document.body.scrollTop); }
(有些浏览器用document.documentElement.scrollLeft)
获取盒子在页面的位置
box.onclick = function () { //盒子坐标 console.log(this.offsetLeft); console.log(this.offsetTop); //偏移量 };
获取盒子大小
console.log(box.offsetWidth); console.log(box.offsetHeight);
offsetParent 获取距离当前元素最近的定位父元素,如果没有定位父元素就是body
获取鼠标在盒子中的位置
鼠标坐标 - 盒子坐标
box.onclick = function (e) { // console.log(this.offsetLeft); // console.log(this.offsetTop); e = e || window.event; var x = e.pageX - this.offsetLeft; var y = e.pageY - this.offsetTop; console.log(x); console.log(y); };
client相关属性
clientLeft border-left的宽度
clientTop border-top的宽度
clientWidth clientHeight
scroll 相关属性
scrollWidth/scrollHeight 内容的大小,包括padding和未显示的内容,不包括滚动条
scrollLeft / scrollTop 内容滚动出去的距离
(此图中,clientWidth / clientHeight 是元素的大小+padding,不包括滚动条。滚动条其实占了原来的一部分,所以clientWidth变小了)
box.onscoll = function(){} 在拖动滚动条时触发的事件
事件对象来取消默认行为
e.preventDefault()
// IE老版本:e.returnValue = false;
取消冒泡
e.stopPropagation()
// IE老版本:e.cancelBubble = true;
键盘事件
var txt = document.getElementById('txt'); // keydown 键盘按下 keyup 键盘弹起 (keydown时按键还没有录入文本框,keyup按的键已经录入文本框) txt.onkeydown = function (e) { if((e.keyCode<48||e.keyCode>57)&&e.keyCode!=8){ //非数字 e.preventDefault(); } }
var txt = document.getElementById('qq'); //当文本改变且失去焦点触发 txt.onchange = function () { console.log(this.value); }
BOM
BOM 顶级对象:window 当我们使用window的时候可以省略
定义的全局变量都属于window,都是window对象的属性
如果定义了和window本来就有的同名属性,可能会有问题,如name(在window里是一个空字符串,定义name=123最后还是会变成字符串),top(window的属性,只能获取不能赋值)
onload
window.onload = function() {} 页面加载完成(所有元素创建完毕,引用的外部资源下载完毕,如js,css,图片)后执行
script标签写在body末尾,只用等元素创建完毕,不用等待下载。
其他元素也都有onload属性
onunload 页面卸载时执行。在onunload中所有的对话框都无法使用,window对象被冻结
刷新页面发生了:1.卸载页面 2.重新加载页面
定时器
//setTimeout() 定时炸弹 隔一段事件执行,只一次 //setInterval() 闹钟 会重复执行
setTimeout(function () { //第一个参数是要执行的函数,第二个参数是间隔时间(毫秒) }, 3000); //此函数有返回值,是一个整数,是定时器的标识,可以获取以找到这个定时器,进行取消操作clearTimeout(id)
倒计时
function getInterval(start,end) { //两个日期对象相差的毫秒 var interval = end - start; var day,hour,minute,second; interval/=1000; day = Math.round(interval/60/60/24); hour = Math.round(interval/60/60%24); minute = Math.round(interval/60%60); second = Math.round(interval%60); return { day: day, hour: hour, minute: minute, second: second } }
var d = document.getElementById('d'); var h = document.getElementById('h'); var m = document.getElementById('m'); var s = document.getElementById('s'); var endDate = new Date('2019-11-11 0:0:0'); function countDate() { var startDate = new Date(); var interval = getInterval(startDate,endDate); d.innerHTML = interval.day; h.innerHTML = interval.hour; m.innerHTML = interval.minute; s.innerHTML = interval.second; } countDate(); //因为setInterval要等一秒才执行,所以先执行一次以免刷新出现空白 setInterval(countDate,1000);
location
location.href = ‘www.baidu.com’;
location.assign(‘www.baidu.com’);
两个效果一样
location.replace(‘www.baidu.com’) 替换地址栏地址但不记录历史,无法后退
location.reload() 刷新 可带参数,为true时强制从服务器获取页面,为false时如果浏览器有缓存,直接从缓存获取页面
URL组成:
点击使位置移动
btn.onclick = function () { console.log(box.style.left); box.style.left = box.style.left + 10 + 'px'; };
注:style.left获取的是标签中的style设置的样式属性值,不是css文件中的,如果标签中的style没有设置该属性,获取到的是空字符串。
第二句并不能实现。第一次为空串时,相加结果为10px;第二次点击相加,结果为 10px10px ,非法值。
所以改用offsetLeft / offsetTop
box.style.left = box.offsetLeft + 10 + 'px';
offsetLeft是只读属性,只能读不能设置,所以设置还是要用style.left
setInterval(function () { if(box.offsetLeft>=500){ clearInterval(id); return; } box.style.left = box.offsetLeft + 10 + 'px'; },30);
形成了类似动画效果。
history 前进后退
history.forward();
history.back();
或者用history.go(1) 和 go(-1)
userAgent
记录了设备浏览器相关信息。
可拖拽窗口
鼠标按下时求鼠标在盒子中的位置,= 鼠标在页面上的位置 - 盒子的位置
drop.onmousedown = function (e) { var x = e.pageX - box.offsetLeft; var y = e.pageY - box.offsetTop; document.onmousemove = function (e) { //鼠标在文档中移动 var boxX = e.pageX - x; var boxY = e.pageY - y; box.style.left = boxX + 'px'; box.style.right = boxY + 'px'; } }; drop.onmouseup = function () { document.onmousemove = null; };
onmouseover 和 onmouseenter
前者触发事件冒泡,后者不触发。
onmouseout 与 onmouseleave 同理
bind
ES5中新增方法
新建一个方法,bind中的第一个参数可以改变函数中的this指向
var a = 3; function f() { console.log(this.a); } f(); // 3 var o = {a: 'abc'}; var f1 = f.bind(o); //this指向o f1(); //相当于o.f() //abc
bind并没有调用方法,还需要自己来调用。
call
改变函数的this,并返回一个新的函数 (相较于bind,直接会调用函数)