V2EX = way to explore
V2EX 是一个关于分享和探索的地方
Sign Up Now
For Existing Member  Sign In
推荐关注
Meteor
JSLint - a JavaScript code quality tool
jsFiddle
D3.js
WebStorm
推荐书目
JavaScript 权威指南第 5 版
Closure: The Definitive Guide
islujw

写 JS 为去除特定 class 下的第一个 p 元素,浏览器没报错,但无效果

  •  
  •   islujw · Aug 9, 2017 · 4366 views
    This topic created in 3186 days ago, the information mentioned may be changed or developed.

    HTML 是这样的:

    <div class="accordion">
    	<div class="spoiler">
    		<div class="content">
            		<p></p>
                    	<p>正文</p>
    		</div>
    	</div>
    </div>
    

    因为正文外的 div 元素是插件生成的,总是会出现第一个多余的 p 元素,希望在后面加个 js 来去除。

    上面的 HTML 段落从 .spoiler 开始的部分共 6 个排比,都在 .accordion 内。我在「正文」的 p 元素标签内加了 id="cleanX",X 是从 1 ~ 6 的数字,按顺序分布在 6 个排比的结构里面。

    接着按如下写的 js,浏览器无报错,但没有效果:

    <script>
    	for (var i=1;i<7;i++) {
    		function cleanTag(i) {
        			var x = document.getElementById("clean"+i);
            		var y = x[i];
            		y.parentNode.removeChild(1);
    		}
    	}
    </script>
    

    问题在哪儿?要怎么解决这个问题呢?

    29 replies    2017-08-28 11:53:30 +08:00
    ferrum
        1
    ferrum  
       Aug 9, 2017
    你的函数执行了吗?

    另外 getElementById 返回单个 Node 节点,不是数组。没有具体的 HTML,其实也不好看出真正的问题……
    piku
        2
    piku  
       Aug 9, 2017 via Android
    你的 for 里定义了一个 function,但是这个 function 在什么时候执行呢?
    leeg810312
        3
    leeg810312  
       Aug 9, 2017 via Android
    function 不是闭包,根本没有执行
    orcusfox
        4
    orcusfox  
       Aug 9, 2017
    (function(i){}) (i)
    Sanko
        5
    Sanko  
       Aug 9, 2017 via Android
    没执行吧
    qiayue
        6
    qiayue  
    PRO
       Aug 9, 2017
    一个函数定义了其次
    blackywkl
        7
    blackywkl  
       Aug 9, 2017
    getElementById 返回的是 Dom 对象吧,为什么 x[i] ?
    chinvo
        8
    chinvo  
       Aug 9, 2017
    函数没执行
    islujw
        9
    islujw  
    OP
       Aug 10, 2017
    @blackywkl 赋给 y,document.getElementById("clean1") 用后面的方法。
    Lax
        10
    Lax  
       Aug 10, 2017
    一个 function 声明了 6 遍 ;->
    msg7086
        11
    msg7086  
       Aug 10, 2017
    你定义了一个函数六次,并且一次都不去执行……?
    autoxbc
        12
    autoxbc  
       Aug 10, 2017   ❤️ 2
    我觉得一句话提示可能不够说明问题

    1. 不应该在循环内部定义函数,效率很差,要这么写
    var cleanTag = function(i)
    {
    // doSomething
    };
    for(var i=1 ; i<7 ; i++ )
    {
    cleanTag(i);
    }

    2. 定义的函数并没有实际执行,没有传递参数

    3. 如果希望函数获取外部的变量值(i),或者传递参数(实参),或者不定义形参,让函数内部代码在作用域链里查找

    传递实参
    (function(i){
    // doSomething
    })(i);

    从作用域链中查找
    var i;
    (function(){
    // doSomething with i
    })();

    4. 变量 x 存储的是 getElementById 的返回值,这是一个元素节点,就是你需要删除的节点,后面再赋值给 y 没有意义

    5. removeChild 的参数是一个节点,不是数字或者索引值
    删除 x 这么写
    x.parentNode.removeChild(x);

    需要达到题目中的目的,一般不用题目的做法,而是这样
    [].slice.call( document.querySelectorAll('.content p') ).forEach(function(e){
    if( e.textContent.trim() == '' )
    e.parentNode.removeChild(e);
    });

    如果确实已经完成了添加 'clean' 标记,也可以这么写
    [].slice.call( document.querySelectorAll('.content p[id^="clean"]') ).forEach(function(e){
    e.parentNode.removeChild(e);
    });

    最后,楼主可能对自己的代码更亲切,按你的风格可以这样改
    for(var i=1 ; i<7 ; i++ )
    {
    (function(i){
    var x = document.getElementById("clean"+i);
    if(x)
    x.parentNode.removeChild(x);
    })(i);
    }

    P.S. 虽然 js 给人一种上手就能写的感觉,不过如果已经写了几千行代码,最好找本书系统看一下,完全自己摸索会很快达到瓶颈。
    b0x
        13
    b0x  
       Aug 10, 2017
    楼主已经从入门到放弃了
    mingl0280
        14
    mingl0280  
       Aug 10, 2017   ❤️ 1
    强行在 for 里定义一个函数六次却不执行 233333 当然没报错
    removeChild 用法也是错的。
    而且完全看不出来这个函数干啥的。
    正确做法:
    <script>
    for (var i=1;i<7;i++) {
    function cleanTag(i) {
    var x = document.getElementById("clean"+i);
    x.parentNode.removeChild(x);
    }(i);
    }
    </script>

    或者
    <script>
    for (var i=1;i<7;i++) {
    var x = document.getElementById("clean"+i);
    x.parentNode.removeChild(x);
    }
    </script>
    fox0001
        15
    fox0001  
       Aug 10, 2017 via Android
    都说得很清楚了,我就不 BB 了
    ZhLTE
        16
    ZhLTE  
       Aug 10, 2017
    楼主加油-。- 该好好学习了
    Anshi
        17
    Anshi  
       Aug 10, 2017
    学会 debug 断点调试。
    ahonn
        18
    ahonn  
       Aug 10, 2017
    12 楼已经讲得很清楚了。建议你还是先去看书吧..
    SourceMan
        19
    SourceMan  
       Aug 10, 2017
    你定义了 6 次 cleanTag function 缺没有执行它
    uvw
        20
    uvw  
       Aug 10, 2017
    这应该是个找错及代码优化的问题
    stillsilly
        21
    stillsilly  
       Aug 10, 2017
    ……
    autoxbc
        22
    autoxbc  
       Aug 10, 2017   ❤️ 1
    很多人说楼主定义了 6 次 cleanTag 函数,我的回答也说这样有性能问题
    刚测试了一下,这个说法需要修正

    循环或者任何语句中的函数声明,并不像函数表达式一样被实际执行,即函数声明不参与流程控制。
    函数表达式作为语句,参与流程控制,有性能开销;函数声明完全没有,哪怕其在一个循环中,使其形式上类似重复多次。或者在一个根本不会执行的流程分支中。

    看这个代码

    console.log( fun.toString() )
    if(0)
    {
    function fun(){return 1}
    }

    // function fun(){return 1}

    函数声明的实际流程是,在代码预解析时(词法分析,语法分析,AST 生成),由引擎将函数声明抽出,放入对应的作用域;在程序执行时,声明语句会被完全略过。

    进一步猜测,只要作用域关系正确,函数声明可以写在代码的任何位置,而不产生副作用。
    daisyxdx
        23
    daisyxdx  
       Aug 10, 2017
    好瞎的代码。。。
    winglight2016
        24
    winglight2016  
       Aug 10, 2017
    你的标签只有定义 class,寻找的时候又是 byId,这能找到正确的 tag 吗?
    islujw
        25
    islujw  
    OP
       Aug 10, 2017
    第一次接触 js,谢谢大家的提醒。确实是一个比较低级的错误。
    islujw
        26
    islujw  
    OP
       Aug 10, 2017
    @winglight2016 我已经写了:在「正文」的 p 元素标签内加了 id="cleanX"。
    islujw
        27
    islujw  
    OP
       Aug 10, 2017
    @autoxbc 谢谢,非常详细。函数位置的问题是个疏忽,放在循环外面,逻辑上更好。主要是内部的方法,感谢指点。
    mingyun
        28
    mingyun  
       Aug 12, 2017
    12 楼厉害了
    flowfire
        29
    flowfire  
       Aug 28, 2017
    removeChild 使用方法
    dom.parentNode.removeChild(dom)
    About   ·   Help   ·   Advertise   ·   Blog   ·   API   ·   FAQ   ·   Solana   ·   2418 Online   Highest 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 80ms · UTC 10:34 · PVG 18:34 · LAX 03:34 · JFK 06:34
    ♥ Do have faith in what you're doing.