2 votes

Slider animé jQuery avec hauteur variable et contenu Ajax

J'ai une série de liens sur un div flottant (pour qu'ils soient toujours visibles). Lorsqu'un utilisateur clique sur l'un d'eux, j'aimerais que les actions suivantes se succèdent :

  1. La page défile jusqu'en haut (où se trouve le conteneur ajax).
  2. Le contenu actuel disparaît
  3. Le nouveau contenu se charge (ajax)
  4. Le nouveau contenu glisse dans

NB : Comme le contenu de chaque fichier ajax est différent, le conteneur ajax devra s'étendre/se contracter pour s'adapter.

Je voudrais faire cela sans jQuery UI, et garder le code aussi léger que possible.

J'ai passé la journée à chercher sur Internet et à essayer de faire cela avec des fonctions de rappel et de file d'attente, mais j'ai du mal à faire en sorte que cela fonctionne comme prévu. Si quelqu'un peut m'aider à comprendre comment structurer ces fonctions pour que cela fonctionne, je lui en serais incroyablement reconnaissant.

J'ai abstrait mon code pour vous montrer où j'en suis : http://pastebin.com/xbJKPmnw

Il fait actuellement glisser le haut de la page, et charge le contenu. Mais je n'ai pas encore réussi à faire fonctionner les transitions de manière fluide et séquentielle.

Merci d'avance.

3voto

Dmitry Pashkevich Points 4160

Si je comprends bien, vous avez tout réglé (body scroll, ajax fetch content) sauf la transition elle-même.

Voici mon prototype qui fait ce dont vous avez besoin :

  1. Fait glisser l'ancien contenu
  2. Fait glisser le nouveau contenu dans
  3. Redimensionne le conteneur de contenu dynamique pour l'adapter au nouveau contenu

Travail de jsFiddle : http://jsfiddle.net/dipish/vhd8e/

Le code est assez bricolé mais reprend les idées principales de l'approche suggérée. J'utilise l'attribut "rel" des liens pour faire référence au contenu statique de la maquette. Dans la vie réelle, vous feriez votre requête ajax, récupéreriez les données et lanceriez ensuite la transaction.

Exemple de code html :

<div id="primarynav">
              <ul id="navigation">
                  <li><a href="page1.html" class="selected" rel="content1">Page 1</a></li>
                  <li><a href="page2.html" rel="content2">Page 2</a></li>
                  <li><a href="page3.html" rel="content3">Page 3</a></li>
              </ul>
          </div>

<div id="ajax-content"></div>

<div class="preload">
    <div id="content1">I have a series of links on a floating div (so they're always visible). When a user clicks one, I would like the following to happen in sequence:

The page scrolls up to the top (where the ajax container is located)
The current content slides out
The new content loads (ajax)
The new content slides in
NB: As the content in each ajax file is different, the ajax container will need to expand/contract to fit.

I would like to do this without jQuery UI, and keep the code as lite as possible.

I've been googling and attempting to do this with callbacks and queue functions all day, but struggle to get it working as intended. If anyone can please help me understand how to structure these functions to get it working I'd be incredibly grateful.

I've abstracted my code to show you where I'm at: http://jsfiddle.net/Cz5kg/1/

It currently slides the top of the page, and loads the content. But i'm yet to get the transitions working smoothly and in sequence.

Many thanks in advance.</div>

    <div id="content2">I'm writing a simple javascript to calculate the time difference between server and user time. But something is going wrong.

If I catch the javascript and php date i have:

date("M d Y h:i:s A")
php date : Wed Jun 27 2012 04:10:41 AM  

new Date()
J S date : Wed Jun 27 2012 10:10:40 GMT+0200 (CEST)   
This is correct! I have two different time for local and server time.

Now if I take the seconds time... something goes wrong:

(php: date("U"))
sec PHP: 1340784640    

(js new Date().getTime()/1000 )
sec J S: 1340784640
I got the same time!

Can you help me to fix it ?

Thanks!
    </div>

    <div id="content3">I've been given a big project by a big client and I've been working on it for 2 months now. I'm getting closer and closer to a solution but it's just so insanely complex that I can't quite get there, and so I need ideas.

The project is quite simple: There is a 1mil+ database of lat/lng coordinates with lots of additional data for each record. A user will visit a page and enter some search terms which will filter out quite a lot of the records. All of the records that match the filter are displayed (often clustered) on a Google Maps.

The problem with this is that the client demands it's fast, lean, and low-bandwidth. Hence, I'm stuck. What I'm currently doing is: Present the first clusters, and when they hover over a cluster, begin loading in the data for that clusters children.

However, I've upped it to 30,000 of the millions of listings and it's starting to drag a little. I've made as many optimizations that I possibly can. When the filter is changed, I AJAX a query to the DB and return all the ID's of the matches, then update the map to reflect this.

So, optimization is not an option. I need an entirely new conceptual model for this. Any input at all would be highly appreciated, as this is an incredibly complex project of which I can't find anything in history even remotely close to it- I even looked at MMORPG's which have a lot of similar problems, and I have made a few, but the concept of having a million players in one room is still something MMORPG makers cringe at.

I'll be awarding 500 rep as soon as it becomes available for anything that solves this.

Thanks- Daniel.        
    </div>
</div>

Quelques CSS (pour la plupart inchangés) :

ul li { float: left;margin: 0 15px 0 0; }

#ajax-content { 
    width:500px; /* fixed width just for viewing convenience */
    clear:both; 
    border: solid 1px black; /* border just for debugging purposes */
    position: relative; /* to contain absolutely positioned children */
    height: 100px; /* initial height */
}

.preload { /* for test purposes */
    display: none;
}

.item-container {/* style your inner content*/}

Et enfin votre JavaScript modifié avec de nombreux commentaires :

$(document).ready(function() {

    var $navlinks = $('#navigation li a'),
        $ajaxcontent = $('#ajax-content'),
        animDur = 5000, // animation duration
        isTransitionRunning = false;

    $navlinks.click(function(e) {        
        e.preventDefault(); // prevent default action
        // block actions until current transition finishes
        if(isTransitionRunning) {
            return false;
        }                
        var contentWidth = $ajaxcontent.width(),
            newContent = $('#' + $(this).attr('rel')).html(), // mock content                
            $newItem = $(document.createElement('div')), // nested container for new content
            newItemHeight,
            newContentHeight,
            $oldItem = $ajaxcontent.children('.item-container');

        // set the flag indicating that the transition is running
        isTransitionRunning = true;

        $newItem.addClass('item-container');

        $('html, body').animate({scrollTop:0}, 'slow');              

        //$ajaxcontent.empty().append("<div id='loading'><img src='http://expression.ws/stackoverflow/load.gif' alt='Loading Content' /></div>");
        $navlinks.removeClass('selected');
        $(this).addClass('selected');

        /*$.ajax({ url: this.href, success: function(html) {
            $ajaxcontent.empty().append(html);
            }
        });*/

        // freeze current ajax container height
        $ajaxcontent.height($ajaxcontent.height());
        $ajaxcontent.css('overflow', 'hidden');

        // slide away old item (if any)
        if($oldItem.length) {
            $oldItem
                 // fix width so no wrapping occurs during transision
                .width(contentWidth) 
                // position absolutely
                .css('position', 'absolute')
                .animate({
                    left: -contentWidth // move new content at the right edge of container
                },
                animDur,
                function() {
                    // remove old content at the end
                    // you may want to cache it instead
                     $oldItem.remove();
                });
        }

        // append new content to container
        $newItem.html(newContent);
        $ajaxcontent.append($newItem);
        // fix new content width
        $newItem.width(contentWidth);
        // determine height of new content when it's appended to DOM
        newItemHeight = $newItem.height();

        // set up new content
        $newItem
            // move it to the right
            .css('position', 'absolute')
            .css('left', $ajaxcontent.width() + 'px')
            // sliding animation
            .animate({
                left: 0
            }, 
            animDur,
            function() {
                // restore css
                $newItem.css('position', 'static');
                $newItem.css('width', 'auto');
            });

        // change ajax container height
        $ajaxcontent.animate({
            height: newItemHeight
        },
        animDur,
        function() {
            // now let ajax container naturally wrap around its content
            $ajaxcontent.css('height', 'auto');
            $ajaxcontent.css('overflow', 'auto');

            // unset the transition running flag
            isTransitionRunning = false;
        });

        return false;
    });

    //$ajaxcontent.empty().append("<div id='loading'><img src='http://expression.ws/stackoverflow/load.gif' alt='Loading Content' /></div>");
    $.ajax({ url: 'page1.html', success: function(html) {
            $ajaxcontent.empty().append(html);
    }
    });
});

Ce qui se passe ici devrait être clair, mais n'hésitez pas à poser des questions. Je ne suis pas un ninja de jQuery donc certaines choses que je fais ici peuvent être légèrement inefficaces mais l'idée reste inchangée.

L'essentiel de la mise en œuvre est :

  • Avant ajouter du nouveau contenu à votre conteneur, fixer ses dimensions et le rendre overflow: hidden;
  • Après avoir inséré un nouveau contenu dans le DOM, vous souhaitez mesurer sa hauteur (après l'avoir définie sur la largeur du conteneur). Ce sera la largeur cible du conteneur
  • Après avoir effectué vos transitions, supprimez toutes les CSS qui forcent les positions/dimensions en rétablissant le flux naturel des éléments (pas toujours nécessaire mais généralement recommandé) ;

Limites du prototype :

  1. Suppose que le contenu est déjà récupéré via ajax et prêt à être inséré.
  2. Glisse dans une seule direction
  3. Je n'ai pas testé le fonctionnement de ce code si vos éléments ont des marges et des paddings, vous devez généralement faire quelques ajustements ici car les méthodes de jquery pour définir les dimensions et le positionnement des éléments ne gèrent pas toujours automatiquement ces éléments comme vous l'attendez.

J'espère que cela vous aidera !

UPD. J'ai ajouté une logique simple qui bloque l'exécution si une transition est en cours, vous pouvez voir les différences via l'historique des modifications ici sur StackOverflow. En général, ce n'est pas une bonne approche, mais elle est facile à mettre en œuvre. L'implémentation d'un vrai widget résistant à l'avalanche de clics demande plus d'efforts et une meilleure architecture de code, faites-moi savoir si vous voulez toujours suivre cette voie ou si vous allez utiliser un widget tiers pour cela.

Pour ce qui est du lien avec la récupération des données par AJAX, vous devez exécuter la transition lorsque le contenu est déjà récupéré. Voici le pseudo-code :

$navlinks.click(function(e) {        
    e.preventDefault(); // prevent default action
    // block actions until current transition finishes
    if(isTransitionRunning) {
        return false;
    }  

    // If content is static, you don't want to fetch it everytime,
    // consider implementing some caching mechanism
    $.ajax({ url: this.href, success: function(html) {
        // this function is basically all the code posted above 
        // except that it takes new html content as parameter
            switchContent(html);
        }
    });
});
});

1voto

Explosion Pills Points 89756

http://explosion-pills.com/11185244.php

Cette page fait ce que je pensez à que vous demandez (je n'ai pas fait de stylisme, je vous en laisse le soin).

Je pense que vous étiez assez proche, vous devez juste changer un peu la façon dont les éléments sont mis en file d'attente. Tu en fais aussi un peu plus que ce que tu dois faire à certains endroits ( .empty().append vs. .html() par exemple).

Faites-moi savoir si je suis à côté de la plaque.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X