興未艾的HTML5市場最近頻放大招,HTML5峰會的盛大開幕,各大企業的跨界合作都為整個行業添上了濃墨重彩的一筆。其中,一家新型互聯網企業的表現尤為耀眼!7月初,一場“7客聯盟”活動的強勢來襲震蕩設計圈和互聯網,目前“7客風暴”仍在繼續,大有席卷全網之勢;多次跨界電影娛樂圈,與愛情喜劇片《再次出發》、都市愛情電影《戀愛中的城市》、今夏唯一史詩愛情巨制《太平輪·彼岸》等強強聯手,打造深度營銷戰略合作;牽手知名珠寶品牌I DO,打開移動互聯網下實體業態的精準社會化戰略部署......這些“動作”不斷的背后,70度——【產品營銷推廣專家】進入大眾視線。
近一年,HTML5模式以它獨有的“魅力”浸入人們手機,走進人們生活,甚至影響著人們的日常。而隨著互聯網車輪的向前,用戶需求的不斷轉變,HTML5的發展之路愈加撲朔迷離。
70度的發力,使整個HTML5市場的前瞻性更加清晰明確。70度不僅是一款基于HTML5模式上的平臺級產品應用,還是集場景制作、內容定制、企業營銷和電子商務于一體的互聯網終端產品。專業化的技術支持、規模化的運作模式、優質的用戶體驗、完善的產品生態鏈是70度打入企業主和消費者“陣地”的四大核心優勢。
任何消費級市場的價值鏈條都由三部分構成:供應商、渠道、消費者。供應商通過渠道傳遞商品信息到消費者手中,在價值鏈中的某一環形成橫向壟斷,或者通過融合某兩個環節而在縱向形成競爭優勢,是將收益擴大的兩種最優手段。
在互聯網興起之前,縱向競爭優勢主要體現在對渠道的控制上。互聯網興起帶來的顛覆徹底逆轉了這樣的趨勢。其一,網絡將(數字化產品的)渠道免費化,很大程度上消除了傳統的“渠道+供應商”的優勢。其二,互聯網消滅了交易(用戶消費信息的)成本的事實,給了渠道商向下游也就是消費者一端融合的動機。于是,直達受眾內心的“渠道”資源成為了眾多上游供應商的核心關注點。
這一契機下,HTML5模式憑借獨有的社會化媒體屬性,受到眾多企業主和品牌商的青睞。70度正在做的事,就是打破HTML5模式的傳統怪圈,告別純單一的場景制作平臺模式,打造以HTML5模式為主導的互聯網營銷產品鏈和溝通消費者的優質渠道。
70度是北京智云時代旗下的一款重量級互聯網產品,憑借HTML5場景制作、數據監控分析、產品營銷推廣、商品防偽溯源、用戶購買導流等功能打造的生態閉環,再結合北京智云時代旗下另一款70度姊妹產品“瘋傳”的百萬級自媒體資源和廣告分發服務,讓企業主和品牌商在互聯網時代下的社會化媒體營銷更精準更有效,和消費者之間的距離更親近。
不論互聯網如何發展,但是現下70度正在做的事,已經在慢慢改變整個HTML5行業......
內容是《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
一篇文章《HTML5(五)——Canvas API》介紹 canvas 繪制基本圖形,這節開始介紹canvas的高級操作。
canvas 轉換常用的幾種方法介紹,如下:
方法 | 描述 |
scale() | 縮放當前繪圖至更大或更小。 |
rotate() | 旋轉當前繪圖。 |
translate() | 重新映射畫布上的 (0,0) 位置。 |
transform() | 替換繪圖的當前轉換矩陣。 |
setTransform() | 將當前轉換重置為單位矩陣。然后運行 transform()。 |
1.1 、scale - 縮放
使用語法:scale(x,y)
x:表示水平方向的縮放倍數
y:表示垂直方向的縮放倍數
eg:canvas 繪制的矩形框放大兩倍,代碼如下:
var canvas = document.getElementById("canvas")
var ctx = canvas.getContext("2d")
ctx.scale(2,2)
ctx.fillStyle="red"
ctx.fillRect(0,0,200,200)
1.2、translate - 畫布平移
使用語法:translate(x,y)
x:添加到水平坐標上的位置
y:添加到垂直坐標上的位置
設置之后開始繪制的圖片位置從(x,y)算起。
eg:繪制兩個一樣的矩形,一個在平移前繪制,一個在平移后繪制,代碼如下:
var canvas = document.getElementById("canvas")
var ctx = canvas.getContext("2d")
ctx.fillStyle="red"
ctx.fillRect(0,0,200,200)
//平移
ctx.translate(200,200)
ctx.fillRect(0,0,200,200)
運行結果如圖:
1.3 、rotate - 旋轉
使用語法:rotate(angle)
angle 旋轉弧度,如果想使用角度,可以把角度轉成弧度,公式為:deg * Path.PI/180。
eg:將一個矩形旋轉45度,代碼如下:
var canvas = document.getElementById("canvas")
var ctx = canvas.getContext("2d")
//旋轉45度
ctx.rotate(45*Math.PI/180)
ctx.fillStyle="red"
ctx.fillRect(0,0,200,200)
運行結果如圖:
根據上述結果我們發現旋轉的時候,默認原點是畫布的起始點,我們想要的旋轉是在矩形框中心為原點的旋轉,此時我們需要借助上translate平移,重置一下原點,修改上述代碼為:
<canvas width="400" height="400" id="canvas"></canvas>
var canvas = document.getElementById("canvas")
var ctx = canvas.getContext("2d")
ctx.translate(200,200)
ctx.rotate(45*Math.PI/180)
ctx.translate(-200,-200)
ctx.fillStyle="red"
ctx.fillRect(100,100,200,200)
運行結果如圖:
1.4、transform - 矩陣變換
使用語法:transform(a,b,c,d,e,f)
transform可以替代前邊平移、縮放、旋轉三者,如下:
// 平移
translate(x,y) <=> transform(1,0,0,1,x,y) <=> transform(0,1,1,0,x,y)
// 縮放
sacle(x,y) <=> transform(x,0,0,y,0,0)
// 旋轉
rotate(angle) <=> transform(Math.cos(angle*Math.PI/180), Math.sin(angel*Math.PI/180), -Math.sin(angle*Math.PI/180), Math.cos(angle*Math.PI/180))
1.5、setTransform - 矩陣變換
setTransform()方法將變換的矩陣進行重置,它把當前的變換矩陣重置為單位矩陣
使用語法:transform(a,b,c,d,e,f)
各參數說明:水平旋轉、水平傾斜、垂直傾斜、垂直縮放、水平移動、垂直移動
setTransform() 方法把當前的變換矩陣重置為單位矩陣,然后以相同的參數運行 transform()。
drawImage() 在畫布上繪制圖像、畫布或視頻。也能夠繪制圖片的一部分,增加或減少圖像的尺寸。以下是三種常見使用語法:
上述參數表示的意義如下:
參數 | 描述 |
img | 規定要使用的圖像、畫布或視頻。 |
sx | 可選。開始剪切的 x 坐標位置。 |
sy | 可選。開始剪切的 y 坐標位置。 |
swidth | 可選。被剪切圖像的寬度。 |
sheight | 可選。被剪切圖像的高度。 |
x | 在畫布上放置圖像的 x 坐標位置。 |
y | 在畫布上放置圖像的 y 坐標位置。 |
width | 可選。要使用的圖像的寬度。(伸展或縮小圖像) |
height | 可選。要使用的圖像的高度。(伸展或縮小圖像) |
eg:利用語法3,進行繪制圖片的部分內容,實現如下效果:
給上述兔子順便加一個點擊屏幕暫停開始功能,完整代碼如下:
<canvas width="400" height="400" id="canvas"></canvas>
<script>
var canvas = document.getElementById("canvas")
var ctx = canvas.getContext("2d")
var img = new Image()
let pause = false,frameCounter = 0,i=0;
img.src = "./rotate.png"
img.onload = function(){
requestAnimationFrame(next)
}
function next(){
ctx.clearRect(0,0,canvas.width,canvas.height)
if(frameCounter%5 == 0){ //frameCounter 控制動畫速度
i++
if(i==11)i=0
}
ctx.drawImage(img,
0,i*240,240,240,
0,0,240,240) // 每張圖片寬高都是240,具體參數根據圖片而定
frameCounter ++
if(!pause)requestAnimationFrame(next)
}
window.onclick = function(){
pause = !pause
next()
}
</script>
eg:使用 canvas 畫布處理視頻,使用定時器繪制視頻的當前幀,連續起來就是一個視頻,需要注意的是必須處理暫停和開始播放兩種操作,具體代碼如下:
var v=document.getElementById("video1");
var c=document.getElementById("myCanvas");
ctx=c.getContext('2d');
v.addEventListener('play',function() {var i=window.setInterval(function()
{ctx.drawImage(v,0,0,270,135)},20);},false);
v.addEventListener('pause',function() {window.clearInterval(i);},false);
v.addEventListener('ended',function() {clearInterval(i);},false);
常見的像素級的操作有三種:
3.1、getImageData
使用語法:getImageData( x , y , width , height )
返回一個 imageData 對象,用來描述 canvas 區域隱含的像素數據,這個區域通過像素表示,起點是( x , y ),寬高為 widht 和 height 。
imageData 對象包含三個屬性:
3.2、createImageData
使用語法:
createImageData( width , height )
創建一個空白的 imageData 對象,新對象的默認像素值 transparent black。對于imageData對象中的每個像素值,都存在 rgba 這四方面的信息,即:
新對象默認像素值為(0,0,0,0)。
eg:如果我們想把 imageData 中一個像素變為紅色時,可以改變第一和第四位信息,代碼如下:
var imageData = ctx.createImageData(100,100)
imageData.data[0] = 255
imageData.data[1] = 0
imageData.data[2] = 0
imageData.data[3] = 255
3.1、putImageData
使用語法:
putImageData( imgData , x , y , dirtyX , dirtyY , dirtyWidth ,dirtyHeight );
參數及意義:
參數 | 描述 |
imgData | 規定要放回畫布的 ImageData 對象。 |
x | ImageData 對象左上角的 x 坐標,以像素計。 |
y | ImageData 對象左上角的 y 坐標,以像素計。 |
dirtyX | 可選。水平值(x),以像素計,在畫布上放置圖像的位置。 |
dirtyY | 可選。水平值(y),以像素計,在畫布上放置圖像的位置。 |
dirtyWidth | 可選。在畫布上繪制圖像所使用的寬度。 |
dirtyHeight | 可選。在畫布上繪制圖像所使用的高度。 |
通過 getImageData 復制的指定矩形像素數據,編輯之后,通過 putImageData 方法將圖像數據放回畫布上。
eg:添加濾鏡效果:上述兔子是白色的變換成紅色兔子,這時需要把綠色和藍色都設置成0即可,代碼如下:
*請認真填寫需求信息,我們會在24小時內與您取得聯系。