整合营销服务商

电脑端+手机端+微信端=数据同步管理

免费咨询热线:

DecSoft HTML Compiler 2024

DecSoft HTML Compiler 2024

ecSoft HTML Compiler 2024.2 (x64) 是一款可以将现代 HTML 应用程序(如单页应用程序)编译为 Microsoft Windows? 32 位和 64 位独立可执行文件的工具。应用程序的文件不会被提取到用户计算机中,而是在基于 Chromium 的现代浏览器环境中运行。

它很安全 您的 HTML 应用程序将被编译为 Microsoft Windows 32 位和 64 位可执行文件。除非您想要提取某些特定的文件,否则您的应用程序文件不会被提取到最终用户计算机中。

没有限制! 您可以将几乎任何现代 HTML 应用程序(如电子书、调查、测验、杂志、演示文稿、相册和画廊、游戏等)转换为 Windows 可执行程序。

超级简单 您可以使用用户图形界面或命令行工具来编译您的 HTML 应用程序,只需指定应用程序 "index.html" 文件的路径。

看一下! 下一个视频展示了 DecSoft HTML Compiler 的工作方式!在短短一分钟内,您就可以看到 DecSoft App Builder 的 "Database" 应用程序示例是如何被转换为 Microsoft Windows 独立可执行文件的。

CLI 支持 除了可视化环境外,DecSoft HTML Compiler 还包括一个命令行编译器。这样,您就可以从命令行简单快速地编译应用程序。

非常简单 DecSoft HTML Compiler 不会向用户显示任何界面元素。但这很好,因为这样您的应用程序看起来正是您想要的,没有任何不必要的干扰!

非常强大 DecSoft HTML Compiler 为您的应用程序提供了一些外部 JavaScript,以超越现代 HTML 应用程序的功能,例如,提供编写文件、执行程序、浏览文件夹等能力。

更新内容

将 Bootstrap CSS 框架(CSS 和 JavaScript)更新到程序欢迎页面、程序帮助、程序关于和程序 "read me" 文件的最新 5.3.3 版本。此版本的 Bootstrap CSS 包括许多更改、修复和增强功能。

DecSoft HTML Compiler 可以应用于许多场景,包括但不限于:

制作电子书:将基于 HTML 的电子书编译为独立的可执行文件,方便用户阅读和分享。

制作调查和测验应用程序:将在线调查问卷或测验编译为桌面应用程序,使用户可以在本地环境中进行填写和提交。

制作杂志和演示文稿:将互动性强的杂志或演示文稿转换为独立的桌面应用程序,提供更好的用户体验。

制作相册和画廊应用程序:将在线相册或画廊制作成桌面应用程序,方便用户浏览和管理照片。

制作游戏应用程序:将基于 HTML 的游戏编译为可执行文件,让用户可以在本地玩游戏而无需依赖浏览器。

教育和培训:将在线教育课程、培训材料或学习应用程序编译为桌面应用程序,方便学生和学习者在离线状态下访问和学习。

商业演示和销售工具:将产品演示、销售演示或营销工具转换为独立的应用程序,方便销售团队在客户面前展示和推广产品。

数据收集和分析:将数据收集应用程序编译为桌面应用程序,方便用户在本地环境中进行数据输入和分析,保护数据的安全性和隐私。

媒体播放器:将基于 HTML 的音频或视频播放器编译为独立的桌面应用程序,提供更好的播放性能和功能。

应用程序封装和保护:将基于 HTML 的应用程序编译为可执行文件,以保护源代码和知识产权,并提供更好的安全性和稳定性。

游戏开发:将基于 HTML5 的游戏编译为桌面应用程序,提供更好的性能和用户体验。

数据可视化:将数据可视化应用程序编译为桌面应用程序,方便用户在本地环境中查看和分析数据图表。

客户端软件:将基于 HTML 的客户端软件(如邮件客户端、聊天工具等)转换为独立的桌面应用程序,提供更好的用户界面和功能扩展。

互动式演示:将交互式演示或培训应用程序编译为桌面应用程序,使用户可以在离线环境中进行演示和培训。

内容发布:将在线内容发布系统转换为桌面应用程序,方便用户管理和发布内容。

桌面工具和实用程序:将实用工具、计算器、日历等工具应用程序编译为桌面应用程序,提供更好的访问和使用体验。

套模板不仅仅带后台(SiteServer CMS),而且还带模板使用说明手册的。不仅仅可以下载到模板,还能下载到整个后台,本地直接配置起来就可以使用。

1、企业站模板一

在线浏览地址:http://templates.siteserver.cn/medraut/index.html

GitHub下载地址:https://github.com/siteserver/template-medraut

这是一套响应式的企业网站,适合企业、公司、或者产品型公司。分类展示,信息展示、增加网站的互动性。跟Banner大图对应起来,整个网站展示方面可以做的非常绚丽多彩。

2、门户站模板

在线浏览地址:http://templates.siteserver.cn/girish/index.html

GitHub下载地址:https://github.com/siteserver/template-girish

这一套自适应的站长模板,这套模板,我们会发现它虽然模块不少,有评论、有注册登录、有搜索、有文章排行、专题等模块,但它的结构还是比较简单的,模板页面数量少,首页、栏目页、文章内容页,栏目页还跟首页结构一样。

3、企业站模板二

在线浏览地址:http://templates.siteserver.cn/batraz/index.html

GitHub下载地址:https://github.com/siteserver/template-batraz

这是一套响应式网站模版,适应于互联网、企业、媒体、产品型公司以及各种企业集团网站模板所有图片在手机端都进行过处理,而响应式网站不同设备内容源码是一样的。因此,你不得不担心响应式网站在移动端的速度以及流量消耗,我们采用图片处理技术后,在手机上会只加载尺寸更小的图片。

4、大学官网模板

在线浏览地址:http://templates.siteserver.cn/albrecht/index.html

GitHub下载地址:https://github.com/siteserver/template-albrecht

这是一套学校模板,适用于各类大学、综合院校,当然删减一些栏目,一样适用各个中小学网站。同样作为一套自适应的学校模板,这套模板包含了学校主页、院系列表页、院系主页、科研专题页、教学专题页、周边生活专题、图片列表页、人员列表专页、新闻列表页、搜索结果页、内容页等板块。

5、博客模板

在线浏览地址:http://templates.siteserver.cn/scevola/index.html

GitHub下载地址:https://github.com/siteserver/template-scevola

这是一套响应式博客模版,适应于科技、个人博客、互联网、媒体等产品型公司网站模板。所有图片在手机端都进行过处理,简单而又清爽的企业、博客响应式模板。

6、单页H5模板

在线浏览地址:http://templates.siteserver.cn/milenko/index.html

GitHub下载地址:https://github.com/siteserver/template-milenko

这是一套响应式的单页宣传性网站,适合一些房产、或者产品型公司,简单的展示一些个人或者企业信息。图片切换板块对图片进行分类展示,可以保持内容图片的多样性又不杂乱,增加网站的互动性。可以一次性展示多张图片,跟banner大图对应起来,整个网站展示方面可以做的非常绚丽多彩。整个网站单页展示,虽然看起来略显单薄,但对应有些企业来说非常适合,展示必要的信息,用户浏览起来直观、不繁重。

7、企业站模板三

在线浏览地址:http://templates.siteserver.cn/aeson/index.html

GitHub下载地址:https://github.com/siteserver/template-aeson

这是一套响应式网站模版,适应于地产、汽车、互联网、建筑、媒体、家居、产品型公司以及各种企业集团网站模板所有图片在手机端都进行过处理,而响应式网站不同设备内容源码是一样的。

8、企业站模板四

在线浏览地址:http://templates.siteserver.cn/kevan/index.html

GitHub下载地址:https://github.com/siteserver/template-kevan

这是一套响应式网站模版,适应于企业、汽车公司、产品型公司以及各种企业集团网站模板所有图片在手机端都进行过处理,而响应式网站不同设备内容源码是一样的。因此,你不得不担心响应式网站在移动端的速度以及流量消耗,我们采用图片处理技术后,在手机上会只加载尺寸更小的图片。

内容是《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:一个包含下列属性的对象:

  • behavior:可选,定义动画过渡效果,"auto"或 "smooth" 之一,默认为 "auto";
  • block:可选,定义垂直方向的对齐,"start", "center", "end", "nearest"之一,默认为 "start";
  • inline:可选,定义水平方向的对齐,"start", "center", "end", "nearest"之一,默认为 "nearest";
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把这个属性纳入了标准之中。

该属性有三个可能的值:

  • loading:正在加载文档;
  • interactive:可交互的,文档已被解析,"正在加载"状态结束,但是诸如图像,样式表和框架之类的资源仍在加载;
  • complete:文档和所有资源已完成加载,表示load状态的事件即将被触发;
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中,有三种不同的呈现模式:

  • 为5,则为混杂模式(IE5),IE8或更高版本中的新功能无法使用;
  • 为7,表示IE7仿真模式,IE8或更高版本中的新功能无法使用;
  • 为8,表示IE8标准模式,IE8中的新功能都可以使用,如可以使用Selectors API,更多CSS2级选择器和某些CSS3功能,还有一些HTML5的功能;不过IE9中的新功能无法使用;

从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有可能有以下值:

  • Edge:始终以最新的文档模式来渲染页面;忽略文档类型声明;
  • EmulateIE9(8、7):如果有文档声明,则以IE9(8、7)标准模式渲染页面,否则将文档模式设置为IE5;
  • 9、8、7、5:强制以IE9(8、7、IE5模式)标准模式渲染页面,忽略文档类型声明;

如:让文档模式像在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