【问题标题】:Why does my button need to be clicked twice for the event handler to work the first time, but thereafter just once?为什么我的按钮需要单击两次才能使事件处理程序第一次工作,但此后只需单击一次?
【发布时间】:2011-03-28 01:47:40
【问题描述】:

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

<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

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

【问题讨论】:

  • 'xx' div 的定义/样式是什么?
  • 我要做的第一件事是打开 FireBug(firefox javascript 开发工具),在 toggleDive 旁边设置一个断点,然后逐步检查,确保一切都如我所想。如果你不想处理这个问题,你可以在你的函数中设置 do alert(e.style.display) 。这可能会对事情有所启发。
  • 就在第一个 if 语句之后,添加以下行:alert("display is '" + e.style.display + "'");然后再次运行代码。这应该可以帮助您了解正在发生的事情。

标签: javascript events dom


【解决方案1】:

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

说明

假设您有一个样式表规则配置为使您的divs 最初隐藏。比如:

div { display: none }

(...当然选择器 (div) 的范围可能会小一些)

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

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

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

解决此问题的简单方法是简单地反转您的测试并检查“阻塞”:

  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

【讨论】:

  • 更多信息:页面验证,在Chrome、IE、Firefox中同样需要第一次双击
  • 回答:感谢您花时间如此清楚地解释 Jaime。我现在已经理解并让它工作了。您可以在这里看到您的手工作品:www.alanarnoldguitars.co.uk/guitar_repairs.htm 再次感谢
【解决方案2】:

这样的事情可能对你有用。但是把它放在文件的头部。窗口加载功能很重要,因为需要先加载 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";
               }
            }
        }

【讨论】:

  • 如果这不起作用,请说明您的要求,我们可以从那里开始......
【解决方案3】:

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

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

编辑

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

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

【讨论】:

    【解决方案4】:

    更容易实现一些方法

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

    【讨论】:

      【解决方案5】:

      您正在寻找的简单答案是将display:none; 添加到内联样式中。这样,当你看

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

      它会返回真!

      【讨论】:

        【解决方案6】:

        Shog9 的回答让我摆脱了一晚的挫败感。谢谢。

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

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

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

        【讨论】:

          【解决方案7】:

          我知道这是一个旧线程,但为了有点有用(为了改变),你总是可以在函数中调用当前显示。或者你可以定义加载,但考虑到按钮可能没有被点击,我宁愿通过 addEventListener() 来做。

          document.getElementById("someID1").addEventListener("click", hideOpen);
          
          function hideOpen() {
            var x = document.getElementById("someID2");
            x.style.display = window.getComputedStyle(document.getElementById("someID2")).display;
            if (x.style.display === "none") {
              x.style.display = "block";
            } else {
              x.style.display = "none";
            }
          }
          

          实际上你加载了 JS,然后当一个元素被点击(someID1)时,该函数将定义变量 X,分配当前计算的 style.display,然后测试它是块还是无。

          【讨论】:

            猜你喜欢
            • 2019-05-30
            • 1970-01-01
            • 2014-08-08
            • 1970-01-01
            • 2017-08-03
            • 2011-07-29
            • 2013-06-07
            • 2013-05-10
            • 2017-05-18
            相关资源
            最近更新 更多