为什么我的按钮需要被点击两次才能让事件处理程序第一次工作,但之后只需要一次?

时间:2010-08-10 21:05:50

标签: javascript events dom

我希望访问者能够展开/折叠某些部分,并且正在使用:

<input onclick="return toggleDiv('xx')" 
       type="button" 
       class="button" 
       value="click here to expand/collapse"/>

在我有功能:

function toggleDiv(a){
  var e=document.getElementById(a);
  if(!e)return true;
  if(e.style.display=="none"){
    e.style.display="block"
  } else {
    e.style.display="none"
  }
  return true;
}

第一次单击按钮时,它不起作用,后续点击(在任何按钮上)都可以正常工作。

这里有相关的对话:  Button needs to be clicked twice to trigger function

但我不明白答案(太技术;-), 有人可以帮忙解释一下吗?

6 个答案:

答案 0 :(得分:10)

“xx”div上的初始样式可能会造成一些麻烦......

解释

假设您已配置样式表规则,以使div最初隐藏。类似的东西:

div { display: none }

(...当然,选择器(div)可能会稍微宽一些)

这似乎可以正常工作,因为页面将加载所有隐藏的div元素(“折叠”)。但是,元素本身上的style.display属性没有实际值 - 它们只是继承样式表中的值。所以在你的代码中,你用来检查元素是否被隐藏的测试:

if(e.style.display=="none"){

...将失败,错误地将目标识别为可见,并导致style.display属性设置为“none”(没有可见效果,因为该元素已被样式表隐藏)。然后单击按钮的 next 时间,您上次设置的值将导致文本成功,并且您的例程会将style.display设置为“阻止”。

easy 纠正此方法的方法是简单地反转测试并检查“阻止”:

  if(e.style.display=="block"){
    e.style.display="none"
  } else {
    e.style.display="block"
  }

...但是,如果您将某些元素配置为最初可见,则会崩溃:您将反向遇到相同的问题,第一个按钮单击无法产生任何可见效果。要获得更强大的行为,您需要测试在元素上实际处于活动状态的样式:

function getStyle(el, name)
{
  // the way of the DOM
  if ( document.defaultView && document.defaultView.getComputedStyle )
  {
    var style = document.defaultView.getComputedStyle(el, null);
    if ( style )
      return style[name];
  }
  // IE-specific
  else if ( el.currentStyle )
    return el.currentStyle[name];

  return null;
}

function toggleDiv(a){
  var e=document.getElementById(a);
  if(!e)return true;
  if(getStyle(e, "display") == "none"){
    e.style.display="block"
  } else {
    e.style.display="none"
  }
  return true;
}

这里我们使用辅助函数getStyle()以跨平台方式检索活动值。另请参阅:getComputedStyle()currentStyle

答案 1 :(得分:1)

要保存所有额外的Javascript代码以获得样式等,对此的一个简单修复就是将隐藏CSS添加到元素本身。

<div class="yourclass" style="display:none;">content</div>

修改

我决定更好地解释我的答案。我假设你没有隐藏你想要切换的div,所以它是可见的,但是当调用e.style.display时,结果将不是none也不会{ {1}}因为尚未设置样式。

相反,你正在检索一个空字符串,这意味着你第一次点击它时,你的else语句就会被触发;第一次点击时block显示被设置为无,这样下一次点击会将值检索为div,因此当然会将其更改为none

答案 2 :(得分:1)

更容易实现一些如何

var a=1;
function toggleDiv(xx){
  var e=document.getElementById(xx);

  if(a==1){
    e.style.display="block";a=0;
  } else {
    e.style.display="none";
  a=1;
  }

}

答案 3 :(得分:0)

这样的事可能适合你。但把它放在文件的头部。窗口onload函数很重要,因为在你可以搞乱输入字段之前需要加载DOM

<input id="divOpener" rel="xx" type="button" class="button" value="click here to expand/collapse"/>

和这个

window.onload = function(){
            //  get input field from html
            var myInput = document.getElementById('divOpener');
            // add onclick handler
            myInput.onclick = function(){
               // if you really need to say which div in the document body, you can
               // add it to the rel or ref etc. attributes then get the value with
               // get attribute
               var myDiv = document.getElementById(this.getAttribute('rel'));
               if(!myDiv) return;
               if(myDiv.style.display=="none"){
                  myDiv.style.display="block";
               } else {
                 myDiv.style.display="none";
               }
            }
        }

答案 4 :(得分:0)

您要寻找的简单答案是将display:none;添加到嵌入式样式中。这样,当您查看

if (x.style.display == 'none')

它将返回true!

答案 5 :(得分:0)

Shog9的回答使我摆脱了一个晚上的沮丧。谢谢。

但是,有比他提出的解决方案简单得多的解决方案。秘诀就是简单地切换条件的顺序。即

if(e.style.display == "block"){
    e.style.display="none"
} else {
    e.style.display="block"
}

这里的见解仅仅是该条件可能由于两个不同的原因而失败:如果无法获得该值,则无论如何都会做对的事情。