2.2注册事件处理程序
摘要:
有两种事件处理程序的方式。第一种是web早期就有的,及设置作为事件的对象或文档元素的一个属性。第二种方法是把处理程序传给这个元素或对象或元素的addEventLIstener()方法。
设置事件处理程序属性:JavaScript
注册时间处理程序最简单的方式就是把事件目标的一个属性设置为关联的事件处理程序函数。按照惯例,事件处理程序属性的名字都有“on”和事件名称组成,比如:onclick、onchange、onload、onmousemove、等等。注意,这些属性名是区分大小写的,必须全部小写,即便事件类型包含多个单词(如:“mousedown”)。以下代码包含两个以这种方式注册事件处理程序的地方:
//设置window对象的onload属性为一个函数 //这个函数式事件处理程序:他会在文档加载完成时被调用 window.onload = function(){ let form = document.querySelector("form#shipping") form.onsubmit = function(event){ if(!isFormValid(this)){ event.preventDefault() } } }
设置事件处理程序属性:HTML
文档元素的事件处理程序属性也可以直接在HTML文件中作为对应的HTML标签的属性来定义(在JavaScript中注册在window元素上的处理程序在HTML中可以定义为<body>标签的属性)。现在web开发中通常不提倡这种技术,但他们是可能的。之所以在这里记录下来,是因为你仍然有可能在已有的代码中看到她们。
在使用HTML属性定义事件处理程序是时,属性的值应该是一段Javascript代码字符串。这段代码应该是事件处理程序函数的函数体,不是完整的函数声明。换句话说,HTML事件处理程序的代码应该没有外围的大括号,前面也没有function关键词,例如:
<button onclick="console.log('1234')">点击我</button>
如果一个HTML事件处理程序属性包含多条JavaScript语句,则必须用分号分隔这些语句,或者用回车把这个属性值分成多行。
再给HTML事件处理程序包含多条JavaScript语句,则必须用分号分割这些语句,或者用回车把这个属性值分成多行。
在给HTML事件处理程序属性JavaScript代码字符串时,浏览器会把这个字符串转寒成为一个函数。
这个event参数意味着你的处理程序代码可以通过他引用当前的时间对象。而with语句意味着你的处理程序可以直接引用目标对象、外层<form>,乃至document对象的属性,就像他们都是作用于内的变量一样。严格模式下是禁止使用with语句的,但html属性中的JavaScript代码没有严格这一说。这样定义的事件处理程序将在一个可能存在意外变量的环境中执行,因此可能是一些讨厌的bug的来源,也是避免在HTML中编写事件处理程序的一个充分理由。
addEventListener()
任何可以作为事件目标的对象(包括Window和document对象以及所有的文档元素),都定义了一个名为addEventListener()方法,可以使用他来注册目标为调用对象的事件处理程序。addEventListener()接收三个参数。第一个参数时注册处理程序的事件类型。类型函数(或名称)是一个字符串,不包含作为HTML元素属性使用时的前缀“on”。第二个参数时当指定类型的事件发生时调用的函数。第三个参数是可选的,下面会介绍。
以下代码在一个<button>元素上为“click”时间上注册了两个事件处理程序。注意这里使用的两种技术的差异:
<body> <form action="" id="shipping"> <button id="mybutton">点击我</button> </form> <p></p> </body> <script> let b = document.querySelector("#mybutton"); b.onclick = function(){ document.inne("Thanks for clicking me!") } b.addEventListener("click",() =>{console.log("Thanks again")}) </script>
以“click”作为第一参数调用addEventListener()不会影响onclick属性的值。在这段代码中,单击一次按钮是在开发者控制台打印两条消息。如果我们先调用addEventListener(),然后设置onclick,那么仍然会看到两条消息,只是顺序相反。跟重要的是,可以多次调用addEventListener()在同一个对象上为同一事件类型注册多个处理程序。当对象上发生该事件时,所有为这个事件而注册的处理程序都会按照注册它们的顺序被调用。在同一个对象上以相同的参数多次调用addEventListener()没有作用,同一个处理程序只能注册一次,重复调用不会改变处理程序被调用的顺序。
与addeventlistener()对应的是removeeventlistener()方法,它们的前两个参数是一样的(第三个参数是可选的),只不过是用来从同一个对象上移除而不是添加事件处理程序。有时,临时注册一个事件处理程序,然后很快移除他是很有用的。比如,在“mousedown”事件发生时,可以为“mousemove”和“mouseup”事件注册临时处理程序,以便知道用户是否拖动鼠标。然后,在“mouseup”事件发生时移除这两个处理程序。此时移除程序的代码大致如下
document.removeEventListener("mousemove",handleMouseMove) document.removeEventListener("mouseup",handleMouseup)
addEventList()可选的第三个参数是一个布尔值或对象。如果传入true,函数就会被注册为捕获事件处理程序,从而在事件派发的另一个阶段调用它。如果在注册事件监听器时给第三个参数传入了true,那么要移除该事件处理程序,必须在调用removeEventListener()也传入true作为第三个参数。
注册捕获事件处理程序只是addEventListener()支持的三个选项之一,如果你要传入其它选项,可以给第三个参数传入一个对象,显示指定这些选项:
document.addEventListener("click",handleClick,{ capture:true, once:true, passive:true })
如果这个options(选项)对象的capture属性为true,那么函数就会被注册为补=捕获处理程序。如果这个属性为false或省略该属性,那么处理程序就不会注册到捕获阶段。
如果选项对象有once属性且值为true,则表示事件程序永远不调用preventDefault()取消默认动作。
操作DOM
客户端JavaScript存在的目的就是把静态HTML文档转换成交互式web应用,因此通过加皮本操作网页内容无疑是JavaScript核心目标。
每个window对象都有一个document属性,引用一个document对象。这个document对象代表窗口的内容,也是本节的主体,不过,document对象并不是孤立存在的,它是DOM中表示和操作文档内容的和核心对象。
3.1选择Document元素
客户端JavaScript程序经常需要操作文档中的一个或多个元素,全局document属性引用Document对象,但一个程序想要操作文档中嵌入层级更多的的元素,必须想通过某种方式获取或选择表示该元素的Element对象。
通过css选择符选择元素
css样式表有一个非常强大的语法,就是他的选择符。选择符用来描述文档中元素的集合。DOM方法querySelector()和querySelectAll()让我们能够在文档中元素和元素的集合。DOM方法querySelector()querySelectAll()让我们能够在文档中找到指定选择符的元素。
css选择符通过标签名、标签id属性的值或标签class属性中的词来描述元素:
div //任意<div>元素 #nav //id="nav"的元素 .warn //class属性中包含“warning”的元素
字符#用于根据id属性匹配,字符.用于根据class属性匹配。此外,也可以根据更通用的属性值来选择元素:
p[lang="fr"] //<p lang="fr"> *[name="x"] //任何有name="x"属性的元素
注意这两个例子组合了标签名选择符(或标签名通配符*)与属性选择符。还可以使用更复杂的组合:
span.faltal.error //class属性中包含“fatal”和“error”的任何<span>元素 span[lang="fr"].warning//class属性中包含“warnimg”的法语<span>元素
选择符也可以指明文档结构:
#log span //id=log的元素的后代中的<span>元素 #log>span //id=log的元素的子元素中的<span>元素 body>h1:first-child //<body>的子元素中的第一个<h1> img + p.caption //紧跟<img>的class属性中包含“caption”的<p> h2~p //<h2>后面所有同辈元素中的p
如果选择符被一个逗号隔开,则意味着要选择匹配其中任意选择符的元素;
button,input[type="button"] //所有<button>,以及所有<input type = "button">
也就是说,CSS选择符可以通过元素类型(标签)、ID、类名、属性、以及元素在文档中位置来引用元素。querySelector()方法接受一个CSS选择符字符串作为参数,返回他在文档中找到的第一个匹配的元素;如果没有找到,则返回full;
//查找文档中所有HTML标签包含属性id="spinner"的元素 let spinner = document.querySelector("#spinner");
querySelectorAll()也类似,只不过返回文档中所有的匹配元素,而不是只返回一个;
//查找所有<h1>、<h2>、<h3>标签的element对象 let titles = document.querySelectorAll("h1","h2","h3");
querySelectorAll()的返回值不是Element对象的数组,而是一个类似数组的NodeList对象。NodeList对象有一个length属性,可以像数组一样通过索引访问,因此可以使传统的for循环遍历。NodeLIst也是可迭代对象,因此也可以在for/of循环中使用它们。如果想把NodeList转换成真正的数组,只要把它传给Array.form()即可。
如果文档中没有与之低昂字符串匹配的元素,则querySelectorAll()返回的NodeList的length属性为0.
element类和document类都实现了querySelector()和querySelectorAll()。当在元素上调用时,这两个方法只返回该元素后代中的元素。
其他选择元素的方法
除了querySelector()和querySelectorAll(),DOM也定义了些老师的元素选择方法。
//通过id属性查找元素。参数就是id属性的值,不包含CSS选择符前缀 //类似于document.querySelector("#sect1") let sect1 = document.getElementById("sect1") //查找具有name="color"属性的所有元素 //类似于document.querySelectAll('*[name="color"]') let colors = document.getElementsByName("color") //查找文档中所有的<h1>元素 //类似于document.querySelectorall("h1") let headings = document.getElementsByTagName("h1") //getEleventByTagName()在element对象上也有定义 //取得sec1的后代中所有<h2>元素 let subheads = sect1.getElementsByTagName("h2") //查找所有类名中包含“tooltip”的元素 //类似于document。querySelectorAll(".tooltip") let tooltips = document.getElementsByClassName("tooltip") //查找sect1的后代中所有类名包含“sidebar”的元素 //类似于sect1.querySelectorAll(".sidebar") let sidebars = sect1.getElementsByClassName("sidebar")
3.2属性
HTML元素有标签名和一组称为属性的名/值对构成。比如,<a>元素定义一个超链接,使用其herf属性的值作为连接的目标。
Element类定义了通用的getAttribute()、setAttribute()、hasAttribute()和removeAttribute()方法,用于查询、设置、检测和删除元素的属性。但HTML元素的属性同时也在表示这些元素的HTMLElement对象上具有相应的属性。而作为JavaScript来存取他们,通常要比调用getAttribute()及其他方法来的更便捷。
作为元素属性的HTML属性
表示HTML文档中的元素的Elment对象通常会定义读/写属性,镜像该元素的HTML属性。HTMLElement为通用HTML属性(如id、title、lang和dir)和事件处理程序属性(如onclick)定义了属性。特定的Element子类型则定义了特定于相应元素的属性。例如要查询图片的URL,可以使用表示<img>的HTMLimageElement的src属性:
let image = document.querySelector("#main_image"); let url = image.scroll; //src属性是图片的URL image.id==="main_image"// ture;我们通过id找到了图片
类似的,可以使用以下代码设置<form>元素的表单提交属性
let f = document.querySelector("form") //文档中第一个form f.action = "https://xxx.com" //设置提交到那个URl f.method = "POST" //设置HTTP请求类型
对于某些元素(比如<input>),有的HTML名会映射到不同的JavaScript属性。比如,<input>元素在html中的value属性是由JavaScript的defaultValue属性镜像的。JavaScript的value属性包含的是用户在当前在<input>元素中输入的值。但是修改这个属性,既不会影响JavaScript的defaultValue属性,也不会影响html的value属性。
HTML属性 是不区分大小写的,但JavaScript属性名区分大小写,要把html属性转换为JavaScript属性,全部小写即可,如果HTML属性包含多个单词,则从第二个单词开始,每个单词的首字母都大写。比如,defaultChecked和tabIndex。不过事件处理程序是例外,比如onclick,需要全部小写。
有些HTML属性名是JavaScript中的保留字。对于这些属性,通常规则是对应的JavaScript属性包含前缀html。比如,<label>元素在HTML中的for属性,变成了JavaScript的htmlFor属性。“class”也是JavaScript的保留字,但这个非常重要的HTML class属性是个例外,他在JavaScript代码终会变成classname。
JavaScript中表示HTML属性的这些属性通常都是字符串值。但当html属性是布尔值或数字值时(如<input>元素的defaultCheck和maxLength属性),相应的JavaScript属性则是布尔值或数值,不是字符串。事件处理程序的值则始终是函数(或null)。
注意,这个基于属性的API只能获取或设置HTML中对应的属性值,并没有定义从元素中删除属性的方式。特别地,不能用delete操作符来删除html属性。如果真想删除HTML属性,可在JavaScript中调用removeAttritube()方法。
class属性
HTML元素的class属性特别重要。它的值是空格分隔的css类别名的列表,用于给元素应用css样式。由于class在JavaScript中是保留字,所以这个HTML属性是通过Elment对象上的classname属性反映出来的。classname可用于设置和返回HTML中属性的字符串值。但class属性这个名字并不恰当,因为它的只是一个css类名的列表。在这个列表中添加或删除某个类名(而不是把列表作为整个字符串来操作)在客户端JavaScript编程中也十分常见。
为此,Elment对象定义了classLIst属性,支持将class属性作为一个列表来操作。classLIst属性的只是一个可迭代的类数组对象。虽然这个属性的名字叫classList,但他的行为更像是一个可迭代的类数组对象。虽然这个属性的名字叫classList,但他的行为更像类名的集合,而且定义了add()、remove()、contains()和taggle()方法:
//再想让用户直到现在正忙的时候 //轮换图标。为此必须删除hidden类,添加animated类(假设样式表有正确的配置) let spinner = document.querySelector("#spinner"); spinner.classList.remove("hidden"); spinner.classList.add("animated")
dataset属性
有时候在HTML元素上附加一些信息很有用,因为JavaScript代码在选择并操作相应的元素时可以使用这些信息。在HTML中,任何一前缀“data-”来头的小写属性都被认为是有效的,可以将它们用于任何目的。这些“数据集”属性不影响他们所在的元素的展示,在保证文档内容正确性的前提下定义了一种附加额外数据的标准方式。
在1DOM中Element对象都有一个dataset属性,该属性引用的对象包含与html中的data-属性对应的属性,但不带这个前缀。也就是说,dataset.x中保存的是HTML中的data-x属性的值,连字符分割的属性将映射为驼峰是属性名:HTML中的data-section-number会变成JavaScript中的dataset.sectionNumber。
假设某HTML文档中包含以下内容:
<h2 id="title" data-section="16.1">ATT</h2> let number = document.querySelector("#title").dataset.sectionNumber;
3.3元素内容
作为HTML的内容
读取一个elment的innerHTML属性会返回该元素内容的标记字符串。在元素上设置这个属性会调用浏览器的解析器,并以新字符串解析后的表示替换元素当前的内容。可以打来控制台运行下面的代码试试
document.body.innerHTML = "<h1>Ops</h1>"
你会发现整个网页都不见了,取而代之的是一个标题“ops”浏览器非常擅长解析HTML,设置innerHTML通常效率很高。
Element的outerHTML属性与innerHTML属性类似,只是返回的只包含元素自身。在读取outerhtml时,该值包含元素的开始和结束标签。而在设置元素的outerHTML时,新内容会取代元素自身。
另一个相关的element方法是insertAdjacentHTML(),用于插入语指定元素相邻的任意HTML标记字符串。要插入的标签作为第二个参数传入,而相邻的精确含义取决于第一个参数的值。第一个参数可以是一下字符串值中的一个“beforebegin”“afterbegin”“beforedend”和“afterend”。
作为纯文本内容
有时候,我们希望得到元素的纯文本,或者想文档中插入文本。这也做的标准方式是使用textcontent属性:
<body> <p>123412</p> </body> <script> let para = document.querySelector("p"); let text = document.textContent; //取得该段落的文本 para.textContent = "Hello World" //修改该段落的文本 </script>
这个textContent属性有node类定义的,因此在text节点和elment节点上都可以使用。对于Element节点,它会找到并返回元素所有后代中的文本。
Elment类定义了一个inerText属性,与textContent类似。但innerText有一些烧碱和复杂的行为,如试图阻止表格格式化。这个属性的定义不严谨 ,浏览器间的视线也存在兼容性问题,因此不该再使用了。
3.4创建、插入、和删除文本
我们已经知道了如何获取及使用HTML和纯文本字符修改文档内容。也知道额可以遍历document,查找构成文档的个别Elment和Text节点。当然,在个别节点的层级修改文档也是可能的。document类也定义了creatElement()方法可以创建一个新元素,并通过自己的append()方法为自己添加或其他元素:
let paragraph = document.createElement("p") //创建一个空的p元素 let emphasis = document.createElement("em") //创建一个空的em元素 emphasis.append("world") //象em中添加文本 paragraph.append("hello",emphasis,"!") paragraph.prepend("i"); //在p的开头添加文本 paragraph.innerHTML
append()和prepend()接收任意多个参数,这些参数可以是node对象或字符串。字符串参数会自动转移为TEXT节点(也可以使用document.creatTextNode()来创建Text节点,但很少需要这样做)。append()把参数添加到孩子列表的末尾。prepend()把参数添加到孩子列表的开头。
如果想在包含元素的孩子列表中间插入Element或Text节点,那append()和prepend()都派不上用场。这时候,应该先获取对一个同辈节点的引用,然后调用before()在该同辈前面插入新内容,或调用after()在该同辈后面插入新内容。例如:
//找到class="greetings"的标题元素 let greetings = document.querySelector("h2.greetings"); //在这个标题后面插入新创建的parafraph和一条水平线 greetings.after(paragraph,document.createElement("hr"));
与append()和prepend()类似,after()和before()也接受任意个数的字符串和元素参数,在将字符串转换为Text节点后把他们全部插入文档中。append()和prepend()只在element上有定义,但after()和before()也接收任意个数的字符串和元素参数,在将字符串转换成Text节点后把他们全部插入文档中。append()和prepend()只在element对象上有定义,但after()和before()同时存在于Element和Text节点上,因此可以使用它们相对于Text节点插入内容。
标签:JavaScript,浏览器,元素,HTML,处理程序,document,属性 From: https://www.cnblogs.com/user-zbb/p/17106740.html