[英]Without jQuery, make a “show more” “show less” a href
我知道使用jQuery非常簡單,但是對於大學作業,需要在單擊更多鏈接時插入新段落,然后在單擊較少鏈接時將其刪除-我們不使用CSS或jQuery,因此到目前為止我的代碼看起來像這樣-插入有效但是remove less()函數沒有任何原因(即使嘗試了less函數的簡單警報,並且href上的return false也無法將頁面重定向到無JavaScript默認值。
window.onload= function()
{
var href = document.getElementById("more");
href.setAttribute("onclick","more(); return false;");
var more = document.getElementById("more");
more.onclick = function more()
{
var para1 = document.createElement("p");
para1.setAttribute("id", "para1");
var para1Cont = document.createTextNode("my text block 1");
para1.appendChild(para1Cont);
var more = document.getElementById("more");
more.parentNode.insertBefore(para1,more);
var para2 = document.createElement("p");
para2.setAttribute("id", "para2");
var para2Cont = document.createTextNode("My text block 2");
para2.appendChild(para2Cont);
more.parentNode.insertBefore(para2,more);
var toLess = more.setAttribute("id", "less");
var less = document.getElementById("less");
less.setAttribute("onclick", "less(); return false;");
less.innerHTML ="click here for less";
return false;
};
var less = document.getElementById("less");
less.onclick = function less()
{
var para1 = document.getElementById("para1");
var para2 = document.getElementById("para2");
alert("fr");
alert( para1.innerHTML);
para1.parentNode.removeChild(para1);
para2.parentNode.removeChild(para2);
var less = document.getElementById("less");
var toMore = less.setAttribute("id", "more");
var more = document.getElementById("more");
more.setAttribute("onclick", "more(); return false;");
more.innerHTML ="click here for more";
return false;
};
};
和html代碼
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
<head>
<title>Help meeeee</title>
<link rel="stylesheet" type="text/css" href="styles/style.css">
<link href="scripts/mystyles.css" rel="stylesheet" type="text/css" />
</head>
<body>
<div id="header">
<h1>test page</h1>
</div>
<div id="content">
<a href="nojs.htm" id="more"> click for more </a>
</div>
<script type="text/javascript" src="scripts/myscript.js"></script>
</body>
好的,您有很多學習要做。 我並不是說這很糟糕,但這是我如何解決此問題的vanillaJS示例:
window.addEventListener('load',function l()
{//use addEventListener, to avoid mem-leaks
"use strict";//for JSLint
var more = document.getElementById('more'),
less = document.getElementById('less'),
div = more.parentNode,//3 DOM reference, to be used by event handlers
added = [],//keep references to added elements, use as stack
rmHandle = function(e)
{//callback definition, don't bind unless less link should be usable
var rm = added.pop();
rm.parentNode.removeChild(rm);
if (added.length === 0)
{
less.removeEventListener('click', rmHandle, false);
}
e.preventDefault();
e.stopPropagation();
};
more.addEventListener('click',function(e)
{//add node:
var newP, count = added.length;
e.preventDefault();
e.stopPropagation();
if (count === 0)
{//bind less event handler here
less.addEventListener('click', rmHandle, false);
}
++count;
newP = document.createElement('p');//create node
newP.setAttribute('id','param'+count);//set id
newP.appendChild(document.createTextNode('New Paragraph #'+count));//add txt content
added.push(newP);//keep reference to node
div.insertBefore(newP, less);//append at end...
},false);
window.removeEventListener('load',l,false);//unbind load handler, this is the leak in IE
}, false);
現在,這本身是有點意義的,所以我已經先行一步,並成立這個小提琴
還有很多事情要做(即,卸載事件處理程序,隱藏較少的鏈接等...)
一些說明可幫助您理解代碼:
addEventListener
:不是添加服裝,也不是使用onload
或onclick
直接綁定事件處理程序,而是添加事件偵聽器。 這些具有保留所有JS端的好處。 您在代碼中的某處使用setAttribute('onclick'...)
。 這將在DOM中設置一個屬性,該屬性會引用回JS。 這被認為是不好的做法,並且已經過時了。 l
回調。 我的主回調( window.addEventListener('load', function l()...
稱為l
。在此函數中,我查詢DOM三次(某種程度),並將對這些DOM節點的引用分配給變量: more
, less
和div
接下來,我聲明一個數組,以容納要創建的所有節點,這是一種堆棧,因此無需查詢dom即可獲得對我創建的那些節點的引用。 rmHandle
),它將處理less
鏈接上的單擊。 因為我在l
的范圍內聲明了此函數,所以該函數可以訪問我先前聲明的所有變量( less
, more
, added
)。 再說一次:我永遠不需要查詢DOM ... more.addEventListener
:此鏈接必須more.addEventListener
開始工作,因此我在加載時將事件偵聽器附加到此DOM節點。 return false
:您的問題表明您知道/曾經使用過jQuery。 return false
在JQ和return false
在JavaScript 是不一樣的東西 。 如果將事件處理程序附加到VanillaJS中的表單,則return false
可能會讓您大吃一驚,因為有時:表單仍會提交。 閱讀有關W3C事件模型的信息:捕獲和冒泡階段。 quirksmode.org是獲取詳細信息的好資源。 您將了解為什么我會盡快足夠明確地調用這些方法。 document.createTextNode
:現在,我也將不時使用innerHTML
。 但是,既然您正在學習,我可能會指出, innerHTML
不是標准的 ,官方標准是使用createTextNode
。 load
事件偵聽器, 因為IE傾向於泄漏內存(如果您不這樣做的話) 。 然后,回調超出范圍,您對此無能為力。 因此,一切都可以標記為GC,並且沒有任何辦法可以泄漏內存,但是... 編輯:
我將承認,列出一些列表項,其中僅涉及JS在嵌套作用域中解析變量名的方法還不夠清楚。 當我第一次開始學習閉包時,這並不適合我,這當然不足以解釋我發布的代碼為什么會比您的代碼性能好很多。
因此,如果您願意的話,我將使用代碼摘錄來進一步解釋這一點,並逐步進行清理復習:
var less = document.getElementById("less");
less.onclick = function less()
{
var para1 = document.getElementById("para1");
var para2 = document.getElementById("para2");
alert("fr");
alert( para1.innerHTML);
para1.parentNode.removeChild(para1);
para2.parentNode.removeChild(para2);
var less = document.getElementById("less");
var toMore = less.setAttribute("id", "more");
var more = document.getElementById("more");
more.setAttribute("onclick", "more(); return false;");
more.innerHTML ="click here for more";
return false;
};
這段代碼對您來說應該很熟悉(畢竟是從您的問題中粘貼出來的)。 現在我為什么要改變這個? 首先:DOM API( 不是 JS BTW的一部分)緩慢,笨拙,不合邏輯,並且是沮喪的主要根源,過多使用它會殺死林地小動物。 在此片段中,我們看到了以下內容:
var less = document.getElementById("less");
less.onclick = function less()
{
//...
var less = document.getElementById("less");
}
因此, less
的名稱在分配上下文中使用了3次。 這些分配中有兩個涉及DOM查詢。 不只是一個查詢,而且是完全相同的查詢 : document.getElementById("less");
! 人們常說,編寫良好代碼的規則之一是“ 不要重復自己” 。
你可能聽說過的另一件事是,使用松散類型的語言,即使,它不是一個壞主意, 不分配不同類型的一個變量。 盡管這樣做是在編寫function less(){}
。 除了一些語義上的差異(有時很重要,但這是另一些時間)之外,這基本上與以下操作相同:
var less = function(){};
這些分配中的每一個都掩蓋了前一個分配。 如果你會寫:
var less = document.getElementById("less");
less.onclick = function less_func()
{
console.log(less);//logs a dom reference!
};
//or even:
less.onclick = function()
{//anonymous or lambda functions are valid... and quite common, too
console.log(less);
};
您完全不需要使用onclick
函數的第二個DOM查詢。 這是因為JS嘗試將所有變量解析為先前聲明的變量的方式。 考慮一下:
var evilGlobal = 'Do not use Globals';
function()
{
var goodLocal = 'Declared in function',
funcVar = function()
{
console.log(goodLocal);
console.log(evilGlobal);
},
func2 = function goodLocal(evilGlobal)
{
console.log(goodLocal);
console.log(evilGlobal);
console.log(funcVar());
};
funcVar();//logs Declared in function and Do not use Globals
func2();//logs itself (function), and undefined and then same as above
func2(goodLocal);//logs itself, Declared in Function and the same as funcVar
}
這是怎么發生的? 在funcVar
這非常簡單:
console.log(goodLocal);//<-- JS looks inside funcVar's function scope for var goodLocal
//not found? JS looks in the outer scope, that of the anonymous function that starts
//with var goodLocal = 'Declared in Function'
//This is the var used
同樣適用於console.log(evilGlobal)
。 只有這一次,JS才掃描funcVar
的范圍,匿名函數的范圍和全局名稱空間。 為什么不使用全局變量? 好吧,它們顯然較慢,它們可以更改狀態,因為函數可以自由訪問它們,並且阻塞了內存(垃圾收集器僅釋放不再在任何地方引用的內容。始終可以訪問全局名稱空間)。
第二種情況有點棘手,但不是很多:
function goodLocal()//the goodLocal name is defined as the function!
此名稱掩蓋了外部作用域中的變量。 JS 開始掃描本地范圍,並發現goodLocal
指向該函數。 它從不檢查外部作用域,因此從不在父函數中看到goodLocal
var。
這同樣適用於evilGlobal
:
function goodLocal(evilGlobal)
參數是在函數范圍內聲明的變量。 JS絕不會掃描全局ns,因為這兩個名稱都可以解析為本地語言,除了:
的console.log(funcVar());
這將導致對父函數進行范圍掃描,該函數聲明了funcVar
變量,並為其分配了先前討論的函數。 該函數的行為仍然沒有什么不同,因為該函數是在其自己的作用域/上下文中調用的。
調用上下文也很棘手,因此我將在稍后介紹一下。
回到您的代碼:其他語句實際上也是您之前編寫的內容的重復: var para1
和var para2
是多余的,如果只是讓它們在外部范圍內可訪問。
嗯,只要繼續閱讀並繼續學習,您就會很快得到它。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.