如果没有jQuery,请将“显示更多”显示为“显示更少”

时间:2013-10-27 14:20:22

标签: javascript css

我知道使用jQuery这是相当直接的,但是对于大学作业需要在点击更多链接时插入新段落然后在点击较少链接时删除它们 - 我们不使用css或jQuery所以我的代码到目前为止看起来像这样 - 插入工作,但删除less()函数没有任何想法为什么(甚至尝试简单的警告从少一点功能和一个href上的返回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>

1 个答案:

答案 0 :(得分:5)

好的,你有很多学习要做的事情。我不是故意这么做,但这是一个我如何解决这个问题的例子:

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);

现在,这本身就没有意义,所以我已经开始设置this fiddle

还有很多事情要做(即卸载事件处理程序,隐藏较少的链接等...)

帮助您理解代码的一些说明:

  • addEventListener:我没有设置属性,也没有使用onloadonclick直接绑定事件处理程序,而是添加事件侦听器。这些有利于保持JS方面的一切。您在代码中的某处使用了setAttribute('onclick'...)。这在DOM中设置了一个属性,它引用了JS。这被认为是不好的做法,而且过时了。
  • l - 回调。我的主要回调(window.addEventListener('load', function l()...被称为l。在这个函数中,我查询DOM三次(排序)并将这些DOM节点的引用分配给变量:morelessdiv。接下来,我声明一个数组,以保存我正在创建的所有节点。一种堆栈,所以我永远不需要查询dom来获取对这些节点的引用我创建的节点。
  • 我还声明了一个函数(rmHandle),它将处理less链接上的点击。因为我在l的范围内声明了这个函数,所以该函数可以访问我之前声明的所有变量(lessmoreadded)。再说一遍:我永远不需要查询DOM ......
  • more.addEventListener:此链接必须在关闭时起作用,因此我在加载时将我的事件侦听器附加到此DOM节点。
  • no return false:您的问题表明您知道/使用过jQuery。 jQ中的return false和JavaScript 中的return false不是同一件事。如果你将一个事件处理程序附加到VanillaJS中的表单return false可能会让你大吃一惊,因为有时:表单仍然会被提交。了解W3C事件模型:捕获和冒泡阶段。 quirksmode.org是一个很好的细节资源。您了解我为什么要尽快明确地调用这些方法。
  • document.createTextNode:现在我也承认时不时地使用innerHTML。但是,既然你正在学习,我也可能会指出innerHTML 不是标准,官方标准是使用createTextNode
  • 最后,我删除了load事件监听器Because IE tends to leak memory if you don't。然后,回调超出了范围,你无能为力。所以一切都可以标记为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);
};

您根本不需要第二个DOM查询来完成onclick功能。这是因为如果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
}

这是怎么发生的? funcVarconsole.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)

同样适用于funcVar。只有这次,JS才会扫描function goodLocal()//the goodLocal name is defined as the function! 的范围,匿名函数的范围全局命名空间。为什么不使用全局变量?好吧,它们显然更慢,它们可以改变状态,因为函数可以自由访问它们,并且它们会阻塞内存(垃圾收集器只释放不再在任何地方引用的内容。全局命名空间总是可访问的。)

第二种情况有点棘手,但不是很多:

goodLocal

此名称掩盖了外部作用域中的变量。 JS 启动扫描本地范围,并发现goodLocal指向该函数。它永远不会检查外部范围,因此它永远不会在父函数中看到evilGlobal var 这同样适用于function goodLocal(evilGlobal)

funcVar

参数是一个变量,在函数范围内声明。 JS永远不会扫描全局ns,因为两个名称都可以解析为localy,除了:

的console.log(funcVar());

这将导致父函数的范围扫描,该函数声明var para1变量,并将之前讨论的函数分配给它。该函数仍然表现不同,因为函数在其自己的范围/上下文中被调用 呼叫上下文也非常棘手,所以我会暂时掩盖这一点。

回到你的代码:其他陈述实际上是你之前写过的东西的重复:var para2和{{1}}是多余的,如果你只是让它们在外部范围内可访问

好吧,继续阅读,继续学习,你很快就能得到它......