在歌剧中滚动的问题

时间:2010-10-26 08:23:17

标签: css scroll opera

更新:我留下了以下javascript代码,以显示问题是如何随着时间的推移而发展的,但事实证明这是不相关的,因为javascript不是问题。请查看下面的html / css代码。

对于包含大菜单的概述页面,我实现了以下功能(most of which I stole from here):

function isScrolledIntoView(elem)
{
    var docViewTop = $(window).scrollTop();
    var docViewBottom = docViewTop + $(window).height();

    var elemTop = $(elem).offset().top;
    var elemBottom = elemTop + $(elem).height();

    alert(elemBottom);

    return ((elemBottom >= docViewTop) && (elemTop <= docViewBottom));
}

$(document).ready(function(){
 var overview = $('#overview');
 var active = $('#active-item');
 if (!isScrolledIntoView(active))
 {
  $('#overview li.active-parent').each(function(index, value){
   if (!isScrolledIntoView(active)) overview.scrollTo(value);
  });
 }
 if (!isScrolledIntoView(active)) overview.scrollTo(active);
});

这个想法是每次加载页面后,包含菜单的页面都会滚动到当前#active-item可见的位置。优选地,通过滚动到其第一个父项(菜单项在树中),否则滚动到项目本身。

现在这在Firefox和Chrome中运行良好(并没有苹果人向我抱怨过),但Opera做了一件非常奇怪的事情:它向下滚动到正确的元素,然后在滚动所有内容之前暂停再次上升

有人有任何想法

  1. 发生了什么事,
  2. 我该如何阻止它?
  3. 谢谢,


    更新:我正在使用Linux(Fedora)上的版本10.63进行测试


    更新:似乎我完全在错误的方向搜索。该问题似乎是一个问题,可以使用以下代码进行复制:

    <html>
    
    <head>
    
    <title>Opera scroll test</title>
    
      <style>
        .main:after
        {
          content: 'abc';
        }
    
        :focus
        {
          padding: 0px;
        }
    
        #overview
        {
          display: block;
          float: left;
          width: 219px;
          height: 500px;
          overflow: auto;
    
        }
      </style>
    
    </head>
    
    <body>
    
      <div id="main" class="main">
    
        <div id="overview">
          <ul>
            <?
            for($i = 1; $i < 100; $i++)
              echo '<li>'.$i.'</li>';
            ?>
    
          </ul>
        </div>
        <div>
    
          <p>123</p>
    
        </div>
    
      </div>
    
    </body>
    </html>
    

    现在,如果向下滚动导航窗格,并将鼠标向右移动(在内容窗格上),则会重置导航窗格的滚动。

    抱歉通过javascript搜索浪费每个人的时间:(

    如果有任何css专家知道如何修复它,或者谁可以简单地解释发生了什么,我将非常感激。


    更新:在Opera 10.63上的windows中测试了上面的代码。发生同样的奇怪行为。


    更新:已将此报告给Opera作为错误。不知道会发生什么......

4 个答案:

答案 0 :(得分:2)

我知道发生了什么,但是我尝试了你的代码,到目前为止我似乎无法复制问题。 Chrome和Opera的行为相同。

这是我试过的HTML:

<div id="overview" style="height: 300px;overflow-y: scroll;">
 <ul>   
  <li class="item" style="height: 400px;">item 1</li>
  <li class="item" style="height: 400px;">item 2 </li>
  <li class="active-parent" style="height: 400px;">active-parent<br/><br/>
    <ul>
      <li id="active-item" style="height: 300px;">active-item</li>
    </ul>
  </li>
 </ul>
</div>

至于为什么它在Opera中不起作用:你使用的是哪个版本的Opera?我尝试了10.63(最新版本)以及它的罚款。

由于我无法重现这个问题,我将对它进行盲目的拍摄:

尝试引入一点延迟,以便在队列中的所有其他内容之后执行此代码:

$(document).ready(function() {
  window.setTimeout(function() {
    // Your code goes here
  }, 500);
});

稍后补充:

回应你的陈述:“我真的很想知道这里发生了什么。为什么要延迟?在较慢的计算机上延迟需要更长时间吗?”:

如果设置延迟修复了您的问题,那么原因很明显,还有一些其他代码干扰了之后执行的“滚动到顶部”功能。通过设置500毫秒的延迟,您确保您的代码在文档加载后执行的每个其他Javascript 之后运行,这可能是您在文档中明确添加到jQuery函数队列的内容加载(使用$(document).ready(function(){),或者以“窗口小部件”的形式由Opera隐式添加(您是否安装了任何翻译工具,Google工具栏等?)。

至于慢速计算机的延迟是否需要更长时间,我个人不这么认为,关键是延迟会强制您的代码在document.onload事件触发的每个其他脚本之后执行。由于我怀疑在文档加载后在直接连续中执行的任何内容都不需要很长的延迟,即使50ms也可能会这样做,关键是延迟会强制你的代码走到队列的后面。

希望这有助于使事情变得更加清晰。

答案 1 :(得分:2)

不确定原因,但问题似乎与.main:after content CSS设置直接相关。你能用jQuery吗?如果是这样,如果您注释掉或删除 .main:after CSS设置并将其替换为<head>标记中的以下脚本,则会获得相同的视觉效果,而不会产生奇怪的滚动问题:

<script type="text/javascript">
  $(document).ready(function(){
    $(".main").append("abc");
  });
</script>

答案 2 :(得分:1)

正如Steven de Salas所说,增加延迟有助于 - &gt; $(window).scrollTop()如果没有延迟则返回0 !!

我玩了一下,想出了这个例子:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>Scrolling Test</title>

<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.4.3/jquery.min.js" type="text/javascript"></script>
<style type="text/css">
.parent { margin-bottom:100px; border:1px solid red; }
</style>

<script type="text/javascript">

(function ($){
    $.fn.extend({
        viewport : function(){
            if (this.length > 0) {

                var element = $(this.get(0)),
                pad = $.fn.viewport.PADDING,
                vp = {
                    height : element.height() + 2 * pad,
                    top : element.offset().top - pad,
                    docHeight : $(window).height(),
                    docTop : $(window).scrollTop(),
                    completelyInViewport : false
                };
                vp.bottom = vp.top + vp.height + pad;
                vp.docBottom = vp.docTop + vp.docHeight;
                vp.fitsInViewport = vp.height <= vp.docHeight;

                if (vp.top > vp.docTop && vp.bottom < vp.docBottom) {
                    vp.completelyInViewport = true;
                }

                return vp;
            }

            return null;
        }
    });

    $.fn.extend($.fn.viewport, {
        PADDING: 10, // ADJUST TO YOUR NEEDS
        LARGE_PARENT_BEHAVIOR: "bottom" // if parent list is bigger than viewport and 
                                        // the active item is not in the first page of 
                                        // the parents list, where should it be shown
                                        // possible: "bottom", "middle" or "top"
    });

    $.extend({
        ensureViewport: function(element, parent) {
            var e_vp = element.viewport(),
            p_vp = parent.viewport();

            if (null == e_vp || null == p_vp) {
                return;
            }

            if (!p_vp.completelyInViewport) {
                if (p_vp.fitsInViewport || e_vp.bottom - p_vp.top <= e_vp.docHeight) {
                    doScroll(p_vp.top);
                } else {
                    switch($.fn.viewport.LARGE_PARENT_BEHAVIOR) {
                        case "top":
                            doScroll(e_vp.top);
                            break;
                        case "middle":
                            doScroll(e_vp.top - (e_vp.docHeight - e_vp.height)/2);
                            break;
                        case "bottom":
                        default:
                            doScroll(e_vp.bottom - e_vp.docHeight);
                            break;
                    }
                }
            }

            function doScroll(y){
                window.scrollTo(0, y);
                // you could implement instead some sort of smooth scroling mechanism here
                // e.g. http://github.com/kswedberg/jquery-smooth-scroll
            }
        }
    });

    $(function(){
        window.setTimeout(function(){
            var item = $("li.active-item");
            if (item.size() > 0) {
                $.ensureViewport(item, item.closest("li.parent"));
            }
        }, 0);
    });
})(jQuery);

</script> 

</head>
<body>

<div id="overview">
 <ul>
  <li class="parent">
   parent 1
   <ul class="item"><li>item 1</li><li>item 2</li></ul>
  </li>
  <li class="parent">
   parent 2
   <ul class="item"><li>item 1</li><li>item 2</li></ul>
  </li>
  <li class="parent">
   parent 3
   <ul class="item"><li>item 1</li><li>item 2</li></ul>
  </li>
  <li class="parent">
   parent 4
   <ul class="item"><li>item 1</li><li class="active-item">item 2</li></ul>
  </li>
  <li class="parent">
   parent 5
   <ul class="item"><li>item 1</li><li>item 2</li></ul>
  </li>
  <li class="parent">
   parent 6
   <ul class="item"><li>item 1</li><li>item 2</li></ul>
  </li>
  <li class="parent">
   parent 7
   <ul class="item"><li>item 1</li><li>item 2</li></ul>
  </li>
 </ul>
</div>

</body>
</html>

在Opera 10.63上测试过,它也在那里工作。

干杯

答案 3 :(得分:1)

这只是一个理论,但可能会让你开始。

当您按回浏览器时,它通常会将您带到您上次查看的页面中。

歌剧是否有可能试图将你带到那一点,这会干扰你的代码?

我想知道你是否清除你的历史/缓存,杀死歌剧进程并开始一个新进程。这有什么不同。