[英]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.