dom与jq基础使用
js有两种运行环境,一个是浏览器,一个是服务器(NodeJS)
js的本质是es,因为运行环境的不同,为了操作环境内的api做了升级
在浏览器上js分为es + dom + bom
在服务器上js又有另外的功能,这个在NodeJS里讲
dom和bom就是环境自带的东西
在css的dom树里讲过,浏览器把标签解析成一个巨大的对象renderTree
,然后js出现了能操作renderTree的功能,每一个标签都是一个独立的可以被js单独操作的对象
注意:在html的标签,元素,在js叫节点node 都是同个意思,他们是同个东西
就拿把一个按钮的字变成红色来说
原生的js都需要这样几个步骤
指定获取这个按钮,通过什么呢,跟css一样
//这个就是dom对象
document.querySelector("#btn")
//怎么改颜色呢?控制这个dom对象的style属性,这个属性也是一个对象,这个对象存的就是有关样式的资料,有些可以改变,有些是只读属性
document.querySelector("#btn").style.color = "red";
那我怎么知道这个对象里有一个叫style
的属性对象呢
这就是写多了就知道了,那他还有什么属性对象呢?这就是dom元素的调试
按下F12,从左数第4个console就是调试窗口,这个窗口是前端工作者的家
,是最常用的地方
自己写一个有div的页面打开后,打开console,依次输入下面三句js
// 这个只能拿到页面上的一样的标签
document.querySelector("div")
// 把上面的标签转成详细dom对象
console.dir(document.querySelector("div"))
// 上面的简化版,偷懒就这么写
[document.querySelector("div")]
然后打开返回的数据的箭头,你会看到一个特别长的对象格式的数据,里面就有上面说的style属性对象,这样的dom对象一个页面有无数个
我们去重复的写document.querySelector("xxx")是非常的恶心的,而且有个悲伤的故事不得不讲,就是不同的浏览器的dom是不一样的,因为有个叫内核的东西,内核决定了解析效果,如果接触过IE等非chorme浏览器,你就会知道什么叫内核,因为渲染的不同,属性也会不一样,比如在这个浏览器颜色是color,另一个可能叫myColor,当然这只是比喻,导致我本地运行没问题的代码,给不同的用户使用就没效果,然后被领导疯狂的怼,于是有个优秀的团队封装了一个叫jquery
的插件,专门用来操作dom对象,并且做了简化和浏览器内核兼容,简称jq
下面对比原生的js-dom和jq的使用
有很多人的原生js一点都不懂,刚接触就用jq,这是非常不好的
下面的内容不是告诉你jq有多好用,而是原生应该怎么实现jq的方法
大佬对jq的源码解读
元素获取
// jq写法
$("#id")
$(".class")
$("div")
$("[name=xx]")
$("[type=radio]")
$("input[type=radio]:checked")
$("select option:selected")
$("[disabled]")
// jq把获取一个和获取多个都封装进了$()里
// 原生js就要根据自己的情况去选择
// 使用 document.querySelector()
// 还是 document.querySelectorAll()
// 括号里的写法在原生一样适用
通过name取form表单里的带有name的form表单标签
// 比如有个name属性是myform的form标签里有个name属性是name叫nameInp的输入框
document.myform.nameInp //不放在form里是拿不到的
选择多个的第N个
// jq写法
$("div").eq(2)
// 原生js写法
document.querySelectorAll("div")[2]
jq转js,jq的核心就是把节点存进一个数组里
$("#id")[0] 跟 document.querySelector("#id") 是一样的
$(".class")[4] 跟 document.querySelectorAll(".class")[4] 是一样的
// 一旦把jq转成js就不能再使用jq的方法
节点的循环
// jq写法
$("div").each(function(index,node){ ... })
// 原生js写法
var divs = document.querySelectorAll("div")
for(var i=0;i<divs.length;i++){ ... }
元素的样式和属性
window的高度获取
// jq写法
$(window).height();
// 原生js写法
// 含 scrollbar
window.document.documentElement.clientHeight;
// 不含 scrollbar,与 jQuery 行为一致
window.innerHeight;
document的高度
// jq写法
$(document).height();
// 原生js写法
var body = document.body;
var html = document.documentElement;
var height = Math.max(
body.offsetHeight,
body.scrollHeight,
html.clientHeight,
html.offsetHeight,
html.scrollHeight
);
某个元素的高度
// jq写法
$el.height();
// 原生js写法
function getHeight(el) {
var styles = this.getComputedStyle(el);
var height = el.offsetHeight;
var borderTopWidth = parseFloat(styles.borderTopWidth);
var borderBottomWidth = parseFloat(styles.borderBottomWidth);
var paddingTop = parseFloat(styles.paddingTop);
var paddingBottom = parseFloat(styles.paddingBottom);
return height - borderBottomWidth - borderTopWidth - paddingTop - paddingBottom;
}
获得匹配元素相对上一级div的坐标位置
// jq写法
$el.position();
// 原生js写法
el.offsetTop/offsetLeft
获得匹配元素相对body的偏移
// jq写法
$el.offset();
// 原生js写法
function getOffset (el) {
const box = el.getBoundingClientRect();
return {
top: box.top + window.pageYOffset - document.documentElement.clientTop,
left: box.left + window.pageXOffset - document.documentElement.clientLeft
}
}
获取元素滚动条垂直位置
// jq写法
$(window).scrollTop();
// 原生js写法
(document.documentElement && document.documentElement.scrollTop) || document.body.scrollTop;
标签的属性
checked,disabled,placeholder,自定义属性都可以用这个方法
自定义属性在css篇里我说用来储存数据就是这个用法
// jq获取属性
$el.attr("src")
// 原生js获取属性
el.getAttribute("src")
// jq设置属性
$el.attr("data-xx","xx")
// 原生js设置属性
el.setAttribute("data-xx","xx")
// 返回标签上所有data的自定义属性和值,格式是一个对象
el.dataset
// jq删除属性
$el.removeAttr("data-xx")
// 原生js删除属性
el.removeAttribute("data-xx")
// 原生js判断属性
el.hasAttribute("data-xx")
关于单选多选有个注意的点
一般我们默认选中是用 checked="checked" 这是没错的
如果选择是通过鼠标去点击选择或者取消选择,最后用 [xxx]:checked 去取值也是没错的
但是
判断有没有被选中不能通过判断节点是否有 checked 属性
想通过js去选中或者取消选中不能通过添加和移除 checked 属性去实现
复制下面的代码可以知道为什么
<input type="checkbox" checked="checked" id="aa">
document.querySelector("#aa").checked = false
console.log($("#aa").attr("checked"))
//虽然页面显示为选择,但是打印出来的属性还是选中状态,这就是BUG产生的隐患
正确操作如下
// 要判断有没有选中,true是有,false是没有
document.querySelector("#aa").checked
// 选中或者取消选中
document.querySelector("#aa").checked = true/false
form表单元素的值
包括输入框,单选多选,下拉框,大输入框textarea
// jq获取value
$el.val()
// js获取value
el.value
// jq修改value
// 下拉框select传入option的value一样的值会修改选中选项
$el.val(123456)
// js获取value
el.value = 123456
关于下拉框的操作
获取下拉框的值上面提到是value,但是value只是获取被选中的option标签里的value属性的值,那option的内容要怎么获取呢,怎么知道当前下拉框选中的是第几个option呢,怎么去修改当前选中的下拉框的值呢
//获取当前选中的下拉框内容的序号
var index = $('select').selectedIndex
// 所有options的数组
$('select').options
// option的内容
$('select').options[index].text
//选另一个
$('select').options[index].setAttribute("selected","selected")
获取内容html
包括div,p,span等等,图片和表单元素没有这个值
// jq获取html
$el.html()
// js获取html
el.innerHTML
// jq修改html,清空填""
$el.html("<div>123456</div>")
// js修改html,清空等于""
el.innerHTML = "<div>123456</div>"
操作class
// jq添加,移除,有就移除没有就添加
$el.addClass("xxx")
$el.removeClass("xxx")
$el.toggleClass("xxx")
// 原生js添加,移除,有就移除没有就添加
el.classList.add("xxx")
el.classList.removeClass("xxx")
el.classList.toggle("xxx")
插入节点
Append 插入到子节点的末尾
// jq写法
$el.append("<div id='container'>hello</div>");
// 原生js写法
el.insertAdjacentHTML('beforeend', '<div id="container">Hello World</div>');
// 也可以先创建一个标签元素
var newEl = document.createElement("div")
el.appendChild(newEl);
Append 插入到子节点的开头
// jq写法
$el.prepend("<div id='container'>hello</div>");
// 原生js写法
el.insertAdjacentHTML('afterbegin', '<div id="container">Hello World</div>');
// 也可以先创建一个标签元素
var newEl = document.createElement("div")
el.insertBefore(newEl, el.firstChild);
在选中元素前插入新节点
// jq写法
$el.insertBefore("<div id='container'>hello</div>");
// 原生js写法
el.insertAdjacentHTML('beforebegin ', '<div id="container">Hello World</div>');
// 也可以
const el = document.querySelector(selector);
if (el.parentNode) {
var newEl = document.createElement("div")
el.parentNode.insertBefore(newEl, el);
}
在选中元素后插入新节点
// jq写法
$el.insertAfter("<div id='container'>hello</div>");
// 原生js写法
el.insertAdjacentHTML('afterend', '<div id="container">Hello World</div>');
// 也可以
const el = document.querySelector(selector);
if (el.parentNode) {
var newEl = document.createElement("div")
el.parentNode.insertBefore(newEl, el.nextSibling);
}
替换元素
// jq写法
$el.replaceWith("<b>Paragraph. </b>");
// 原生js写法
var newEl = document.createElement("div");
el.parentNode.replaceChild(newEl,el);
移除一个元素
// jq写法
$el.remove()
// 原生js写法
el.parentNode.removeChild(el)
//现在也是可以直接el.remove()的,只是不知道兼容性如何
在html的第一篇里说标签除了属性就是方法,dom节点如何绑定一个方法
让dom响应方法的方式有3种
- 在标签上去添加全局暴露的方法
- 通过选择器添加方法(这个又分为直接赋值和订阅发布)
在标签上去添加全局暴露的方法
关键词是全局
,下面写的所有方法,必须是全局的,如果被私有的作用域保护,是找不到的,什么叫全局的方法,就是window.xx()可以执行的,或者在F12的调试框输入方法名找得到的,这个写法很不安全,因为可以被随意被调用,但是快,简单
<div onclick="click()">点击时</div>
<input type="text" onblur="blur()" oninput="input()" />光标选择时,输入时
<input type="checkbox" onchange="change()" />选中或者取消选中
<input type="file" onchange="change(this.files[0])" />传入文件时
// 讲个特别的,阻止a标签的路径跳转
// 但是为什么要用a标签,还要专门去阻止跳转,这就是傻逼行为
// 知识点 void(0) 就是undefined的意思,很老很装逼的写法
<a href="javascript:void(0)">跳转不了</a>
通过选择器添加方法(这个又分为直接赋值和订阅发布)
先说直接赋值,一个标签的同个方法只能赋值一次,新的会替换掉旧的
//原生js写法,jq没有
document.querySelector(el).onclick = function(){ ... }
document.querySelector(el).onchange = function(){ ... }
window.onscroll = function(){ ... }
window.onload = function(){ ... }
再说说订阅发布
下面的写法不会因为新添加方法移除上一个方法,
添加多少次方法就会执行多少次,会引起多次执行
支持移除,但需要方法名作为标识
//jq写法
//这种写法不支持移除
$el.click(function(){ ... })
$el.change(function(){ ... })
//这种写法可以移除
$el.on("click",functionName)
$el.remove("click",functionName)
//这种写法不能移除,没有标识
$el.on("click",function(){ ... })
// 原生js写法
document.querySelector(el).addEventListener("input",functionName)
document.querySelector(el).removeEventListener("input",functionName)
//这种写法不能移除,没有标识
document.querySelector(el).addEventListener("input",function(){ ... })
虽然上面有很多绑定方法的写法,但是通过id和class等标识去绑定的方式我不是很喜欢,我常用的写法有两种
- 直接把方法写在标签里,方法写成全局的方法
- 创建标签不用字符串,用creatElment,然后把创建好的dom元素直接addEventListener绑定方法
注意
上面的所有的事件绑定都必须保持原标签不改变的前提,一旦标签被父元素innerHTML=""清空,或者本身remove,之后就算再添加一个一样id一样class的标签,他也不是原来的标签了,因为他原本被赋予的方法被删除时已经消失了,需要重新添加方法
dom方法的event对象
任何关于dom元素的方法,他的作用域里都有一个隐藏的叫做event的对象
event的对象有很多种,
最原始的window的onload的Event,
比如输入框失去光标的FocusEvent,
比如键盘按下的KeyboardEvent,
比如鼠标的MouseEvent,
还有手机屏幕滑动的TouchEvent,
等等
$el.click(function(){ console.log(event) })
window.onload = function(){ console.log(event) }
document.querySelector(el).onclick = function(){ console.log(event) }
window.ontouchmove = function(){ console.log(event) }
当给window添加点击事件时认真的去看那个event对象,会发现,event对象里有一个target属性,这个属性里的值就是被鼠标点到的节点,有了这个节点就可以进行节点的判断了,如果点击到的节点的className是aa执行aa方法,如果点到的节点是个img,就如何如何,event就是这样一个俯视节点的上帝的存在,这也是一种绑定事件的方法,叫做事件代理,除了点击事件外,其他事件做不出同样的效果
我用到event的三个地方
- 一是写一个打气球的游戏;
- 还有解决苹果手机ios系统页面不会弹的BUG;
- 手机滑动手势计算
TouchEvent
• clientX:触摸目标在视口中的x坐标。
• clientY:触摸目标在视口中的y坐标。
• pageX:触摸目标在页面中的x坐标。
• pageY:触摸目标在页面中的y坐标。
• screenX:触摸目标在屏幕中的x坐标。
• screenY:触摸目标在屏幕中的y坐标。
事件冒泡和阻止冒泡
在页面上我们会遇到这样的情况,divA有个点击事件A,还有个子元素divB,divB也有个点击事件B,这时鼠标点击B会执行什么事件呢?
点击事件的执行是一种冒泡的模式,从最里面往外面执行,也就是先执行B,然后执行A,但是我们点击B却不想执行A,怎么办
两种方法
一种是把divB从divA里移出来
另一种是阻止冒泡行为,就是在B方法里面写上
function B(){ event.stopPropagation() }
event的其他事件
// 阻止默认行为
event.preventDefault()
// 阻止剩余的事件处理函数执行并且防止事件冒泡到DOM树上
// 这个方法不接受任何参数。
// 例如注册了A、B两个 click 事件,在 A 的方法中阻止后,不会执行 B 的方法
event.stopImmediatePropagation()
dom方法的this对象
每个function都有执行者,function的执行者就是function作用域内的this,这句概念使用在整个js领域,function的执行者就是一个对象,可以是构造对象,可以是dom对象,最常见的是全局对象(全局对象在浏览器端是window对象,在服务器端叫global对象)
上面的几种事件绑定方式
第一种标签绑定事件的默认this是window,需要让标签把自己传过来
<div onclick="aa(this)"></div>
最后一种event.target就是this
其他几种就是直接
function x(){ console.log(this) }
》》其他
这里的内容都很少用到,要么找插件,要么找插件
画布/视频/音频
// 画布api,画布比较常用会单独做一篇
var canvas = document.getElementById("myCanvas");
var cxt = canvas.getContext("2d");
// 视频api
var mp4 = document.getElementById("myVideo");
mp4.onplay = function() { alert("The video has started to play") }
// 音频api
var mp3 = document.getElementById("myAudio");
mp3.onplay = function() { alert("The Audio has started to play") }
还有文件读取fileReader,文件详情DataView,IntersectionObserver是否在可见区域,文件容器FromData,iframe,富文本,拖拽上传,复制上传,地址,摄像头,录音,websocket,打印机
// 文件读取会跟画布做在一期
var fr = new FileReader()
// iframe的高度等于内容的高度
document.querySelector('#iframe').onload = function () {
this.height = this.contentWindow.top.innerHeight + "px";
if(this.contentDocument){
// 不跨域的情况
}else{
// 跨域的情况
this.height = this.contentWindow.top.innerHeight + "px";
this.style.marginLeft = "16px";
document.body.style.overflowX = "hidden";
}
};
// 富文本有相关3个api,会专门总结一期
var selection = window.getSelection();
var range = selection.getRangeAt;
document.execCommand("Copy");
// 拖拽上传
$("#id")
.on("dragover", function (event) {
event.preventDefault();
})
.on("drop", function(event) {
event.preventDefault();
// 数据在event的dataTransfer对象里
let file = event.originalEvent.dataTransfer.files[0];
console.log(file)
// 然后就可以使用FileReader进行操作
// var fr = new FileReader();
// fr.readAsDataURL(file);
// 或者是添加到一个FormData
// let formData = new FormData();
// formData.append("file", file);
})
// 复制上传,查看富文本篇
// IntersectionObserver查看面试题二
后续会继续补充
dom与jq基础使用的更多相关文章
- Dom探索之基础详解
认识DOM DOM级别 注::DOM 0级标准实际并不存在,只是历史坐标系的一个参照点而已,具体的说,它指IE4.0和Netscape Navigator4.0最初支持的DHTML. 节点类型 注:1 ...
- 深入浅出DOM基础——《DOM探索之基础详解篇》学习笔记
来源于:https://github.com/jawil/blog/issues/9 之前通过深入学习DOM的相关知识,看了慕课网DOM探索之基础详解篇这个视频(在最近看第三遍的时候,准备记录一点东西 ...
- DOM操作(基础版)
DOM操作(基础版) DOM是document Object Model的缩写,简称文档对象模型.只要记住这是操作文档的就行了. DOM基础选择器 1.getElementById(id); //获取 ...
- 【JQ基础】DOM操作
内部插入:append() //向每个匹配的元素内部追加内容,可包含 HTML 标签 $(selector).append(function(index,html)) /*•index - 可选.接收 ...
- jQuery源代码解析(1)—— jq基础、data缓存系统
闲话 jquery 的源代码已经到了1.12.0版本号.据官网说1版本号和2版本号若无意外将不再更新,3版本号将做一个架构上大的调整.但预计能兼容IE6-8的.或许这已经是最后的样子了. 我学习jq的 ...
- js基础例子dom+原型+oop基础知识记录01
//oo:概念是计算机中对于现实世界的理解和抽象的方法 //由计算机利用编程技术发展到现在的产物 //面向对象几要素 //对象:由属性和方法组成的集合 //属性:保存数据,存储在对象内存空间中的唯一的 ...
- jq基础
$(function() { $(".dd").attr("class","cc").append("<h ...
- JAVA与DOM解析器基础 学习笔记
要求 必备知识 JAVA基础知识.XML基础知识. 开发环境 MyEclipse10 资料下载 源码下载 文件对象模型(Document Object Model,简称DOM),是W3C组织推荐的 ...
- 《锋利的JQ》摘抄(一) jq基础篇
前言:第一次写博客有点紧张233333,我会在博客里放一下在赌这本书过程中遇到的一些有用的知识点,希望等帮助到大家.好了正题开始(只要是我不知道该说啥了= =) 一,资源(在w3cfuns资源中可以 ...
随机推荐
- PAT T1011 Cut Rectangles
大模拟题,按要求建立多边形,先定位斜边的位置,再分类讨论~ #include<bits/stdc++.h> using namespace std; ; struct node { dou ...
- LeetCode167. Two Sum II - Input array is sorted(双指针)
题意:对于一个有序数组,输出和为target的两个元素的下标.题目保证仅有唯一解. 分析: 法一:二分.枚举第一个元素,二分找另一个元素,时间复杂度O(nlogn),非最优解. class Solut ...
- Languages-used-on-the-Internet
Languages-used-on-the-Internet 1. 互联网上使用的语言 1.1 网站内容语言 1.2 按语言互联网用户 1.3 维基百科文章统计 2. 综合以上表格数据出图表(2019 ...
- 随机游走模型(Random Walk)
给定了一个时间顺序向量\(z_1,...,z_T\),rw模型是由次序r来定义的,\(z_t\)仅取决于前\(t-r\)个元素.当r = 1时为最简单的RW模型. 给定了向量的其他元素,\(z_t\) ...
- Day11 - I - 取石子游戏 HDU - 2516
1堆石子有n个,两人轮流取.先取者第1次可以取任意多个,但不能全部取完.以后每次取的石子数不能超过上次取子数的2倍.取完者胜.先取者负输出"Second win".先取者胜输出&q ...
- Java程序基本优化
1.尽量指定类的final修饰符,因为带有final修饰符的类是不可派生的. 2.尽量重用对象. 3.尽量使用局部变量. 4.不要重复初始化变量. 5.在Java+Oracle的应用系统开发中,Jav ...
- sqlplus导入sql,dmp导入导出
1.创建表空间及用户名 1).用Oracle的EM做数据库的管理(表空间.用户及授权为例子) https://blog.csdn.net/anderslu/article/details/566701 ...
- P3919 【模板】可持久化数组 -初步探究主席树
本篇blog主要是给自己(大家)看的. 感谢longlongzhu123奆佬(此人初二LCT)的指点,使本蒟蒻可以快速开始主席树入门. what is 主席树? $ $主席树这个名字只不 ...
- Numpy中 arange() 的用法
1. 概述Numpy 中 arange() 主要是用于生成数组,具体用法如下: 2. arange()2.1 语法numpy.arange(start, stop, step, dtype = Non ...
- 基于IntelliJ IDEA的代码评审插件 Code Review Plugin
一.阿里规范公约 1.左上角 File -> Settings -> Plugins -> 搜索:Alibaba Java Coding Guidelines,安装插件并重启IDEA ...