2

我正在尝试删除 Google swiffy (v 5.2.0) 动画,然后在以后阅读它。

在运行动画方面似乎没有任何问题,但代码触发错误:TypeError:无法重新定义属性:Animation_fla.MainTimeline,此时电影中的所有AS3都停止工作。这似乎是因为 destroy 方法没有在 swiffy 运行时中删除对 AS3 代码的引用。我花了一些时间尝试单步执行代码,但这非常难以理解。

下面是我对 swiffy 所做的所有操作的精简版本 - 在调用 destroy 后再次调用 init 将触发此 TypeError。我试图重新初始化 swiffy 运行时本身,但这会导致类似的错误。

var stage;

function init() {
    stage = new swiffy.Stage(domElement, swiffyJson);
    stage.start();
}

function destroy() {
    stage.destroy();
    stage = null;
} 
4

2 回答 2

1

我想出的唯一解决方案是一个非常可怕的黑客攻击。看起来 Swiffy 真的不喜欢在动画被破坏后重新创建它们。我已经成功地将 Swiffy 从 DOM 中分离出来,但在内存中保留了它的引用。然后我不得不破解运行时以启用暂停和重新启动。然后我可以重新连接原来的 Swiffy 而不必破坏它。这是在从https://www.gstatic.com/swiffy/v5.2/runtime.js下载的 v5.2.0 中,在将运行时通过 jsbeautifier.org 之后

在函数之后的第 5640 行附近,M.releaseCapture我添加了以下函数:

M.hackPause = function (bool) {
    if(this.hackPaused === bool) return;

    if(this.hackPaused) {
        bi(ef(this.qh.yl, this.qh));
    }

    this.hackPaused = bool;
};

在第 7137 行周围,将AK[I].yl函数替换为以下内容:

Ak[I].yl = function () {
    if (this.bh) {
        var a = Date.now();
        a >= this.Mf && (this.tl.ei(), this.Mf += (s[Xb]((a - this.Mf) / this.sl) + 1) * this.sl);
        this.tl.lc();

        if(!this.tl.hackPaused) {
            bi(ef(this.yl, this))
        }
    }
};

这样做是为了阻止 requestAnimationFrame 或 setTimeout 触发,从而有效地暂停动画。

我也尝试在运行时中公开 gotoAndStop 函数,但我无法在代码中找到范围。与此同时,使用这篇文章中的一个技巧 -是否可以从 JS 暂停/恢复/操作一个 swiffyobject?我们可以通过将进入帧事件添加到 Flash 电影并测试 Flashvars 的变化来使用蛮力方法来做到这一点。下面是我们一直用于动画的文档类。值得注意的是,Swiffy 似乎不喜欢从同一个基类扩展的 AS3 类,它会引发相同的无法重新定义属性错误,因此我们在每个 Flash 动画的 Document 类中复制了此处的代码。我'

package {

    import flash.display.MovieClip;
    import flash.net.URLRequest;
    import flash.net.navigateToURL;
    import flash.events.Event;
    import flash.utils.setTimeout;

    public class BaseAnimation extends MovieClip {

        private var _request:URLRequest;
        private var _pageName:String;
        private var _movieName:String;

        public function BaseAnimation() {
            _request = new URLRequest();

            _pageName = getFlashVar('pageName');
            _movieName = getFlashVar('movieName');

            addEventListener(Event.ENTER_FRAME, jsListen);
        }

        private function getFlashVar(name:String):String {
            var flashVar:String = stage.loaderInfo.parameters[name] || '';
            stage.loaderInfo.parameters[name] = '';

            return flashVar;
        }

        public function dispatchJSEvent(eventName:String, param:String = ''):void {
            _request.url = "javascript:onSwiffyEvent('" + eventName + "', '" + param + "', '" + _movieName + "', '" + _pageName + "');";
            navigateToURL(_request, "_self");
        }

        private function jsListen(e:Event):void {
            var mode:String = getFlashVar('mode');

            if(mode.length) {
                switch(mode) {
                    case 'stop':
                        stop();
                        break;

                    case 'play':
                        play();
                        break;

                    case 'gotoStart':
                        gotoAndStop('start');
                        break;
                }
            }
        }
    }
}

Swiffy 似乎也不喜欢 gotoAndStop(0) 所以我不得不在动画的第一帧上设置一个帧标签“开始”。

有了所有这些可怕的骇客,我们就可以删除并重新启动 Swiffy 动画。我们发现的唯一问题是分离和重新附加导致嵌入的 SVG 字体出现问题,我们最终将所有文本转换为轮廓。上面是这样使用的:

您可以像这样在 swiffy 舞台上调用它:

var stage = new swiffy.Stage(domObject, swiffyObj);
stage.start();

// when reading to remove this element from the DOM do the following:
stage.setFlashVars('mode=gotoStart');

setTimeout(function () {
    // timeout is required to ensure that the enterframe listener has time to run
    stage.hackPause(true);   // paused animation
}, 100);

// you can then remove the containing div from the DOM, but retain it in memory

// after you reattach the div to the DOM, ensuring we've kept hold of our stage variable in memory, you can restart it like this:

stage.hackPause(false);             // resumes javascript requestAnimationFrame
stage.setFlashVars('mode=play');    // resumes flash animation

希望这对某人有所帮助,但我也真的希望 Google 开始向 Swiffy 运行时公开某种 JS API 或 ExternalInterface,以便让我们更好地控制真正非常棒的工具。

于 2013-06-19T22:46:35.753 回答
0

在将 swiffyobject 传递给 swiffy.Stage() 之前尝试创建一个副本。Swiffy 在实例化时修改对象,因此使用副本您可以在 destroy() 之后简单地重新创建

于 2013-08-23T01:06:56.930 回答