页,又叫Web,其实就是一个后缀名为.html的文本文件。HTML文件采用超级文本标记语言(HyperText Markup Language)书写而成,最终由客户端浏览器解释并呈现给用户。
Web由HTML内容、CSS样式、JavaScript前端行为三要素组成。开发一个网页,就好比设计一出舞台剧,首先要决定舞台上有哪些演员(HTML网页内容)、演员的扮相(CSS网页样式)、演员的动作及剧情(JavaScript网页前端行为)。
HTML使用标记标签来描述网页,标记标签是HTML语言中最基本的单位,是HTML中最重要的组成部分。
标记是HTML文档中一些有特定意义的符号,这些符号指明网页内容的含义或结构。
标记即标签,不同的标记能实现不同的功能。HTML标记按功能可大致分为六大类。分别是语义标记、元标记、文本标记、容器标记、嵌入式标记,以及表单和表单元素标记六大类。
(1) 语义标记。又称结构标记,是指尽量使用有相对应结构含义的HTML标记。语义标记的逐渐增加便于开发者阅读并写出优雅美丽的代码,同时让浏览器的“爬虫”和机器更好地解析检索。在没有CSS的情况下,语义标记让页面也能呈现出很好的内容、代码结构。简而言之,语义标记的使用,即是为了网页“裸奔时也好看”。
(2) 元标记。是指位于HTML文件头部的一些特殊代码,是解释说明的标记。其主要功能就是对文档进行说明,描述HTML文档的整体信息。元标记向浏览者提供某一页面的附加信息,告诉我们它是谁。当客户机找服务器要东西时,它帮助一些搜索引擎进行页面分析,使导出的某一页面检索信息能正确地放入合适的目录中。
HTML元标记出现于网页头标签处,主要包括标题标记、关键词标记、描述标记等,合理运用元标记会使网页在搜索引擎中表现更为突出。
(3) 文本标记。这是最重要、最基本的标记,一般只能嵌套文本、超链接的标签。为了让网页中的文本看上去编排有序、整齐美观、错落有致,就要设置文本的标题、字号大小、字体颜色、字体类型以及换行、换段等。而为实现这一目的所使用的特定的HTML语言,就叫作文本标记。
(4) 容器标记。又称作内容组织标记,可以简单地理解为它是能嵌套其他所有标签的标签,是用来装东西的容器。容器与容器之间也可以相互嵌套,表现为父级容器和子级容器。
如div标签中可以镶嵌span标签,div可以看作是一个可以装入其他标签的大容器,span是一个只能装文本的小容器,大容器当然可以放得下小容器。
(5) 嵌入式标记。常用于嵌入图像、音频、视频、flash动画、插件等多媒体元素,使网页呈现方式更加多样化,还可以嵌套某些标签来指定视频文件的路径或者网址路径,决定多媒体元素的属性和播放方式等。
(6) 表单和表单元素标记。多用于制作网页和用户交互的界面、控件,是客户端与服务器端进行信息交流的途径。用户可以使用诸如文本域、列表框、复选框及单选按钮之类的表单元素输入信息,然后单击某个按钮提交这些信息。
如果说HTML语言规定了网页的具体内容,那么CSS(cascading style sheets)就是为了给这些内容进行规整和装饰而存在的。CSS最初的诞生,就是因为HTML为了满足页面设计者的显示要求而变得臃肿复杂,因而需要一种样式表语言达到控制页面呈现内容的效果。CSS让整个页面可视化程度更强,可以说是网页的门面。如果将网页比作一个舞台,HTML是舞台上的演员,那么CSS就是演员的扮相,更完美地将节目(即页面内容)呈现在观众面前。
CSS即层叠样式表。作为一种用来表现HTML或者XML的计算机语言,CSS可以对网页元素位置的排版进行像素级别的精确控制,可以静态地修饰网页,也可以配合脚本语言(如后文会提到的JavaScript)动态地格式化网页元素。
所谓层叠,是即样式可以层层叠加。
每个HTML元素都有一组样式属性,它们可以通过CSS来设定。这些属性涉及背景(background)、字体(fonts)、颜色(color)、链接(link)、边框(border)、列表样式(url)等。CSS就是一种先选择HTML元素,然后设定选中元素属性的机制。
CSS选择器和要应用的样式构成了一条CSS规则。
CSS规则由两个主要的部分构成:选择器及一条或多条声明。选择器(selector)就是想要改变样式的HTML元素;每条声明(declaration)由一个属性(property)和一个值(value)构成。属性是想要设置的样式属性(style attribute),每个属性有一个值。属性和值被冒号(:)分开,CSS声明总是以分号(;)结束,声明组以大括号({ })括起来。
JavaScript最早是由Netscape Communication(网景)公司开发出来的一种客户端脚本语言,将JavaScript代码直接嵌入在HTML页面中,能对HTML页面中的HTML、CSS和JavaScript本身进行增加、删除、修改、查询等操作,使得客户端静态页面变成支持用户交互并响应相应事件的动态页面(DHTML=HTML+CSS+JavaScript)。它的出现弥补了HTML语言的缺陷,使得开发客户端Web应用程序成为可能。
HTML Web运行在浏览器中,这就是说浏览器是Web的实际运行环境。如果将运行环境视为一个京剧表演的舞台,则在这个舞台上有网页内容HTML(演员)、网页样式CSS(演员的扮相)、网页行为JavaScript(演员的动作)。JavaScript只能在自己的舞台上表演,能对舞台上的既有存在(HTML、CSS、JavaScript)进行操作(增、删、改、查),而不能跨越到舞台外面表演(功能受限,JavaScript程序不能操作浏览器之外的事物)。
更进一步思考与观察,会发现两个有趣的现象:
① 当网站被服务器软件架设起来时(如同京剧正式开演),由于遵守网络安全协议,JavaScript这个演员的功能受限于表演的舞台(也就是浏览器客户区)。也就是说,此时JavaScript是存在功能受限的,能对HTML、CSS、JavaScript进行增删改查,而不能对浏览器客户区之外做任何事情,如不能操作硬盘等本地资源等。为了在互联网上搭建网站,让所有人都能看到的,还需要租用域名、空间。
② 当直接双击运行本地Web文件时(如同京剧在做排练),JavaScript的功能相对不受限制。此时JavaScript可以访问本地资源,如读取本机IP、操纵本地文件系统等。但这样架设的Web不能被他人通过网络访问,也不能被百度检索。事实上,我们可以在本地放置无数个网页,只要我们的硬盘容量足够大。
JavaScript包含了三个部分的内容:JavaScript脚本语言规范EMCAScript(语言核心)、文档对象模型DOM(以面向对象的方式操纵文档内容)、浏览器对象模型BOM(以面向对象的方式操纵浏览器窗口元素)。
3.1 语言核心EMCA Script
EMCA 是欧洲计算机制造商协会(EuropeanComputer Manufacturers Association)的缩写,EMCAScript就是这个协会制定的标准化脚本语言。我们知道,JavaScript是一门编程语言,而每一种语言都有它自己的基本语法如数据类型等,这些概念必须遵循一定的规范,浏览器开发者要严格依据这个规范来开发编译器,JavaScript程序员要严格依据这个规范来调用API。也就是说,EMCAScript是JavaScript的语法规范,规定了JavaScript脚本的核心内容。打个比方,新华字典(也算是一种语言规范)规定了“血”这个字,而无论在“血液”中的读“xuè”,还是在“血晕”中的读“xiě”。新华字典规范了汉字,EMCAScript规范了JavaScript。
3.2 文档对象模型DOM
文档对象模型(document object model)是针对HTML和XML文档的应用程序编程接口。DOM 把整个页面规划成由多个节点构成的文档,我们可以用DOM API将页面内容绘制成一个树状图。在这种模型下,页面中的每个部分都是可用程序操纵的节点,我们可以通过DOM 来方便地控制页面的结构和内容(增加、删除、修改、查询等),如我们就可以用document.getElementById()通过id号来查询文档中的元素。DOM 使得用户页面可以动态地变化,用户可以和Web文档内容进行交互。
3.3 浏览器对象模型
浏览器对象模型BOM(browser object model)是针对浏览器的应用程序编程接口。我们可以通过BOM 对浏览器窗口进行访问和操作,例如弹出新的浏览器窗口,移动、关闭和更改浏览器窗口,提供详细的网络浏览器信息(navigator object)、详细的页面信息(location object)、详细的用户屏幕分辨率的信息(screen object)等。BOM 方便我们从浏览器上获得信息,更好地和浏览器进行交互。例如,我们可以用window.alert()弹出消息框,用window.prompt()弹出提示框,使得用户可以和浏览器窗口进行交互。
点击没同选项卡,实现如下切换效果:
代码:
<html>
<head>
<title>tab control</title></head>
<style type="text/css">
#tab{
position:relative;/* 定义选项卡的为相对定位,使其子级元素有定位参考对象 */
width:45%;
height:400px;
}
#tab h4{
display:inline;
background-color:#ccc;
color:black;
}
#tab div{
border:1px #666 solid;
position:absolute; /*tab下的div叠在一起*/
top:28px;
left:0px;
width:100%;
height:370px;
display:none;
}
#tab .block{
display:block;
}
#tab .up{
color:#999999;
background-color:black;
}
</style>
<script>
function tabSwitch(tab,ao) {
var h = document.getElementById(tab).getElementsByTagName("h4");
var d = document.getElementById(tab).getElementsByTagName("div");
var n = document.getElementById(tab).getElementsByTagName("div").length;
for (var i = 0; i < n; i++) {
if (ao - 1 == i) {
h[i].className += " up";
d[i].className += " block";
} else {
h[i].className = " ";
d[i].className = " ";
}
}
}
</script>
<body>
<div id="tab">
<h4 onclick="tabSwitch('tab',1)" class="up">道德经</h4>
<h4 onclick="tabSwitch('tab',2)" >岳阳楼记</h4>
<h4 onclick="tabSwitch('tab',3)" >中庸</h4>
<div class="block">
<p>上善若水。</p>
<p>水善利万物而不争,处众人之所恶,故几於道。</p>
<p>居善地,心善渊,与善仁,言善信,正善治,事善能,动善时。</p>
<p>夫唯不争,故无尤。</p>
</div>
<div>
<p>不以物喜,不以己悲</p>
<p>惟江上之清风,与山间之明月</p>
<p>耳得之而为声,目遇之而成色</p>
</div>
<div>
<p>博学,审问,慎思,明辨,笃行。</p>
<p>学之要能,问之要知,思之要得,辨之要明,行之要笃。</p>
<p>虽愚必明,虽柔必强。</p>
</div>
</div>
</body>
</html>
ref:
王小峰《大话Web开发:基于知识管理角度》
-End-
个视频我们来写两个圆环。这个圆环虽然看起来只是普普通通的两个圆,但是认真一看好像又没那么简单,因为它是交错重叠起来的,并且还有一点阴影的效果,看起来比较真实。这个案例其实是UTube上面一个比较知名博主的教学案例,我们不妨来学习一下。
可能很多人也看过,我们今天主要来实现这两个圆环重叠的部分,阴影的部分比较简单,大家可以自己去思考一下。html里面这两个div就是这两个圆环,样式现在写了一些基本的样式,其它样式重新来写。
·先来把这两个圆环的基础样式写出来,两个圆有了,然后把其中一个变成红色,再让它们先简单的重叠一下,控制一下第二个圆环,调整一下它的边框颜色就可以了,把它变成红色。
·再往左边移动60像素,先简单重叠起来。现在两个圆只是简单的重叠,我们要怎么样实现这种交错重叠?就好像两个圆环是穿起来的这种感觉。这里分别给这两个圆环加个伪元素,我们是可以通过定位把一个盒子撑起来的。
·这里给它设置一下inset,关键就是inset设置为多少合适。如果是设置为0,也就是四个方向都是设为0,按道理应该是和父元素完全重叠的(没border的话)。
·加个边框看一下,很明显它并没有和白色圆环完全重叠,而是在它里面。这是因为我们看到的这两个圆环,看到的只是border边框的区域。inset的设置为0,它只不过是贴在content内容区域里面,所以伪元素我们要把它扩大才可以。
·这里要调整一下inset的值,0是刚好贴满content的区域,设置为正值它是收缩的,所以这里设置为-25px。现在和白色的圆环就一样大了,只不过一个正方形一个圆形,等一下把伪元素调整成圆的就可以了。
·然后单独来设置一下上边框,同样也是白色的边框,还有右边框也单独设置一下。ok,再把另外两条边框设置为透明。现在左边和下边就看不到了,再把它设置成一个圆,这样它就可以和第一个圆环完全重叠起来了。
·现在伪元素这半个圆环就和本来的圆环完全重叠起来,那有什么用?还是和原来的一样,但是现在就可以单独给伪元素这半个圆环设置层级了,把层级调高一点,这样这一段圆环它就可以盖在上面,然后再给它旋转一下位置,让它旋转负的四十五度,这样两个圆环贯穿重叠起来的效果就完成了。
其实就是借助了一个伪元素做了一个障眼法,如果想实现圆环交汇的地方有点阴影的效果,也可以多写两个伪元素来实现,这个大家可以自己来思考一下。
这个视频就到这里,感谢大家的收看。
内容是《Web前端开发之Javascript视频》的课件,请配合大师哥《Javascript》视频课程学习。
HTML5规范围绕着如何使用新增标记定义了大量Javascript API;其中一些API与DOM重叠,定义了浏览器应该支持的DOM扩展;
从HTML4开始,在Web开发领域,有一个非常大的应用,就是滥用class属性,一方面可以通过它为元素添加样式,另一方面还可以用它表示元素的语义;于是,开发人员会用大量的Javascript代码来操作CSS类,比如动态修改类或者搜索文档中具有给定类或给定的一组类的元素,等等这些操作;为了让开发人员适应并增加对class属性的新的认识,HTML5新增了很多API,致力于简化CSS类的用法;
getElementsByClassName(names)方法:
该方法是基于元素class属性值中的类名来选取成组的文档元素,可以通过document对象或Element元素调用这个方法;该方法最早出现在第三方Javascript类库中,是通过既有的DOM功能实现的,而现在,原生的实现具有极大的性能优势;
该方法接收一个names参数,即一个包含一个或多个类名的字符串,多个类名使用空格隔开,返回带有指定类的所有元素的HTMLCollection;
var elts = document.getElementsByClassName("myclass");
console.log(elts); // HTMLCollection
console.log(elts[0]); // 第一个元素
传入多个类名时,类名的先后顺序不重要;如:
// 取得所有类中同时包括username和current的元素,类名的先后顺序无所谓
var allCurrentUsernames = document.getElementsByClassName("username current");
console.log(allCurrentUsernames);
var selected = document.getElementById("mydiv").getElementsByClassName("selected");
console.log(selected);
它返回的HTMLCollection集合,可以借用Array的方法,如:
var elts = document.getElementsByClassName("selected");
var eltDivs = Array.prototype.filter.call(elts, function(ele){
return ele.nodeName === 'DIV';
});
console.log(eltDivs); // 返回拥有selected类名的所有div元素
使用这个方法可以更方便地为带有某些类的元素添加事件处理程序,从面不必再局限于使用ID或标签名;
<style>
.zr{background-color: rosybrown;}
@keyframes rotate{
0%{transform: rotate(0deg);}
50%{transform: rotate(45deg);}
100%{transform: rotate(0deg);}
}
.animating{
animation: rotate 2s ease-in-out;
}
</style>
<p class="zr">this is ok</p>
<!-- 添加若干个class为zr的元素 -->
<script>
var elts = document.getElementsByClassName("zr");
for(var i=0,len=elts.length; i<len; i++){
elts[i].addEventListener("click",function(e){
this.classList.add("animating");
},false);
elts[i].addEventListener("animationend",function(e){
this.classList.remove("animating");
console.log("end");
});
}
</script>
如此,我们就可以为某些需要执行动画的元素添加一个名为zr的class类即可;当然,此处是一个动画效果,也可以是其他的某些操作;
getElementsByClassName()方法与querySelector()和querySelectorAll()方法很类似,但用法及返回类型不同;
var elts = document.getElementsByClassName("myclass outer");
console.log(elts); // HTMLCollection
var elts = document.querySelectorAll(".myclass,.outer");
console.log(elts); // NodeList
getElementsByClassName()参数只能是类名,且多个类名用空格隔开,多个类名是并的关系,而且不分顺序,即只有所有class都匹配的元素才会被返回,其返回类型是HTMLCollection,是动态的集合;
querySelector()参数是CSS选择器,并且可以使用复杂的CSS选择器,只要是合法的CSS选择器都可以,但多个选择器必须使用逗号分隔,它们是或的关系,其返回类型是NodeList,并且这个NodeList是静态的;
目前,获取元素集合共有四个方法,要注意它们的不同点;
var elts = document.getElementsByClassName("myclass outer");
console.log(elts); // HTMLCollection
var elts = document.getElementsByTagName("div");
console.log(elts); // HTMLCollection
var elts = document.getElementsByName("myname");
console.log(elts); // NodeList
var elts = document.querySelectorAll(".myclass,.outer,.current");
console.log(elts); // NodeList
另外,需要注意的是,getElementsByClassName()方法返回的是动态HTMLCollection,所以使用这个方法与使用getElementsByTagName()以及其他返回动态集合的DOM方法都具有同样的性能问题;
元素滚动:
Element.scrollIntoView(alignToTop | scrollIntoViewOptions)方法:
DOM对滚动页面没有做出规定;各浏览器分别实现了相应的方法,用于以不同方式控制滚动,最终HTML5选择了scrollIntoView()作为标准方法;
该方法是作为Element类型的扩展存在的,因此可以在所有元素上使用,通过滚动浏览器窗口或某个容器元素,使调用该方法的元素出现在视口中;
该方法接收一个布尔值参数alignToTop或Object型(scrollIntoViewOptions)参数,如果为true或者省略,那么窗口会尽可能滚动到自身顶部与元素顶部平齐,如果为false,调用元素会尽可能全部出现在视口中,不过顶部不一定对齐;
var mybtn = document.getElementById("mybtn");
mybtn.onclick = function(){
var img = document.getElementById("myimg");
img.scrollIntoView(false);
}
Object型参数scrollIntoViewOptions:一个包含下列属性的对象:
img.scrollIntoView({behavior:"smooth",block:"nearest",inline:"center"});
但是IE与Edge对scrollIntoViewOptions这个参数并不友好,比如不支持behavior:”smooth”等;
var btn = document.getElementById("btn");
btn.onclick = function(){
var img = document.querySelector("img");
// 以下三行是等同的
img.scrollIntoView();
img.scrollIntoView(true);
img.scrollIntoView({behavior:"auto",block:"start"});
// 以下两行是等同的,但IE与Edge似乎不识别end
img.scrollIntoView(false);
img.scrollIntoView({behavior:"auto",block:"end"});
}
另外,CSS3中有个平滑滚动的属性scroll-behavior,如;
<style>
html,body{scroll-behavior: smooth;}
</style>
只要页面有滚动行为,自动进行平常处理;但IE与Edge不支持;
当页面发生变化时,一般会用这个方法来吸引用户的注意力;实际上,为某个元素设置焦点也会导致浏览器滚动并显示出获得焦点的元素;
var username = document.getElementById("username");
username.focus();
Element.scrollIntoViewIfNeeded()方法:
用来将不在浏览器窗口的可见区域内的元素滚动到浏览器窗口的可见区域,如果该元素已经在浏览器窗口的可见区域内,则不会发生滚动,此方法是标准的Element.scrollIntoView()方法的专有变体,不属于任何规范,是一种WebKit专有的方法;
var btn = document.getElementById("btn");
btn.onclick = function(){
var elt = document.getElementById("elt");
elt.scrollIntoViewIfNeeded(true);
}
目前,除了Chrome和Opera支持,其他都不支持;
应用的场景:
对URL中hash标记的进化;比如:回到顶部(#);
<a href="javascript:void(0)" id="topA" style="position:fixed;right:50px;bottom:50px;display:block; width:50px;height:50px;background-color:purple;">回到顶部</a>
<script>
// 回到顶部
var topA = document.getElementById("topA");
topA.onclick = function(){
document.body.scrollIntoView({behavior:"smooth",block:"start"});
}
</script>
滚动到指定位置(#xxx);
如:一个单页导航的应用;
<style>
*{margin:0; padding: 0;}
html,body{
-ms-overflow-style: none; scrollbar-width: none;
}
::-webkit-scrollbar{ display: none; }
ul,li{list-style-type: none;}
header{
position: fixed; top:0; left: 0;;
width: 100%; height: 2rem; background-color: rgba(0, 0, 0, .5);
}
nav ul li{padding: 0 2rem; line-height: 2rem; float: left;}
nav ul li a{color:#FFF; text-decoration: none;}
section{width: 100%; height: 100vh; box-sizing: border-box; padding: 10%; background-size:cover;}
section#banner{background: url(images/1.jpg) no-repeat center; background-size:cover;}
section#service{background:url(images/2.jpg) no-repeat center; background-size:cover;}
section#contact{background: url(images/3.jpg) no-repeat center; background-size:cover;}
footer{
width:100%;height: 2rem; background-color: rgba(0, 0, 0, .8); color:rgba(255, 255, 255, .8);
position: fixed; left: 0; bottom: 0;
}
</style>
<header>
<nav>
<ul>
<li><a href="dom1.html">首页</a></li>
<li><a href="#news" data-name="news">新闻</a></li>
<li><a href="#service" data-name="service">服务</a></li>
<li><a href="#about" data-name="about">关于</a></li>
<li><a href="#contact" data-name="contact">联系</a></li>
</ul>
</nav>
</header>
<section id="banner">
<h2>零点程序员</h2>
<h3>zeronetwork</h3>
</section>
<section id="news"><h2>新闻中心</h2></section>
<section id="service"><h2>服务领域</h2></section>
<section id="about"><h2>关于我们</h2></section>
<section id="contact"><h2>联系我们</h2></section>
<footer><p>北京零点网络科技有限公司,www.zeronetwork.cn 零点程序员</p></footer>
<script>
window.onload = function(){
scrollPage();
var navs = document.querySelectorAll("nav a");
for(var i=0,len=navs.length; i<len; i++){
(function(){
var item = navs[i];
item.addEventListener("click",function(event){
event.preventDefault();
scrollPage(event.target.dataset.name);
},false);
})();
}
}
function scrollPage(id){
console.log(id);
var section = id ? document.querySelector("#" + id) : document.body;
section.scrollIntoView({behavior:"smooth",block:"start"});
}
</script>
聊天窗口滚动显示最新的消息;
<style>
*{margin: 0px; padding: 0;}
html,body{font-size: 14px;}
ul,li{list-style-type: none;}
li{margin: 1.5vh 0;}
#app{
width: 400px; height: 400px; border: 10px solid purple;
position: relative; background-color: rosybrown;
padding-bottom: 40px;
}
#message{ width: 100%; height:100%; padding:15px; padding-bottom: 0;
box-sizing: border-box; overflow-y: scroll;
}
#message ul{padding-bottom: 15px;}
#message ul li{display: flex;}
#message ul li.me{flex-direction: row-reverse;}
#message ul li a{display: inline-block;}
#message ul li a img{width: 2vw; height: 2vw; border-radius: 50%;}
#message ul li p{
background-color: #FFF; border-radius: 3px; padding:0.5vw; margin:0 3vw 0 1vw;
}
#message ul li.me p{background-color:#09ce44;margin: 0 1vw 0 3vw;}
#inputdiv{
position: absolute; left: 0; bottom: 0; width: 100%; height: 40px;
background-color:rgba(0, 0, 0, 1); padding: 5px; box-sizing: border-box;
display:flex;
}
#txtInput{flex-grow: 3;}
#btn{flex-grow: 1;}
</style>
<div id="app">
<div id="message">
<ul>
<li><a href="#"><img src="images/1.jpg" /></a><p>...</p></li>
<li class="me"><a href="#"><img src="images/1.jpg" /></a><p>...</p></li>
<li class="me"><a href="#"><img src="images/1.jpg" /></a><p>..</p></li>
<li><a href="#"><img src="images/1.jpg" /></a><p>...</p></li>
<li class="me"><a href="#"><img src="images/1.jpg" /></a><p>...</p></li>
</ul>
</div>
<div id="inputdiv"><input type="text" id="txtInput" name="txtInput" />
<input type="button" value="发送" id="btn" /></div>
</div>
<script>
window.onload = function(){
var ul = document.querySelector("#message>ul");
if(navigator.userAgent.indexOf("Trident") != -1){
ul.scrollIntoView(false);
}else{
ul.scrollIntoView({behavior:"smooth", block:"end"});
}
var btn = document.querySelector("#btn");
btn.addEventListener("click",function(e){
var txtInput = document.querySelector("#txtInput");
if(txtInput.value){
var html = "<li class=\"me\"><a href=\"#\"><img src=\"images/1.jpg\" /></a>";
html += "<p>" + txtInput.value + "</p></li>";
document.querySelector("#message ul").insertAdjacentHTML("beforeend", html);
txtInput.value = "";
}
if(navigator.userAgent.indexOf("Trident") != -1){
ul.scrollIntoView(false);
}else{
ul.scrollIntoView({behavior:"smooth", block:"end"});
}
},false);
}
</script>
焦点管理:
HTML5也添加了辅助管理DOM焦点的功能;
document.activeElement属性:
该属性始终会引用DOM中当前获得了焦点的元素;
元素获得焦点的方式有页面加载、用户输入和在代码中调用focus()方法,如:
console.log(document.activeElement);
var btn = document.getElementById("myButton");
btn.focus();
console.log(document.activeElement === btn); // true
默认情况下,文档刚刚加载完成时,document.activeElement中保存的是document.body元素的引用,文档加载期间,其该属性的值为null;
一般情况下,都是在一个表单控件上应用焦点管理,比如,在一个input或textarea上选择文本时,activeElement属性就会返回该元素;
在现实中,该属性在控件中使用时,一般会与选择控件中的文本操作配合使用,比如,调用该控件的selectionStart()和selectionEnd()方法来获取选择的文本内容;
<input type="text" id="myinput" value="北京零点网络科技有限公司" /><br/>
<textarea id="mytextarea" rows="5" cols="40">北京零点网络科技有限公司推出零点程序员品牌,专门从事IT培训,主讲是大师哥王唯。</textarea>
<p>获得焦点的元素:<b id="outputelement"></b></p>
<p>选择的文本:<b id="outputtext"></b></p>
<script>
function selectText(e){
var activeEl = document.activeElement;
var selection = activeEl.value.substring(
activeEl.selectionStart, activeEl.selectionEnd
);
var outputelement = document.getElementById("outputelement");
var outputtext = document.getElementById("outputtext");
outputelement.innerHTML = activeEl.id;
outputtext.innerHTML = selection;
}
var myinput = document.getElementById("myinput");
var mytextarea = document.getElementById("mytextarea");
myinput.addEventListener("mouseup", selectText,false);
mytextarea.addEventListener("mouseup", selectText,false);
</script>
小示例:
// 获取焦点的控件自动滚到页面中间
window.addEventListener("click",function(e){
var elt = document.activeElement;
if(elt.tagName == "INPUT" || elt.tagName == "TEXTAREA")
elt.scrollIntoView({behavior:"smooth", inline:"center"});
},false);
解决由于窗口缩放、键盘弹出后遮挡表单的问题:
<!-- 按tab切换到input,再缩放窗口大小 -->
<h1 tabindex="1">Web前端开发</h1>
<div style="height: 1000px; background-color: purple;" id="mydiv" tabindex="2">div</div>
<input type="text" />
<script>
window.addEventListener("resize",function(e){
if(document.activeElement.tagName === 'INPUT' ||
document.activeElement.tagName === 'TEXTAREA'){
setTimeout(function(){
document.activeElement.scrollIntoView({behavior:"smooth"});
},100);
}
});
</script>
activeElement属性是只读的,如果想让某个元素获取焦点,可以调用该元素的focus()方法,如:
var myinput = document.getElementById("myinput");
document.activeElement = myinput; // 失效
myinput.focus();
console.log(document.activeElement); // input
document.hasFocus()方法:
该方法用于表明当前文档或者当前文档内的节点是否获得取焦点,该方法可以用来判断当前文档中的活动元素是否获得了焦点,如:
console.log(document.hasFocus());
当查看一个文档时,当前文档中获得焦点的元素一定是当前文档的活动元素,但一个文档中的活动元素不一定获得了焦点,例如,一个在后台窗口中的活动元素一定没有获得焦点;
通过检测文档是否获得了焦点,可以知道用户是不是正在与页面交互;
<input id="btn" type="button" value="打开窗口" /><br/>
<script>
function openWin(){
window.open("about:blank","newwin","width=400,height=300");
}
var btn = document.getElementById("btn");
btn.addEventListener("click", openWin, false);
function checkPageFocus(){
if(document.hasFocus())
console.log("该页面获得了焦点");
else
console.log("该页面失去了焦点");
}
setInterval(checkPageFocus, 1000);
</script>
查询文档获知哪个元素获得了焦点,以及确定文档是否获得了焦点,这两个功能最重要的用途是提高Web应用的无障碍性;无障碍Web应用的一个主要标志就是恰当的焦点管理,而确切地知道哪个元素获得了焦点是一个比较重要的操作;
HTMLDocument的增强:
HTML5扩展了HTMLDocument,增加了新的功能;
document.readyState属性:
该属性描述了document 的加载状态,当该属性值发生变化时,会在 document 对象上触发 readystatechange事件;
IE4最早为document对象引入了readyState属性,然后,其他浏览器也都陆续实现了这个属性,最终HTML5把这个属性纳入了标准之中。
该属性有三个可能的值:
console.log(document.readyState); // loading
为什么要使用document.readyState属性?目的就是通过它来实现一个指示文档已经加载完成的指示器;在这个属性没有得到广泛支持前,要实现这样的一个指示器,必须借助onload事件处理程序,表明文档已经加载完毕;
window.onload = function(){
console.log("文档加载完毕")
console.log(document.readyState); // complete
}
现在可以直接使用document.readyState属性来判断,如:
// 不会被执行,因为代码运行到此处,readySate状态为loading
if(document.readyState == "complete"){
console.log("文档已加载完毕");
console.log(document.readyState);
}
但并没有执行,因为代码执行到此处,readyState的状态为loading,而后它又不能自己更新,所以要实时的取得readyState的状态;当该属性值发生变化时,会在 document 对象上触发 readystatechange事件,所以使用该事件就可以实时监听它的状态;
document.onreadystatechange = function(e) {
// if(document.readyState == "loading"){
// console.log("Loading");
// }else if(document.readyState == "interactive"){
// var span = document.createElement("span");
// span.textContent = "资源正在加载";
// document.body.appendChild(span);
// console.log("Interactive");
// }else if(document.readyState == "complete"){
// var span = document.querySelector("span");
// document.body.removeChild(span);
// console.log("Complete");
// }
// 或者
switch(document.readyState){
case "loading":
console.log("Loading");
break;
case "interactive":
// 文档已经结束了“正在加载”状态,DOM元素可以被访问。
// 但是像图像,样式表和框架等资源依然还在加载。
var span = document.createElement("span");
span.textContent = "资源正在加载";
document.body.appendChild(span);
console.log("Interactive");
break;
case "complete":
// 页面所有内容都已被完全加载
var img = document.getElementsByTagName("img")[0];
console.log("图片等资源加载完成:" + img.src);
break;
}
}
一个简单小示例,loading页
<style>
*{margin: 0; padding: 0;}
#loading{
width: 100vw; height: 100vh; background-color: rgba(0, 0, 0, .6);
position: absolute; top: 0; left: 0;
}
@keyframes rotate{
0%{transform: rotate(0deg);}
100%{transform: rotate(360deg);}
}
#loading img{
width: 5vw;
position: absolute; left: 50%; top:50%;
margin-left: -5vw; margin-top:-5vh;
animation: rotate 1s linear infinite; /* [ˈɪnfɪnət] */
}
#loading.loading-none{display: none;}
</style>
<div id="loading"><img src="images/loading.png" /></div>
<script>
document.onreadystatechange = function(e) {
if(document.readyState == "complete")
document.getElementById("loading").className = "loading-none";
else
document.getElementById("loading").className = ""
}
</script>
compatMode兼容模式:
页面的渲染有两种方式,Standards mode标准模式和Quirks mode混杂模式(也称为怪异模式);
这两种模式主要影响CSS内容的呈现,某些情况下也会影响JavaScript的执行;所以,在开发时,确定浏览器处于何种模式很重要;
起先,是从IE6开始区分渲染页面的模式是Standards mode还是Quirks mode;IE为此给document对象添加一个名为compatMode属性,该属性即用于识别浏览器处于什么模式;如果是标准模式,返回CSS1Compat,反之返回BackCompat;后来,其他浏览器也实现了这个属性,最终HTML5也把这个属性纳入标准;
console.log(document.compatMode); // CSS1Compat
目前,存在以下几种情况:
浏览器都是根据是否有DOCTYPE声明判断,有则为标准模式,值为CSS1Compact,无则为混杂模式,值为BackCompact;因此,一条好习惯就是每个html文档都要有doctype声明;
对于有DOCTYPE声明,但浏览器不能正确识别,则使用混杂模式,值为BackCompact;
如果有xml声明 <?xml version="1.0" encoding="utf-8"?>也是混杂模式;
另外,如果文档的第一行是标签或文本,也为混杂模式;
对于IE来说,这两种模式差别很大,但对其他浏览器来说,差别很小,因此,这两种模式的判断和差别主要是针对IE;
两种模式的具体差别:
在Standards Mode下对于盒模型的解释所有浏览器都是基本一致的,但在Quirks Mode模式下则有很大差别;
在Standards mode中:
元素真正的宽度 = margin + border-width + padding + width;
在Quirks mode中:
元素真正的宽度 = width,而其内容宽度 = width - (margin – padding - border-width);
在标准模式下,所有尺寸都必须包含单位,否则会被忽略,而在混杂模式下,可以不带单位,如:style.width = "20",相当于"20px";
当一个div元素中包含的内容只有图片时,在标准模式下的所有浏览器中,在图片底部都有4像素的空白;但在混杂模式下,div距图片底部默认没有空白;
两种模式获取视口的方式是不同的;
console.log(document.body.clientHeight);
console.log(document.documentElement.clientHeight);
就是说,在BackCompact模式下,取得document的某些属性,如clientWidth、scrollLeft等,使用的是document.body,而标准模式下,使用的是document.documentElement,如:
var height = document.compatMode == "CSS1Compat" ? document.documentElement.clientHeight : document.body.clientHeight;
console.log(height);
documentMode文档模式:
IE8为document对象添加了documentMode属性,即文档模式(document mode),该属性与compatMode属性紧密相关,但该属性不是标准属性,除了IE,其它浏览器都不支持;
console.log(document.documentMode); // 11
页面的文档模式决定了可以使用什么功能,如,文档模式决定了可以使用哪个级别的CSS,可以在Javascript中使用哪些API,以及如何对待文档类型;
在IE8中,有三种不同的呈现模式:
从IE8往后,都遵循了这一规律,比如,为9,表示IE9标准模式,支持ES5,CSS3和更多HTML5的功能;
有了这个属性,就能准确的判断IE的各种版本了,如:
var isIE = !!(window.ActiveXObject || "ActiveXObject" in window);
var ieMode = document.documentMode;
var isIE7 = isIE && ieMode && ieMode == 7;
var isIE8 = isIE && ieMode && ieMode == 8;
var isIE9 = isIE && ieMode && ieMode == 9;
var isIE10 = isIE && ieMode && ieMode == 10;
console.log(isIE); // true
console.log(isIE10); // 切换到10版本,返回true
X-UA-Compatible:
开发者还可以主动要求客户端按照什么文档模式进行渲染,也就是强制浏览器以某种模式渲染页面,此时可以使用HTTP头部信息X-UA-Compatible,或通过等价的<meta>标签来设置:
<meta http-equiv="X-UA-Compatible" content="IE=IEVersion">
IEVersion有可能有以下值:
如:让文档模式像在IE7中一样,可以:
<meta http-equiv="X-UA-Compatible" content="IE=EmulateIE7">
如果不考虑文档类型声明,而直接使用IE8标准模式,可以:
<meta http-equiv="X-UA-Compatible" content="IE=8">
再如,强制以IE5混杂模式渲染:
<meta http-equiv="X-UA-Compatible" content="IE=5" />
如果在IE8以下的浏览器中设置,是无效的,因为该设置是在IE8才开始有的;
使用最新的文档模式:
<meta http-equiv="X-UA-Compatible" content="IE=edge"/>
IE浏览器将总是使用最新版本的文档模式;
另外,也可以同时设置多个值,中间用逗号隔开;
<meta http-equiv="X-UA-Compatible" content="IE=IEVersion">
注意,由右向左进行尝试,即先使用IE8模式,如果失败,则使用IE模式;
最流行的设置:
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1"/>
chrome=1表示可以激活Chrome Frame;
如果安装了Google Chrome Frame(谷歌浏览器內嵌框架)则使用谷歌浏览器内核模式,甚至会使用Chrome的控制台,否则使用最新的IE模式;
head属性:
在HTML5规范中新增了document.head属性,引用文档的<head>元素,属于HTMLHeadElement类型;
console.log(document.head);
console.log(document.head === document.querySelector("head"));
各主流浏览器均支持,但为了兼容低版本的,也可以结合备用方式,如:
var head = document.head || document.getElementsByTagName("head")[0];
如果有多个<head>元素,则返回第一个;
document.head 是个只读属性,为该属性赋值只会静默失败,如果在严格模式中,则会抛出TypeError异常;
字符集属性:
HTML5新增了几个与文档字符集有关的属性,其中,charset属性表示实际使用的字符集,也可以用来指定新字符集;可以通过<meta>元素、响应头部或直接设置charset属性修改这个值,但实际上是只读的,现在已经被characterSet替代,该属性是只读属性,返回当前文档的字符编码,该字符编码是用于渲染此文档的字符集,如:
console.log(document.charset); // UTF-8
此时,可以修改文档的字符集设置,如:
// IE与老版的Edge返回gb2312,其它默认失败
document.charset = "gbk";
console.log(document.charset); // UTF-8
console.log(document.characterSet);
// 同上,但所有浏览器静默失败
document.characterSet = "gbk";
console.log(document.characterSet);
另一个属性是defaultCharset,表示根据默认浏览器及操作系统的设置,当前文档默认的字符集应该是什么,该属性不是标准属性,没什么用处;
console.log(document.defaultCharset); // 只有IE与Safari有值
data-自定义数据属性:
HTML5定义了一种标准的、附加额外数据的方法,即在HTML5文档中,任意以”data-”为前缀的小写的属性名称都是合法的,这样的属性被称为数据集属性,目的是为元素提供与渲染无关的信息,或者提供语义信息;这些属性可以任意添加、随便命名,只要以data-开头即可,如:
<div id="mydiv" data-appId="1234" data-myname="wangwei"></div>
HTMLElement.dataset属性:
在Javascript中也为Element对象上定义了dataset属性,该属性指代一个对象,是元素的data-特性的实时、双向的接口;
dataset属性的值是DOMStringMap接口的一个实例,被用于容纳和展示元素的自定义属(特)性,它就是一个名值对的映射,在这个映射中,每个data-name形式的属性都会有一个对应的属(特)性,只不过属性名没有data-前缀,比如,dataset.x保存的就是data-x属(特)性的值;带连字符的属(特)性对应于驼峰命名属性名,如:data-web-test属(特)性就变成dataset.webTest属性;如:
<div id="mydiv" data-appId="001" data-subtitle="zeronetwork" data-web-description="零点程序员">
// Javascript
var mydiv = document.getElementById("mydiv");
console.log(mydiv.dataset); // DOMStringMap
console.log(mydiv.dataset.subtitle); // zeronetwork
console.log(mydiv.dataset.webDescription); // 零点程序员
console.log(mydiv.dataset.appid); // 只能小写,不能是appId
设置或删除dataset的一个属性就等同于设置或移除对应元素的data-属(特)性,并且在将键值转换为一个属性的名称时会使用相反的转换;
// 判断有没有该属性
if(mydiv.dataset.myname){
console.log(mydiv.dataset.myname);
}
mydiv.dataset.subtitle = "wangwei"; // 修改
mydiv.dataset.imgurl = "images/1.jpg"; // 添加
mydiv.dataset.userName = "wangwei"; // 添加,被转换为data-user-name
delete mydiv.dataset.subtitle; // 删除
遍历DOMStringMap对象;
for(var k in mydiv.dataset){
console.log(k + ":" + mydiv.dataset[k]);
}
与getAttribute()和setAttribute()相比:
在效率上,dataset没有上述两个方法高,但是,这个影响可以忽略不计;从操作上来看,虽然使用dataset不能提高代码的性能,但是对于简洁代码,提高代码的可读性和可维护性是很有帮助的,如:
<div class="user" data-id="123" data-user-name="wangwei" data-sex="男" data-date-of-birth="1998/8/8"></div>
<div class="user" data-id="124" data-user-name="jingjing" data-sex="女" data-date-of-birth></div>
<div class="user" data-id="125" data-user-name="juanjuan" data-sex="女" data-date-of-birth="1995/5/5"></div>
<script>
var users = document.querySelectorAll(".user");
// 使用getAttribute()和setAttribute()
for(var i=0,len=users.length; i<len; i++){
var user = users[i];
var id = user.getAttribute("data-id");
var username = user.getAttribute("data-user-name");
var sex = user.getAttribute("data-sex");
if(!user.getAttribute("data-date-of-birth"))
// user.setAttribute("data-date-of-birth","2020-1-1");
var dateofbirth = user.getAttribute("data-date-of-birth");
console.log("ID:" + id + ",username:" + username + ",sex:" + sex + ",dateofbirth:" + dateofbirth);
}
// 使用dataset
for(var i=0,len=users.length; i<len; i++){
var user = users[i];
var id = user.dataset.id;
var username = user.dataset.userName;
var sex = user.dataset.sex;
if(!user.dataset.dateOfBirth)
user.dataset.dateOfBirth = "2020/1/1";
var dateofbirth = user.dataset.dateOfBirth;
console.log("ID:" + id + ",username:" + username + ",sex:" + sex + ",dateofbirth:" + dateofbirth);
}
</script>
另外,dataset属性在IE中,只有IE11支持,所以在低版本的IE中,如果要使用dataset属性,必须做兼容性处理;
if(mydiv.dataset){
console.log(mydiv.dataset.subtitle);
console.log(mydiv.dataset.webDescription);
}else{
console.log(mydiv.getAttribute("data-subtitle"));
console.log(mydiv.getAttribute("data-web-description"));
}
// 封装一个函数
function getDataset(elt){
if(elt.dataset)
return elt.dataset;
var attrs = elt.attributes, // 元素的属性集合
dataset = {}, // 包装的一个属性集对象
name, // 要获取的特性名
matchStr; // 匹配结果
for(var i=0, len = attrs.length; i<len; i++){
// 匹配data-自定义属性
matchStr = attrs[i].name.match(/^data-(.+)/);
if(matchStr){
// 转成小驼峰
name = matchStr[1].replace(/-([\da-z])/gi, function(all, letter){
return letter.toUpperCase();
});
dataset[name] = attrs[i].value;
}
}
return dataset;
}
var dataset = getDataset(mydiv);
console.log(dataset);
另外data-属性并不是只在Javascript中使用,在CSS中应用的场景也很多,如:
<style>
p[data-font-size='2em']{font-size: 2em;}
p[data-font-size='3em']{font-size: 3em;}
</style>
<p data-font-size="3em">零点程序员</p>
<p data-font-size="2em">王唯</p>
// 又如
<style>
#mydiv::after{background-color: rgba(0,0,0,.2); content: attr(data-content);}
</style>
<div id="mydiv" data-content="王唯是好人">大师哥</div>
dataset应用的场景还是非常多的,一般来说,为了给元素添加一些不可见的数据,并要进行后续的处理,就可以用到自定义数据属性;比如,配合CSS开发一些动画效果,或在跟踪链接等应用中,通过自定义数据属性能方便地知道点击来自页面中的哪个部分;
<a href="https://www.zeronetwork.cn" data-title="零点网络">零点网络</a>
<script>
window.onload = function(){
var aElts = document.querySelectorAll("a");
for(var i=0,len=aElts.length; i<len; i++){
aElts[i].addEventListener("click",function(e){
e.preventDefault();
doDataset(this);
},false);
}
var aDataset = [];
function doDataset(elt){
var o = {title:elt.dataset.title, href:elt.href, page:location.pathname};
aDataset.push(o);
console.log(aDataset);
}
}
</script>
// 小示例
<style>
.banner{
background:url("images/2.jpg") no-repeat center; background-size:cover;
}
.fadeInDown{opacity: 0; transform: translateY(20px);}
</style>
<div class="banner">
<h2 class="fadeInDown" data-duration=".8" data-delay="400">零点程序员</h2>
<h3 class="fadeInDown" data-duration="1" data-delay="800">大师哥王唯</h3>
<p class="fadeInDown" data-duration="1" data-delay="1000"><a href="#">更多</a></p>
</div>
<script>
window.onload = function(){
var elts = document.getElementsByClassName("fadeInDown");
// for(var i=0,len=elts.length; i<len; i++){
// (function(){
// var elt = elts[i];
// var dataset = elt.dataset;
// setTimeout(function(){
// elt.style.opacity = 1;
// elt.style.transform = "translateY(-20px)";
// elt.style.transition = "all " + dataset.duration + "s linear";
// }, dataset.delay);
// })();
// }
Array.prototype.forEach.call(elts, function(v,k){
console.log(v);
var dataset = v.dataset;
setTimeout(function(){
v.style.opacity = 1;
v.style.transform = "translateY(-10px)";
v.style.transition = "all " + dataset.duration + "s linear";
}, dataset.delay);
});
}
</script>
Web前端开发之Javascript
*请认真填写需求信息,我们会在24小时内与您取得联系。