jQuery是构造函数吗?
- 可以说是,因为确实构造出了对象提供了各类方法
- 也可以说不是,因为正常情况的构造函数是 new Function一个对象
链式风格就是jQuery风格
基本概念
- jQuery对象指的是由jQuery构造函数构造出来的对象
- Object对象表示Object构造函数构造出来的对象
重要理解
- 用到fisrtchild children之类的api都会把文本节点算在内,(空格,换行都算)
- 自己灵活的多敲.去查看节点的api列表中选择children childNodes firstElementChild firstChild 之类的多尝试即可
- 很多dom api使用时都要搞清是在父节点还在自己节点操作,使用时遇到问题直接mdn
- 遍历node.children时,如果涉及到remove之类的操作,children.length会变,意味着传统的for循环是不行的
- 因为你想顺着index去取arr[0] arr[1]... 但是length也在变化,因此应该每次都取arr[0]才能顺利遍历才对
DOM操作只要是在appendChild之后的操作,都是跨线程的,也就是会直接影响页面渲染,渲染引擎
元素的attributes是指能够挂载在页面上的properties
- properties是存在于JS线程中(JS引擎中) attributes是存在于渲染引擎中的
- attributes指的是渲染到页面上标签具有的那些属性比如 class id title
- properties则指的是你console.dir打印一个element对象的全部完整属性
- attributes只支持字符串
- properties支持布尔等类型
实例深刻体会一下
console.dir(test);
// 可以顺利在这个元素的结构上看到id class title 与dataset
// 但非标准属性xxxxxx不存在,由此可见通过写在标签上的非标准属性是不会作用到properties的
test.x123=100;
console.dir(test); // 同时如果你试图在console中这么做的话,确实可以让非标准属性挂在test对象身上
// 但依旧不会出现在渲染的html页面中
console.log(typeof test1.disabled) // boolean
// 你可以console.dir(test1) 发现此元素的disabled:true
id.可直接操纵元素
- idxxx.style.xxx 可直接操纵的原因是写有id='idxxx'的元素被直接挂在window上
- 但有些js关键字比如parent,就不适合做id,因为这本身就是挂在window上的,你无法直接parent.去操纵了
查询元素只用document.querySelector/All
获取特定元素
- document.documentElement
- 获取< html >元素及其中内容
- document.head
- 获取head
- document.body
- 获取body
- document.all
- 获取所有元素,这可以被理解为是一个奇葩,这可以算是第六个falsy值
Boolean(document.all)// false
- window
- window可不是标签/元素,window只是窗口,获取这个有时候可以window.onclick=()=>{console.log('hi')})
获取元素身上的API
console.dir(document.documentElement)
Element有着一根很长的原型链
- < html element >---HTMLHtmlElement---HTMLElement---Element---Node---EventTarget---Object
- 可以看到< html element >后面跟着6个原型,每一层原型都具有大量的API
- Element可以分为xml html
- Node大致可分为1:Element 3:Text 8:Comment 9:Document
- 我们可以看到Element构造函数会往this(也就是即将创建的对象身上)加id
// 敲一下以下代码
let div=document.querySelector('#div123')
console.log(div.nodeType)
console.log(div.childNodes[0].nodeType)
DOM增删改查
增加一个标签节点
let div=document.createElement('div')
text1=document.createTextNode('你好')
div.appendChild(text1) // 方式1
div.innerText='你好' // 方式2
克隆一个标签节点
let div=document.createElement('div')
let div1=div.cloneNode(true); // true为深拷贝
移除节点 remove
- 移除不等于删除
- 移除只是移出来
你要移除的节点.parentNode.removeChild(你要移除的节点) // 方式1
你要移除的节点.remove(); // 方式1 推荐
删除节点 节点=null
- 节点=null
修改节点属性 比如id class src 等等
节点.className = 'blue';
//如果你要增加一个class你必须 追加
节点.className += ' red'; // 这里有一个空格的,不然就和blue连在一起了
// 新api classList
节点.classList.add('blue')
节点.classList.add('red')
// 修改style样式
节点.style['background-color']='red'; // 成立
节点.style.backgroundColor='blue'; // 成立
设置与读取自定义属性
- 元素上的属性分三类
- 标准属性class...
- data属性data-x...
- 非标准属性x...
- 这一部分内容就记住node.setAttribute() / getAttribute()这两个API是通解
- 修改data属性用node.dataset.xxx
- div123.id/ className/style 这种方式读取或者修改 √
- div123.非标准属性x 这种方式去读取或者修改 ×
// 设置属性
节点.setAttribute('xxx',123) // 方式1 非标准属性xxx
节点.setAttribute('data-xxx',123) // 方式2 data属性data-xxx
节点.dataset.xxx = '123' // 方式3
// 读取属性
节点.getAttribute('xxx'/'data-xxx') // 这种读取方式不论读取 xxx还是data-xxx都可行
节点.dataset.xxx // 只能读取data-xxx
// 修改data属性
节点.dataset.xxx = ...
// 注意,这种方式修改非标准属性是行不通的
节点.xxx= 你想赋的值 // 这是做不到的
HTML节点上的自定义属性这一块内容比较复杂,一起跟着敲一下例子
div123.setAttribute('non-dataset',123);
console.log(div123); // 可以看到这种非标准自定义属性是ok的
div123.setAttribute('data-123',234);
console.log(div123); // 可以看到这标准自定义属性是ok的
div123.dataset.xxx = 345;
console.log(div123); // 可以看到此方式也可以自定义属性
div123.dataBBB=101;
console.log(div123); // 可以看到此方式是不可以的
读取a标签的href属性
a123.href // 会被浏览器动手脚
a123.getAttribute('href') // 这才确保所得的是你想要的
事件处理函数
每个node自己都有类似onclick这样的事件对象,只不过一开始都是null
以下代码点击此处
console.log(div123.onclick) // null
console.dir(div123) // 可以观察到div123这个对象上是有onclick属性的
//要注意的是
div123.onclick() //这种方式在console中敲入的也可以触发onclick事件
// 但是这样子是获取不到event参数的
// 只有当用户去点击div123这个元素了浏览器才会传递event参数,当然这个传递是隐式传递而非用户可见
div123.onclick=function(x){
console.log(this);
console.log(x);
};
// 为什么在里面this是指向div123?
// 第一种理解,因为onclick事件是由div123调用的 div123.onclick
// 第二种理解: div123.onclick() ======被JS转化成====> div123.onclick.call(div123,event)
改内容
改文本内容
div.innerText=
div.textContent=
改HTML内容
div.innerHTML=
改标签
div.innerHTML='' // 清空
div.appendChild(div1) // 再追加
为本元素修改父节点
newParentNode.appendChild(div) // div这个节点会直接从现在的地方消失去到新的父节点下面
查看元素的节点
node.parentNode node.parentElement // 查爸爸
node.parentNode.parentNode // 查爷爷
node.childNodes // 查子节点 注意 就算是空格 换行也都会算在childNodes数目中 因为是node的计算
node.children // 符合人类的直觉
// 敲一下以下的代码
parentDiv.childNodes // 可以看到数组中包含七个元素
// 并且不论空格回车还是文本123 都算作nodeType:3 都是text类型的node
childDiv1.childNodes // 可以看到值是一个空格 这是符合预期的
childDiv2.childNodes // 可以看到值是一个空格后面是换行符再是多个空格 这是符合预期的
childDiv3.childNodes // 可以看到值是一个换行符再是多个空格 这是符合预期的
parentDiv.children.length // 3
查兄弟姐妹
node.parentNode.childNodes // 查找得到父节点下的所有子节点,因此还需排除自己
node.parentNode.children // 查找得到父节点下的所有子节点,因此还需排除自己
查第一个/最后一个节点
node.firstChild / lastChild // 注意 这会查找到text文本节点哦
node.firstElementChild / lastElementChild // 这只会查找到element节点
查找比自己大一点的兄弟节点
node.previousSibling / nextSibling // 注意 这会查找到text文本节点哦
node.previousElementSibling / nextElementSibling // 这只会查找到element节点
获取元素节点的长度(有坑,无法自动获取更新)
- 这里算是一个避坑,某些写法会引起length不会实时更新
- 这里列举了三种方式获取长度然后进行remove操作再获取一下长度
方式1: 每次都重新获取长度 这是肯定对的
// 每次都重新获取长度的方式 如下
// 初次获取
document.querySelectorAll('div').length // 6
parentDiv.childNodes.length // 7
parentDiv.children.length // 3
childDiv1.remove() // 删一个节点
// 再次获取
document.querySelectorAll('div').length // 5
parentDiv.childNodes.length // 6
parentDiv.children.length // 2
方式2: 存一下.length前的对象 这就有问题了
// 存一下.length前的对象 如下
// 初次获取
let a=document.querySelectorAll('div')
console.log(a.length) // 6
let b=parentDiv.childNodes
console.log(b.length) // 7
let c=parentDiv.children
console.log(c.length) // 3
childDiv1.remove() // 删一个节点
// 再次获取
console.log(a.length) // 6 可以看到此方式预先存一下对象之后,.length也不会自动更新
console.log(b.length) // 6 但是下面两种方式是可以的
console.log(c.length) // 2
利用数据结构遍历一个div里的所有元素
详解:为什么说dom操作是跨线程的, 以及如何影响的?
- 只要dom操作是发生在appendChild这类挂载元素操作前的,就不会影响,在appendChild之后的,那肯定会影响渲染线程
- 每个浏览器有两个引擎: 渲染引擎和 JS执行引擎
- 这两个引擎分别在不同的线程中,两者互不相干,并且各司其职
- JS引擎不能操纵页面只能操作JS
- 渲染引擎不能操作JS只能操纵页面
- 效率低在于浏览器需要付出时间去感知变化再修改
- 在div1放入页面之前指的是:node.appendChild()这样的操作
- node.appendChild()之前也就是说元素还未挂载到页面上,所有操作都是JS引擎内部发生的
- 浏览器修改页面时也就是渲染时,才会用到渲染引擎
- 元素已经挂载到页面后,如果对element.id element.title进行修改的话也可能引起对页面的重新渲染((JS修改=>渲染引擎再次触发)
// 在上面实例敲入以下代码以体会什么叫修改id可能会影响渲染引擎
id4test1.id='id4test';
// 在上面实例敲入以下代码以体会什么叫修改title也会重新影响渲染引擎
div123.title='我在修改title,也会影响页面渲染'
transition过渡期动画时的例子
transition接连两句的时候浏览器会自动合并 不产生过渡效果,但是你办当中读一下相关属性的话他就会分开执行
- 除非你中间有强制要求分开渲染的操作
jQuery的设计模式