var obj = {
"0":'a',
"1":'b',
"2":'c',
"length":3,
"push":Array.prototype.push, //引入数组的push功能
"splice":Array.prototype.splice
}
可以动态的增长length属性
执行obj.push('d');
obj对象就会引入一个属性”3”:’d’,且length变为4
如果再加上"splice":Array.prototype.splice
属性,此对象会以数组的形式显现,但仍然是对象。
类数组定义:属性要为索引(数字)属性,必须有length属性,最好加上push方法,是对象,且可以当数组一样用。
类数组的关键点在于length,push内部原理为:
Array.prototype.push = function (target){
obj[obj.length] = target;
obj.length ++;
}
var obj = {
"0":"a",
"1":"b",
"length":2,
"push":Array.prototype.push
}
obj.push('c');
obj.push('d');
/*
obj = {
"0":"a",
"1":"b",
"2":"c",
"3":"d",
"length":4
}*/
let obj = {
0:"huawei",
1:"xiaomi",
2:"meizu",
length:3,
push:Array.prototype.push
}
console.log(obj);
let arr1= Array.from(obj);
console.log(arr1);
文档对象模型(Document Object Model),是W3C组织推荐的处理可扩展置标语言的标准编程接口。简单理解就是HTML DOM 是关于如何获取、修改、添加或删除 HTML 元素的标准。我们用JavaScript对网页进行的所有操作都是通过DOM进行的。
document.getElementById('id')
<div id="box"></div>
<script>
let box= document.getElementById("box");
</script>
document.getElementsByClassName('box');
注意:该方法获取的是一个集合
<div class="box"></div>
<div class="box"></div>
<script>
let boxCollection= document.getElementsByClassName("box");
let box1 = boxList[0];
let box2 = boxList[1];
</script>
document.getElementsByName('name')
注意:只有含有name属性的元素(表单元素)才能通过name属性获取
document.getElementsByTagName('p');
注意:该方法获取的是一个集合
<div id="box">
<p>段落1</p>
<p>段落2</p>
<p>段落3</p>
<p>段落4</p>
<p>段落5</p>
<p>段落6</p>
</div>
<script>
let pCollection= document.getElementsByTagName("p");
</script>
- document.documentURI
可以获取当前页面的URL地址document.documentElement
是专门获取html这个标签
<div id="box">
<ul class="list">
<li class="item"></li>
<li class="item"></li>
<li class="item"></li>
<li class="item"></li>
<li class="item"></li>
<li class="item"></li>
</ul>
</div>
<script>
let box= document.querySelector("#box > .list");
</script>
<div class="box">box1</div>
<div class="box">box2</div>
<div class="box">box3</div>
<div class="box">box4</div>
<div class="box">box5</div>
<script>
let box1= document.querySelector(".box");
let boxes= document.querySelectorAll(".box");
</script>
注意:querySelector()和querySelectorAll()方法括号中的取值都是css选择器,但从图中我们可以看出,两个方法是有区别的。当有多个class相同的元素时,使用querySelector()方法只能获取到第一个class为box的元素,而querySelectorAll()获取到了所有class为box的元素集合。
// 获取集合中的第一个元素
console.log(lis[0]); // 索引
console.log(lis.item(0)); // 方法
// 遍历元素集合
lis.forEach(item => console.log(item))
所有获取DOM对象的方法中,只有getElementById()
和querySelector()
这两个方法直接返回的DOM对象本身,可直接为其绑定事件。其余获得都可能是一个元素集合。
常用的节点类型
节点类型 | 例子 |
---|---|
元素节点 | <div>, <input> |
属性节点 | type,src,class,id |
文本节点 | 空格元素中文字等 |
html 结构如下:
<div class="box">
<ul class="list">
<li class="item">item1</li>
<li class="item">item2</li>
<li class="item">item3</li>
<li class="item">item4</li>
<li class="item">item5</li>
<li class="item">item6</li>
</ul>
</div>
但注意的是,他们获取的节点包括文本节点和元素节点,如果我们只获取元素节点,需要使用下面一组遍历元素节点树来获取。
let li = document.querySelector("li");
// 获取li的父节点ul
let ul = li.parentNode;
// 获取ul的父节点div.box
let box = ul.parentNode;
let ul = document.querySelector("ul");
// 获取ul节点的子节点们
console.log(ul.childNodes)
firstChild //获取所选节点的第一个子节点
lastChild //获取所选节点的最后一个子节点
nextSibling //获取所选节点的后一个兄弟节点 列表中最后一个节点的nextSibling属性值为null
previousSibling //获取所选节点的前一兄弟节点 列表中第一个节点的previousSibling属性值为null
我们一般用下列这些来获取相应的元素节点。
let ul = document.querySelector("ul");
console.log(ul.childElementCount); // 6
cosnole.log(ul.children.length); // 6
let li = document.querySelector("li");
console.log(li.parentElement);
let ul = document.querySelector("ul");
console.log(ul.children);
let ul = document.querySelector("ul");
console.log(ul.firstElementChild);
let ul = document.querySelector("ul");
console.log(ul.lastElementChild);
nextElementSibling //返回的是后一个兄弟元素节点
let li3 = document.querySelector("ul li:nth-of-type(3)");
console.log(li3.nextElementSibling);
previousElementSibling //返回的是前一个兄弟元素节点
let li3 = document.querySelector("ul li:nth-of-type(3)");
console.log(li3.previousElementSibling);
document.querySelector("ul li:nth-of-type(3)").textContent;
document.querySelector("ul li:nth-of-type(3)").textContent = "我是第三个节点";
document.querySelector("ul li:nth-of-type(4)").innerText;
document.querySelector("ul li:nth-of-type(4)").innerText = "我是第四个节点";
注意:前两个只能设置元素节点的文本,如果其实含有HTML标签,将不能被解析出来原样显示在标签中。
let li3 = document.querySelector("ul li:nth-of-type(3)");
let li4 = document.querySelector("ul li:nth-of-type(4)");
li3.textContent = "<em>强调</em>";
li4.innerText = "<em>强调</em>";
于是我们需要使用innerHTML来设置渲染含有HTML的字符串
let li3 = document.querySelector("ul li:nth-of-type(3)");
let li4 = document.querySelector("ul li:nth-of-type(4)");
li3.innerHTML = "<em>强调</em>";
li4.innerHTML = "<em>强调</em>";
document.querySelector("ul li:nth-of-type(3)").outerHTML = "<em>强调</em>";
value:可以获取表单元素中的value值(jq:val())
<input type="text" value="用户名">
<script>
let input = document.querySelector("input");
// 获取表单的值
console.log(input.value); // 用户名
// 设置表单的值
input.value = 'value的值';
</script>
原生 javascript 可以通过 HTML DOM 的 getAttribute() 方法获取DIV元素属性的值,修改DIV元素中的指定属性的值,可以使用 setAttribute() 方法,使用 removeAttribute() 方法来删除DIV元素中的属性
getAttribute()
获取属性 .getAttribute(“属性”)
<div id="mochu" title="标题"></div>
<script>
var title = document.getElementById('mochu').getAttribute('title');
console.log(title); // 标题
</script>
setAttribute()
设置属性 .setAttribute(“属性”,”值”)
<div id="mochu" title="这里的值会被改变成网址"></div>
<script>
document.getElementById('mochu').setAttribute('title','http://www.zhsh520.com');
</script>
removeAttribute()
删除属性 .removeAttribute(‘属性名’)
<div id="mochu" title="hello word!"></div>
<script>
document.getElementById('mochu').removeAttribute('title');
</script>
HTML 5 允许用户为元素自定义属性,但要求添加 data- 前缀,目的是为元素提供与渲染无关的附加信息,或者提供语义信息。<div id="box" data-myid="12345" data-myname="zhangsan" data-mypass="zhang123" data-my-age="18">自定义数据属性</div>
添加自定义属性之后,在 JavaScript 中可以通过元素的 dataset 属性访问自定义属性。dataset 属性的值是一个 DOMStringMap 实例,也就是一个名值对的映射。在这个映射中,每个 data-name 形式的属性都会有一个对应的属性,只不过属性名没有 data- 前缀。
let div = document.getElementById("box");
//访问自定义属性值
let id = div.dataset.myid;
let name = div.dataset.myname;
let pass = div.dataset.mypass;
// 注意 data-my-age我们直接通过dataset.my-age获取是不行的
// 多个单词需要将转换为驼峰式
let age = div.dataset.myAge;
//设置自定义属性值(存在该属性则为修改,没有则为添加自定义属性)
div.dataset.myid = "66666";
div.dataset.myname = "zhangsan";
div.dataset.mypass = "zhangsan666";
1.1 createElement
createElement通过传入指定的一个标签名来创建一个元素,如果传入的标签名是一个未知的,则会创建一个自定义的标签var div = document.createElement("div");
使用createElement要注意:通过createElement创建的元素并不属于html文档,它只是创建出来,并未添加到html文档中,要调用appendChild或insertBefore等方法将其添加到HTML文档树中;
// 创建DOM元素
let div = document.createElement("div");
let span = document.createElement("span");
// 添加文本
span.textContent = "hello world!";
// 添加元素
div.append(span); // 先将span添加到div中
document.body.append(div); // 添加到body中
// 注意:这里的创建的元素,只能添加一次,相当于剪切。
1.2 createTextNode
createTextNode用来创建一个文本节点,用法如下var textNode = document.createTextNode("一个TextNode");
createTextNode接收一个参数,这个参数就是文本节点中的文本,和createElement一样,创建后的文本节点也只是独立的一个节点,同样需要append Child将其添加到HTML文档树中
1.3 cloneNode
cloneNode是用来返回调用方法的节点的一个副本,它接收一个bool参数,用来表示是否复制子元素,使用如下:
var parent = document.getElementById("parentElement");
var parent2 = parent.cloneNode(true);// 传入true
parent2.id = "parent2";
这段代码通过cloneNode复制了一份parent元素,其中cloneNode的参数为true,表示parent的子节点也被复制,如果传入false,则表示只复制了parent节点
<div class="box">
<ul class="fruit">
<li class="item">香蕉</li>
<li class="item">苹果</li>
<li class="item">西红柿</li>
<li class="item">榴莲</li>
</ul>
<br>
<ul class="vegetables">
<li class="item">芹菜</li>
<li class="item">萝卜</li>
<li class="item">黄瓜</li>
</ul>
</div>
有如上结构的html,我们可以看出,西红柿不属于水果,我们需要将其移动到蔬菜列表汇总,如何操作:
// 获取西红柿
let xi = document.querySelector(".fruit li:nth-of-type(3)");
// 获取蔬菜列表
let vegetables = document.querySelector(".vegetables");
// 移动西红柿到蔬菜列表中
vegetables.append(xi);
但是,西红柿也可以属于水果也可以属于蔬菜,我们该如何操作呢
// 获取西红柿
let xi = document.querySelector(".fruit li:nth-of-type(3)");
// 获取蔬菜列表
let vegetables = document.querySelector(".vegetables");
// 复制西红柿到蔬菜列表中
vegetables.append(xi.cloneNode(true));
1.4 createDocumentFragment
createDocumentFragment方法用来创建一个DocumentFragment。在前面我们说到DocumentFragment表示一种轻量级的文档,它的作用主要是存储临时的节点用来准备添加到文档中
createDocumentFragment方法主要是用于添加大量节点到文档中时会使用到。假设要循环一组数据,然后创建多个节点添加到文档中
<input type="button" value="添加多项" id="btnAdd" />
document.getElementById("btnAdd").onclick = function() {
const list = document.createElement("ul");
for (var i = 1; i <= 100; i++) {
var li = document.createElement("li");
li.textContent = `item${i}`;
list.style.color = "red";
list.appendChild(li);
}
document.body.appendChild(list);
}
这段代码将按钮绑定了一个事件,这个事件创建了100个li节点,然后依次将其添加HTML文档中。这样做有一个缺点:每次一创建一个新的元素,然后添加到文档树中,这个过程会造成浏览器的回流。所谓回流简单说就是指元素大小和位置会被重新计算,如果添加的元素太多,会造成性能问题。
这个时候,就是使用createDocumentFragment了DocumentFragment不是文档树的一部分,它是保存在内存中的,所以不会造成回流问题。我们修改上面的代码如下
document.getElementById("btnAdd").onclick = function(){
var list = document.getElementById("list");
var fragment = document.createDocumentFragment();
for(var i = 0;i < 100; i++){
var li = document.createElement("li");
li.textContent = i;
fragment.appendChild(li);
}
list.appendChild(fragment);
}
优化后的代码主要是创建了一个fragment,每次生成的li节点先添加到fragment,最后一次性添加到list
需要注意下面几点:
<div id="box">
<ul class="list">
<li class="item">item1</li>
<li class="item">item2</li>
<li class="item">item3</li>
<li class="item">item4</li>
<li class="item">item5</li>
</ul>
</div>
<script>
let ul = document.querySelector("#box > .list");
// 1. 创建元素
const li = document.createElement('li');
// 2. 添加元素
ul.appendChild(li);
// 3.添加节点内容
li.innerHTML = "item6";
// ----直接添加html模板字符串------
let htmlStr = `<li style="color: pink">item7</li>`;
// 将HTML字符串直接解析为DOM元素
ul.insertAdjacentHTML('beforeEnd', htmlStr);
// 也可以添加createElement创建的元素
// afterBegin 添加到开头 beforeEnd添加到末尾
// ul.insertAdjacentElement("afterBegin",li);
//------批量添加使用文档片段完成------
// const frag = document.createDocumentFragment();
const frag = new DocumentFragment();
for (let i = 1; i < 5; i++) {
// 创建元素
const li = document.createElement('li');
// 设置元素内容
li.textContent = `item${i+7}`;
// 设置元素样式
li.style = "color:green";
// 将生成的节点临时挂载到文档片段中
frag.appendChild(li);
}
ul.appendChild(frag);
</script>
前面我们提到创建型api,它们只是创建节点,并没有真正修改到页面内容,而是要调用appendChild来将其添加到文档树中。我在这里将这类会修改到页面内容归为一类。
2.0 append(ele,”text”) 子元素结尾添加
此方法用于以Node对象或DOMString(基本上是文本)的形式添加元素。
const parent = document.createElement('div');
const child = document.createElement('p');
parent.append(child);
parent.append("文本");
// 这会将子元素追加到div元素
// 然后div看起来像这样<div> <p> </ p> 文本 </ div>
prepend(ele,”text”) 子元素开头添加
const parent = document.createElement('div');
const child = document.createElement('p');
child.textContent = "我是一个段落";
parent.prepend(child);
parent.prepend("文本");
parent.prepend(child.cloneNode(true));
// 这会将子元素追加到div元素
/*然后div看起来像这样
<div>
<p>我是一个段落</ p>
文本
<p>我是一个段落</ p>
</ div>
*/
before() 在参照节点之前插入
let li3 = document.querySelector("li:nth-of-type(3)");
let li = document.createElement('li');
li.textContent = "在参照节点之前插入";
li.style.background = "red";
li3.before(li);
after() 在参照节点之后插入
let li3 = document.querySelector("li:nth-of-type(3)");
let li = document.createElement('li');
li.textContent = "在参照节点之后插入";
li.style.background = "pink";
li3.before(li);
2.1 appendChild(追加为子元素)
appendChild我们在前面已经用到多次,就是将指定的节点添加到调用该方法的节点的子元素的末尾。调用方法如下:parent.appendChild(child);
child节点将会作为parent节点的最后一个子节点
appendChild这个方法很简单,但是还有有一点需要注意:如果被添加的节点是一个页面中存在的节点,则执行后这个节点将会添加到指定位置,其原本所在的位置将移除该节点,也就是说不会同时存在两个该节点在页面上,相当于把这个节点移动到另一个地方
注意:appendChild与 .append 方法类似,该方法用于DOM中的元素,但在这种情况下,只接受一个Node对象。
<div id="child">
要被添加的节点
</div>
<br/><br/><br/>
<div id="parent">
要移动的位置
</div>
<input id="btnMove" type="button" value="移动节点" />
<script>
document.getElementById("btnMove").onclick = function(){
var child = document.getElementById("child");
document.getElementById("parent").appendChild(child);
}
</script>
这段代码主要是获取页面上的child节点,然后添加到指定位置,可以看到原本的child节点被移动到parent中了。
这里还有一个要注意的点:如果child绑定了事件,被移动时,它依然绑定着该事件
2.2 insertBefore(插入前面)
insertBefore用来添加一个节点到一个参照节点之前,用法如下parentNode.insertBefore(newNode,refNode);
<div id="parent">
父节点
<div id="child">子元素</div>
</div>
<input type="button" id="insertNode" value="插入节点" />
<script>
var parent = document.getElementById("parent");
var child = document.getElementById("child");
document.getElementById("insertNode").onclick = function(){
var newNode = document.createElement("div");
newNode.textContent = "新节点"
parent.insertBefore(newNode,child);
}
</script>
2.3 removeChild(删除子元素)
removeChild用于删除页面中的元素节点,用法如下:let oldChild = node.removeChild(child);
child 是要移除的那个子节点.
node 是child的父节点.
oldChild保存对删除的子节点的引用. oldChild === child.
// 先定位父节点,然后删除其子节点
var d = document.getElementById("top");
var d_nested = document.getElementById("nested");
var throwawayNode = d.removeChild(d_nested);
// 无须定位父节点,通过parentNode属性选择父元素直接删除自身
var node = document.getElementById("nested");
if (node.parentNode) {
node.parentNode.removeChild(node);
}
// 移除一个元素节点的所有子节点
var element = document.getElementById("top");
while (element.firstChild) {
element.removeChild(element.firstChild);
}
// ele.remove(没有参数)可以删除自己(自毁)
2.4 replaceChild(替换子元素)
replaceChild用于使用一个节点替换另一个节点,用法如下parent.replaceChild(newChild,oldChild);
newChild是替换的节点,可以是新的节点,也可以是页面上的节点,如果是页面上的节点,则其将被转移到新的位置,oldChild是被替换的节点
// 将第三个li替换为h3标签元素
let h2 = document.createElement('h2');
h2.textContent = "我是替换元素h2";
document.querySelector("ul").replaceChild(h2,document.querySelector("li:nth-of-type(2)"));
// repaceWith()替换当前元素
let h3 = document.createElement('h3');
h3.textContent = "我是替换元素h3";
document.querySelector("li:nth-of-type(3)").replaceWith(h3);
不管是新增还是替换节点,如果新增或替换的节点是原本存在页面上的,则其原来位置的节点将被移除,也就是说同一个节点不能存在于页面的多个位置,节点本身绑定的事件也不会消失,会一直保留着。
2.5 insertAdjacentElement(‘插入位置’,节点)
插入位置有四个:
let ul = document.querySelector('ul');
// 插入第一个子元素之前(在起始标签之后)
const li = document.createElement('li');
li.textContent = "第一个子元素";
ul.insertAdjacentElement('afterBegin',li);
// 将div插入到整个ul的前面,也就是前一个兄弟节点
const div = document.createElement('div');
div.style.width = "60px";
div.style.height = "60px";
div.style.background = "red";
ul.insertAdjacentElement('beforeBegin',div);
此方法还有一个plus版insertAdjacentHTML(),可以直接使用html字符串当元素来插入到相应位置
// 追加到ul的结尾
ul.insertAdjacentHTML('beforeEnd','<li style="color: pink">最后一个子元素</li>');
还可以直接插入文本 insertAdjacentText()
const h2 = document.createElement('h2');
h2.insertAdjacentText('beforeEnd',"我是一个大标题");
console.log(h2); // <h2>我是一个大标题</h2>
3.1 getAttribute() (获取属性)
getAttribute()用于获取元素的attribute值
node.getAttribute('id');
//表示获取node元素的id属性的 ‘值’
3.2 createAttribute() (创建属性)
createAttribute()方法生成一个新的属性对象节点,并返回它。
attribute = document.createAttribute(name);
// createAttribute方法的参数name,是属性的名称。
3.3 setAttribute() (设置属性)
setAttribute()方法用于设置元素属性
var node = document.getElementById("div1");
node.setAttribute(name, value);
//name为属性名称 ;value为属性值
// 例如
var node = document.getElementById("div1");
node.setAttribute("id", "ct");
// 等同于
var node = document.getElementById("div1");
var a = document.createAttribute("id");
a.value = "ct";
node.setAttributeNode(a);
3.4 romoveAttribute() (删除属性)
removeAttribute()用于删除元素属性node.removeAttribute('id');
3.5 element.attributes(将属性生成数组对象)
// 获取文档的第一个 <p> 元素
var para = document.getElementsByTagName("p")[0];
//获取该元素属性(多个属性会形成一个数组对象)
var atts = para.attributes;
const p = document.querySelector('p');
p.style.color = 'red';
p.style.fontSize = "30px";
console.log(p)
// <p style="color: red; font-size: 30px;">我是一个段落</p>
className是类别选择器的名字,使用这个className可以进行动态更改某个标签的类的属性值。
// 直接修改元素的类名,多个以空格隔开
p.className = 'one content';
使用元素的 classList 属性可以访问或添加、删除及修改元素的 class 属性。
.cred {
color: red;
}
.cpink {
color: pink;
}
.cgreen {
color: green;
}
.f32{
font-size: 32px;
}
<ul>
<li>item1</li>
<li>item2</li>
<li>item3</li>
</ul>
<input type="button" value="切换">
const ul = document.querySelector('ul');
// 一个子元素
const firstLi = ul.firstElementChild;
// 最后一个子元素
const lastLi = ul.lastElementChild;
// 添加class类
firstLi.classList.add('cgreen', 'f32');
lastLi.classList.add('cpink');
// 移除class类
firstLi.classList.remove('f32');
// 替换class 类
lastLi.classList.replace('cpink', 'cred');
// 切换类样式(没有则添加,有则移除)
// 点击按钮切换item1的类样式
const btn = document.querySelector("input[type='button']");
btn.addEventListener('click', function() {
firstLi.classList.toggle('f32')
})
一个元素最终应该渲染成什么样式,有浏览器来决定。
浏览器根据一个元素的行内元素,内部元素,外部样式表来计算出最终的样式
第一个参数是要查看的元素,第二个参数是伪元素
let styles = window.getComputedStyle(p,null);
// 计算样式都是只读的
console.log(styles.getPropertyValue('height'));
console.log(styles.getPropertyValue('font-size'));