0

Jqueryで水平アコーディオンを構築しようとしています。Firefoxでは「問題なく」動作しているようです。ただし、Webkit(Safari 3 + 4、およびChrome)では、非表示機能の後にサブレベルのULが点滅します。どんな助けでも大歓迎です。動作するデモを見るには:http://ableobject.com/horaccordion1.html

これが私が取り組んでいることです:

<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
    <script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.3/jquery.min.js"></script>

    <title>untitled</title>
    <style type="text/css">
    #container {
        display: table; 
        margin: 0 auto; 
        text-align: center; /* for IE */
    }
            ul{
                    list-style: none;
                    background-color: yellow;
                    margin: 0;
                    padding: 0;
                    float: left;
                    height: 20px; /* For testing */     
            }
            ul li {
                   background-color: aqua;
                    float: left;
            }
            ul li ul {
                   background-color: blue;
                    display: none;
            }
            ul li ul li {
                   background-color: green;
            }
            a, a:link, a:hover, a:visited, a:active {
                    color: black;
                    text-decoration: none;
                    float: left;
            }
    </style>

   <script type="text/javascript">
/* Care of Hunter Daley */
    var $current = null;
        $(document).ready(function(){
         $("ul li ul").hide();  // hide submenus by default on load

           $("ul li a").click(function(){
              var $sub = $(this).next(); 
              if ($sub.css("display") == "none")
              {
                 if ($current != null)
                    $current.animate({ width: 'hide' }); // if you want to only show one sub at a time
                 $sub.animate({ width: 'show' }); 
                 $current = $sub;
              }
              else
              {
                 $sub.animate({ width: 'hide' });
                 $current = null;
              }
           });
        });
    </script>
</head>

<body>
    <div id="container">
    <ul>
            <li>
                    <a href="#">Top-level 1</a>
            </li>
            <li>
                    <a href="#">Top-level 2</a>

                    <ul>
                            <li><a href="#">Bottom Level A1</a></li>
                            <li><a href="#">Bottom Level A2</a></li>
                            <li><a href="#">Bottom Level A3</a></li>
                            <li><a href="#">Bottom Level A4</a></li>
                    </ul>
            </li>

            <li>
                    <a href="#">Top-level 3</a>
                    <ul>
                            <li><a href="#">Bottom Level B1</a></li>
                            <li><a href="#">Bottom Level B2</a></li>
                    </ul>
            </li>

            <li>
                    <a href="#">Top-level 4</a>
            </li>
    </ul>
</div>
</body>
4

2 に答える 2

1

前の回答がまだ役立つ場合に備えて、これを別の回答として投稿しています。

次の点に注意してください:

  • 私はこれをテストしていません。
  • これは「ネストされた」バージョンに戻るので、クラスと変数の名前を少し変更しました。
  • 表示するメニューがない場合、空のメニューは不要になりました。
  • 各メニューの「コンテナ」の幅は、メニューと同じ量だけ縮小されています。これは、webkit の一時的なフラッシュ (元の戦略であった) を排除するものです。
  • メニューのアニメーションのタイミングが、メニューのコンテナのアニメーションのタイミングとわずかに異なることに気付くでしょう。基本的には、拡大するときは容器が少し手前に、縮小するときはメニューが少し手前になるようにします。タイミングが同じになるように設定すると、メニューの点滅が発生する可能性があります。
  • コメントで説明されているように、最初に、「fullWidth」という以前は存在しなかった属性を設定することにより、各メニューが完全に展開されたときにその幅を「記憶」します。その後、必要に応じてこの属性の値を取得します。グローバル変数や jQuery の data() 関数を使用して情報を保存することも簡単にできます。要点は、各メニューが展開されたときの幅を認識している場合、物事が単純化されるということです。

それで、ここにあります。それが役に立てば幸い!

CSS

#container {
    margin: 0 auto 0 auto; 
    text-align: center;
    display: table;
}

.menuContainer {
       margin: 0;
       padding: 0;
       float: left;
       height: 32px; /* For testing */
       font-family: helvetica;
       font-size: 18px;
       clip: auto; overflow: hidden;
}
.menu {
       height: 32px; /* For testing */
       clip: auto; overflow: hidden;
       float: left;
}
a, a:link, a:hover, a:visited, a:active {
       color: black;
       text-decoration: none;
       padding: 12px;
       font-weight: 700;
       float: left;
       color: #222;
}

.menu a, .menu a:link, .menu a:hover, .menu a:visited, .menu a:active {
   color: black;
   text-decoration: none;
   padding: 12px;
   font-weight: normal;
   float: left;
}

JavaScript

var $currentMenuContainer = $('#someFictionalElement');
var $previousMenuContainer = null;

$(document).ready(function() {

// Iterate through each .menu element, setting the full width of each menu to a 'custom'
//        attribute called 'fullWidth'. Since the full width should never change, this
//        makes it easy to recall it quickly. You could use global variables instead.
// After setting 'fullWidth', it then collapses each menu and title.
$(".menu").each(function() {
    var $theMenu = $(this);
    var $theMenuContainer = $theMenu.parent();
    $theMenu.attr({fullWidth: ($theMenu.width() + 3)});   // Add a few pixels for firefox
    var menuContainerWidth = $theMenuContainer.width() - $theMenu.attr('fullWidth') + 6;  // Add DOUBLE the pixels here
    $theMenu.css({width: 0});
    $theMenuContainer.css({width: menuContainerWidth});
});

    $(".menuContainer a").click(
        function() {
// Set the current and previous elements properly
            $previousMenuContainer = $currentMenuContainer;
            $currentMenuContainer = $(this).parent();
            var $previousMenu = $previousMenuContainer.find('.menu');
            var $currentMenu = $currentMenuContainer.find('.menu');

// Collapse the previous menu
            $previousMenu.animate({ width: 0 }, {duration: 480, queue: false} );

// Subtract the width of the previous menuContainer's menu from the menuContainer (only if its menu is displayed)
            if($previousMenu.width() > 0) $previousMenuContainer.animate({width: ('-=' + $previousMenu.attr('fullWidth'))}, 500);

// Expand the current menu and its menuContainer if it's not showing
            if($currentMenu.width() == 0) {
                // Increase the menuContainer width by the full width of its menu
                $currentMenuContainer.animate({width: ('+=' + $currentMenu.attr('fullWidth'))}, 480);
                // Increase the menuContainer to its full width
                $currentMenu.animate({ width: $currentMenu.attr('fullWidth') }, 500);
            }
    });

    $(".menuContainer a").hover(
        function(){$(this).animate ({ opacity: 0.7 }, 200);},
        function(){$(this).animate ({ opacity: 1 }, 600);}
    );
});

HTML

<div id="container">
    <div class='menuContainer'>
        <a href="#">Top-level 1</a>
    </div>
    <div class='menuContainer'>
        <a href="#">Top-level 2</a>
        <div class='menu'>                         
            <a href="#">Bottom Level A1</a>
            <a href="#">Bottom Level A2</a>
            <a href="#">Bottom Level A3</a>
            <a href="#">Bottom Level A4</a>
        </div>
    </div>
    <div class='menuContainer'>
        <a href="#">Top-level 3</a>
        <div class='menu'>
            <a href="#">Bottom Level B1</a>
            <a href="#">Bottom Level B2</a>
        </div>
    </div>
    <div class='menuContainer'>
        <a href="#">Top-level 4</a>
    </div>
</div>

編集:次の DTD をページの上部に追加します。

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
"http://www.w3.org/TR/html4/strict.dtd">
于 2009-07-05T15:46:14.417 に答える
1

これは、少し前に webkit で発生した問題に関連しているようです。要素の幅を縮小するアニメーションの後に、要素の親が元のサイズに戻ることがある webkit のバグがあります。アニメーションの後、要素の親は、そのコンテンツに対応するために元のサイズに戻ります。

編集: jQueryUI に関するコメントを削除しました。なぜあなたがそれを使っていると思ったのか分かりません。

バグについてはこちらで説明されており、回避策が詳しく説明されています。

jQueryにもバグレポートを提出しました。

$sub基本的に、要素の親の幅を縮小するのと同じ量だけ同時に縮小する必要があります$sub。したがって、の幅が 100px の場合、親を 100px 縮小するための$subセパレートがあります。animate()

あなたの例でこれをテストしたことはありませんが、おそらくそれが鍵だと思います。

編集 2: div を使用した新しいバージョン

CSS:

.title {
       list-style: none;
       margin: 0;
       padding: 0;
       float: left;
       height: 32px; /* For testing */
       font-family: helvetica;
       font-size: 18px;
       clip: auto; overflow: hidden;
}
.menu {
       height: 32px; /* For testing */
       clip: auto; overflow: hidden;
       float: left;
}
a, a:link, a:hover, a:visited, a:active {
       color: black;
       text-decoration: none;
       padding: 12px;
       font-weight: 700;
       float: left;
       color: #222;
}

 .menu a, .menu a:link, .menu a:hover, .menu a:visited, .menu a:active {
   color: black;
   text-decoration: none;
   padding: 12px;
   font-weight: normal;
   float: left;

}

JavaScript:

    // Prevents us from having to check for null.
    var $current = $('#someFictionalElement');
    var $previous = null;
    $(document).ready(function(){
    $(".menu").css({width: 0});  // hide submenus by default on load

    $(".title").click(
        function() {
            $previous = $current;
            $current = $(this);
            var $currentMenu = $current.next();

            $previous.next().animate({ width: 0 }, {duration: 1000, queue: false} );

    // Make sure that if there's no menu text (like Top Level 1 and 4) that it does not animate.
    // This is because of the pixels added for Firefox (see comment below)
            if( $currentMenu.width() == 0 && $currentMenu.text() != ''  ) {

    // Expand the menu but keep it hidden so we can get its width
                $currentMenu.css({visibility: 'hidden', width: ''});

    // Store the width, and add a few pixels for Firefox
                var currentWidth = $currentMenu.width() + 3;

    // Make menu visible and set with to 0 in preparation for the animation
                $currentMenu.css({visibility: 'visible', width: 0})
                            .animate({ width: currentWidth }, 1000);
            }
    });

    $(".title a").hover(
        function(){$(this).animate ({ opacity: 0.7 }, 200);},
        function(){$(this).animate ({ opacity: 1 }, 600);}
    );
});

HTML:

<body>
    <div id="container">
        <div class='title' id='level1'>
            <a href="#">Top-level 1</a>
        </div>
        <div class='menu'></div>
        <div class='title' id='level2'>
            <a href="#">Top-level 2</a>
        </div>
        <div class='menu'>                         
            <a href="#">Bottom Level A1</a>
            <a href="#">Bottom Level A2</a>
            <a href="#">Bottom Level A3</a>
            <a href="#">Bottom Level A4</a>
        </div>
        <div class='title' id='level3'>
            <a href="#">Top-level 3</a>
        </div>
        <div class='menu'>
            <a href="#">Bottom Level B1</a>
            <a href="#">Bottom Level B2</a>
        </div>
        <div class='title' id='level4'>
            <a href="#">Top-level 4</a>
        </div>      
        <div class='menu'></div>
    </div>
</body>
于 2009-06-28T15:56:44.230 に答える