为什么我的按钮需要两次单击才能使事件处理程序第一次起作用,而之后才需要单击一次?

问题描述 投票:6回答:6

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

<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

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

javascript events dom
6个回答
10
投票

'xx'div上的初始样式可能会引起一些麻烦...

说明

假设您已配置了样式表规则,以使div最初处于隐藏状态。类似于:

div { display: none }

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

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

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

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

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()getComputedStyle()


2
投票

要保存所有额外的Javascript代码以获取样式等,为此的一个简单解决方法是将hide CSS添加到元素本身。

currentStyle

edit

我决定更好地解释我的答案。我假设您没有隐藏要默认切换的currentStyle,所以它是可见的,但是,当调用<div class="yourclass" style="display:none;">content</div> 时,结果既不会是div也不会是e.style.display,因为样式没有尚未设置。

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


1
投票

更容易实现一些方法

none

0
投票

类似的方法可能对您有用。但是将其放在文档的开头。窗口onload功能非常重要,因为需要先加载DOM,然后才能弄乱输入字段

block

和此

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

}

0
投票

您正在寻找的简单答案是将<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";
               }
            }
        }

它将返回true!


0
投票

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

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

display:none;

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

© www.soinside.com 2019 - 2024. All rights reserved.