0

我知道这使用 jQuery 相当简单,但是对于大学作业,需要在单击更多链接时插入新段落,然后在单击更少链接时删除它们——我们不使用 css 或 jQuery,所以我的代码到目前为止看起来像这样——插入有效但是 remove less() 函数不知道为什么(甚至尝试了来自 teh less 函数的简单警报,并且 a 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>

4

1 回答 1

5

好的,你有很多学习要做。我的意思并不是说不好,但这里有一个 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);

现在,这本身有点没有意义,所以我继续设置这个小提琴

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

一些澄清,以帮助您理解代码:

  • addEventListeneronload:我没有设置属性,也没有使用or直接绑定事件处理程序onclick,而是添加了事件侦听器。这样做的好处是保留了 JS 端的所有内容。您正在setAttribute('onclick'...)代码中的某处使用。这在 DOM 中设置了一个属性,该属性引用回 JS。这被认为是不好的做法,而且已经过时了。
  • l-打回来。我的主要回调 (window.addEventListener('load', function l()...被称为l。在这个函数中,我查询 DOM 三次(排序),并将这些 DOM 节点的引用分配给一个变量:morelessdiv接下来,我声明一个数组,以保存所有节点 I'将创建。一种堆栈,所以我永远不需要查询 dom 来获取对我创建的那些节点的引用。
  • 我还声明了一个函数 ( rmHandle),它将处理less链接上的点击。因为我在 的范围内声明了这个函数l,所以该函数可以访问我之前声明的所有变量 ( less, more, added)。再说一遍:我永远不需要查询 DOM ......
  • 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,因为这两个名称都可以本地解析,除了:

控制台.log(funcVar());

这将导致父函数的范围扫描,它声明funcVar变量,并将前面讨论的函数分配给它。该函数的行为仍然没有什么不同,因为该函数是在其自己的范围/上下文中调用的。
调用上下文也很棘手,所以我将暂时忽略这一点。

回到您的代码:其他语句实际上也是您之前编写的内容的重复:var para1并且var para2是多余的,如果您只是让它们在外部范围内可访问。

嗯,继续阅读,继续学习,你很快就会明白的......

于 2013-10-27T14:55:09.963 回答