如何让jquery以完全并行的方式执行动画? [英] How can I get jquery to execute animations in exact parallel?

查看:110
本文介绍了如何让jquery以完全并行的方式执行动画?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试在jquery中创建一个类似于 jquery的手风琴插件的手风琴小部件,我希望句柄出现在各自内容之下而不是上面的差异。我的手风琴的工作原理是降低打开内容部分的高度,同时增加点击内容部分的高度。我在此处发布了一个示例。我的问题是动画不是在完全相同的时间开始,并且由于在第二个动画开始之前的轻微延迟而存在明显的跳跃。

I'm trying to create an accordion widget in jquery similar to jquery's accordion plugin, with the difference that I want the handles to appear below their respective content instead of above. My accordion works by decreasing the height of the open content section while at the same time increasing the height of the clicked content section. I've posted an example here. My problem is that the animations aren't started at exactly the same time, and there is a noticeable "jump" due to the slight delay before the second animation is started.

Scriptaculous有一个名为 Effect.Parallel 的功能,可以让你创建一个数组动画效果并行执行它们。不幸的是,我似乎找不到与jquery类似的东西。

Scriptaculous has a function called Effect.Parallel that allows you to create an array of animation effects and execute them in parallel. Unfortunately, I can't seem to find something similar with jquery.

有没有办法可以在jquery中的不同div上运行精确的并行动画?

Is there a way I can run precise parallel animations on separate divs in jquery?

编辑:我'我对编写这个手风琴小部件的替代方法很感兴趣。因此,如果有人认为其他方法可行,我会对此持开放态度。

I'm as much interested in alternative methods of coding this accordion widget. So if there is any other method people think would work I'm open to that.

推荐答案

还有一个答案,希望是我的最后一个答案一个...

One more answer, hopefully my last one...

不幸的是,John Resig的syncAnimate方法对于我想要做的手风琴式动画来说并不是很好。虽然它在Firefox上运行得很好,但我无法在IE或Safari上顺利运行。

Unfortunately, John Resig's syncAnimate method is not quite up to snuff for the accordion-type animation I want to do. While it works great on Firefox, I couldn't get it working smoothly on IE or Safari.

说完了,我决定咬紧牙关写自己的动画执行简单并行动画的引擎。类代码使用jquery函数,但不是jquery插件。另外,我只是将它设置为大小/位置动画,这就是我所需要的。

With that said, I decided to bite the bullet and write my own animation engine that does simple parallel animations. The class-code uses jquery functions but is not a jquery plugin. Also, I've only set it up to do size/position animations, which is all I need.

ParallelAnimations = function(animations, opts){
    this.init(animations, opts);
};

$.extend(ParallelAnimations.prototype, {
    options: {
        duration: 250
    },
    rules: {},

    init: function(animations, opts){
        // Overwrite the default options
        $.extend(this.options, opts);

        // Create a set of rules to follow in our animation
        for(var i in animations){
            this.rules[i] = {
                element: animations[i].element,
                changes: new Array()
            };

            for(var style in animations[i].styles){

                // Calculate the start and end point values for the given style change
                var from = this.parse_style_value(animations[i].element, style, "");
                var to = this.parse_style_value(animations[i].element, style, animations[i].styles[style]);

                this.rules[i].changes.push({
                    from: from,
                    to: to,
                    style: style
                });
            }
        }

        this.start()
    },

    /*
     * Does some parsing of the given and real style values
     * Allows for pixel and percentage-based animations
     */
    parse_style_value: function(element, style, given_value){
        var real_value = element.css(style);

        if(given_value.indexOf("px") != -1){
            return {
                amount: given_value.substring(0, (given_value.length - 2)),
                unit: "px"
            };
        }

        if(real_value == "auto"){
            return {
                amount: 0,
                unit: "px"
            };
        }

        if(given_value.indexOf("%") != -1){
            var fraction = given_value.substring(0, given_value.length - 1) / 100;

            return {
                amount: (real_value.substring(0, real_value.length - 2) * fraction),
                unit: "px"
            };
        }

        if(!given_value){
            return {
                amount: real_value.substring(0, real_value.length - 2),
                unit: "px"
            };
        }
    },

    /*
     * Start the animation
     */
    start: function(){
        var self = this;
        var start_time = new Date().getTime();
        var freq = (1 / this.options.duration);

        var interval = setInterval(function(){
            var elapsed_time = new Date().getTime() - start_time;

            if(elapsed_time < self.options.duration){
                var f = elapsed_time * freq;

                for(var i in self.rules){
                    for(var j in self.rules[i].changes){
                        self.step(self.rules[i].element, self.rules[i].changes[j], f);
                    }
                }
            }
            else{
                clearInterval(interval);

                for(var i in self.rules){
                    for(var j in self.rules[i].changes)
                        self.step(self.rules[i].element, self.rules[i].changes[j], 1);
                }
            }
        }, 10);
    },

    /*
     * Perform an animation step
     * Only works with position-based animations
     */ 
    step: function(element, change, fraction){

        var new_value;
        switch(change.style){
            case 'height':
            case 'width':
            case 'top':
            case 'bottom':
            case 'left':
            case 'right':
            case 'marginTop':
            case 'marginBottom':
            case 'marginLeft':
            case 'marginRight':
                new_value = Math.round(change.from.amount - (fraction * (change.from.amount - change.to.amount))) + change.to.unit;
                break;
        }

        if(new_value)
            element.css(change.style, new_value);
    }
});

然后只需要在animate方法中修改原始的Accordion类以使用新的调用。

Then the original Accordion class only needs to be modified in the animate method to make use of the new call.

Accordion = function(container_id, options){
    this.init(container_id, options);
}

$.extend(Accordion.prototype, {
    container_id: '',
    options: {},
    active_tab: 0,    
    animating: false,
    button_position: 'below',
    duration: 250,
    height: 100,

    handle_class: ".handle",
    section_class: ".section",

    init: function(container_id, options){
        var self = this;
        this.container_id = container_id;
        this.button_position = this.get_button_position();

        // The height of each section, use the height specified in the stylesheet if possible
        this.height = $(this.container_id + " " + this.section_class).css("height");

        if(options && options.duration)    this.duration = options.duration;
        if(options && options.active_tab)  this.active_tab = options.active_tab;

        // Set the first section to have a height and be "open"
        // All the rest of the sections should have 0px height
        $(this.container_id).children(this.section_class).eq(this.active_tab)
            .addClass("open")
            .css("height", this.height)
            .siblings(this.section_class)
            .css("height", "0px");

        // figure out the state of the handles
        this.do_handle_logic($(this.container_id).children(this.handle_class).eq(this.active_tab));

        // Set up an event handler to animate each section
        $(this.container_id + " " + this.handle_class).mouseover(function(){

            if(self.animating)
                return;

            self.animate($(this));
        });
    },

    /*
     * Determines whether handles are above or below their associated section
     */     
    get_button_position: function(){
        return ($(this.container_id).children(":first").hasClass(this.handle_class) ? 'above' : 'below');
    },

    /*
     * Animate the accordion from one node to another
     */ 
    animate: function(handle){
        var active_section = (this.button_position == 'below' ? handle.prev() : handle.next());    
        var open_section = handle.siblings().andSelf().filter(".open");

        if(active_section.hasClass("open"))
            return;

        this.animating = true;

        // figure out the state of the handles
        this.do_handle_logic(handle);

        // Close the open section
        var arr = new Array();
        arr.push({
            element: open_section,
            styles: {
                "height": "0px"
            }
        });
        arr.push({
            element: active_section,
            styles: {
                "height": this.height
            }
        });
        new ParallelAnimations(arr, {duration: this.duration});

        var self = this;
        window.setTimeout(function(){
            open_section.removeClass("open");
            active_section.addClass("open");
            self.animating = false;
        }, this.duration);
    },

    /*
     * Update the current class or "state" of each handle
     */ 
    do_handle_logic: function(handle){
        var all_handles = handle.siblings(".handle").andSelf();
        var above_handles = handle.prevAll(this.handle_class);
        var below_handles = handle.nextAll(this.handle_class);

        // Remove all obsolete handles
        all_handles
            .removeClass("handle_on_above")
            .removeClass("handle_on_below")
            .removeClass("handle_off_below")
            .removeClass("handle_off_above");

        // Apply the "on" state to the current handle
        if(this.button_position == 'below'){
            handle
                .addClass("handle_on_below");
        }
        else{
            handle
                .addClass("handle_on_above");
        }

        // Apply the off above/below state to the rest of the handles
        above_handles
            .addClass("handle_off_above");

        below_handles
            .addClass("handle_off_below");
    }
});

仍然以相同的方式调用HTML:

The HTML is still called the same way:

<html>
<head>
    <title>Parallel Accordion Animation</title>
    <script type="text/javascript" src="jquery.js"></script>
    <script type="text/javascript" src="ui.js"></script>
    <script type="text/javascript">
    $(document).ready(function(){
        new Accordion("#accordion");
    });
    </script>
    <style type="text/css">
    #accordion{
        position: relative;
    }
    #accordion .handle{
        width: 260px;
        height: 30px;
        background-color: orange;
    }
    #accordion .section{
        width: 260px;
        height: 445px;
        background-color: #a9a9a9;
        overflow: hidden;
        position: relative;
    }
    </style>
</head>
<body>

<div id="accordion">
    <div class="section"><!-- --></div>
    <div class="handle">handle 1</div>
    <div class="section"><!-- --></div>
    <div class="handle">handle 2</div>
    <div class="section"><!-- --></div>
    <div class="handle">handle 3</div>
    <div class="section"><!-- --></div>
    <div class="handle">handle 4</div>
    <div class="section"><!-- --></div>
    <div class="handle">handle 5</div>
</div>

</body>
</html>

我可能会在未来添加一些内容:
- 排队动画
- 其他类型样式(颜色等)的动画

There are a few things I may add in the future: - Queued Animations - Animations for other types of styles (colors,etc)

这篇关于如何让jquery以完全并行的方式执行动画?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆