6

ポップアップ情報バブルを表示することを目的とDIVしたハンドラーを備えたsを含むWebページがあります。mouseover一度に複数の情報バブルを表示したくありません。しかし、ユーザーが2つのアイテムの上でマウスをすばやく動かすと、2つのバブルが発生することがあります。ポップアップを表示するコードは前のポップアップをキャンセルするため、これは発生しないはずです。

これがマルチスレッドシステムの場合、問題は明らかです。ポップアップを表示しようとしている2つのスレッドがあり、どちらも既存のポップアップをキャンセルしてから、独自のポップアップをポップアップします。しかし、JavaScriptは常にシングルスレッドで実行されると思いました。これにより、これが妨げられます。私が間違っている?イベントハンドラーは非同期で実行されていますか?その場合、共有データへの同期アクセスが必要ですか、それともポップアップをキャンセルするためにライブラリコードのバグを探す必要がありますか?

追加するために編集:

  • 問題のライブラリは、SIMILETimelineとそのAjaxライブラリです。
  • イベントハンドラーはを呼び出しますSimileAjax.DOM.cancelEvent(domEvt)。これは、名前に基づいてイベントのバブリングをキャンセルすると思います。
  • もっと複雑にするために、私が実際に行っているのはタイムアウトを開始することですmoustout。これは、ポップアップによってキャンセルされない場合、ポップアップが煩わしくちらつくのを防ぐことを目的としていますが、逆の効果があります。

私はそれをもう一度突いて、どこが間違っているのかを理解できるかどうかを確認します。:-)

4

7 に答える 7

9

はい、Javascript はシングルスレッドです。Google Chrome のようなブラウザでも、タブごとに 1 つのスレッドがあります。

あるポップアップを別のポップアップからキャンセルしようとしている方法を知らなければ、問題の原因を特定することは困難です.

DIV が互いに入れ子になっている場合、イベントの伝播に問題がある可能性があります。

于 2008-10-02T11:23:09.927 に答える
2

使用しているライブラリはわかりませんが、一度に何らかのツールチップを 1 つだけ表示しようとしている場合は、flyweight オブジェクトを使用してください。基本的にフライウェイトは、一度作って何度も使うものです。シングルトンクラスを考えてみてください。したがって、最初に呼び出されたときに自動的にそれ自体のオブジェクトを作成して格納するクラスを静的に呼び出します。これはすべての static all が同じオブジェクトを参照するたびに発生します。このため、複数のツールチップや競合が発生することはありません。

私は ExtJS を使用しており、ツールチップとメッセージ ボックスを両方の軽量要素として使用しています。あなたのフレームワークにも flyweight 要素があることを願っています。それ以外の場合は、独自のシングルトンを作成して呼び出す必要があります。

于 2009-05-20T05:47:39.247 に答える
1

ブラウザではシングルスレッドです。イベント ハンドラーは 1 つのスレッドで非同期に実行されます。非ブロッキングは常にマルチスレッドを意味するわけではありません。あなたの div の 1 つは他の div の子ですか? イベントは dom ツリーの泡のように子から親へと広がっていくからです。

于 2008-10-02T11:24:47.867 に答える
1

pkaeding が言ったことと同様に、マークアップとスクリプトを見ずに問題を推測するのは困難です。ただし、イベントの伝播を適切に停止していない、および/または既存の要素を適切に隠していない、とあえて言いたいと思います。フレームワークを使用しているかどうかはわかりませんが、Prototype を使用した解決策は次のとおりです。

// maintain a reference to the active div bubble
this.oActiveDivBubble = null;

// event handler for the first div
$('exampleDiv1').observe('mouseover', function(evt) {
    evt.stop();
    if(this.oActiveDivBubble ) {
        this.oActiveDivBubble .hide();
    }
    this.oActiveDivBubble = $('exampleDiv1Bubble');
    this.oActiveDivBubble .show();

}.bind(this));

// event handler for the second div
$('exampleDiv2').observe('mouseover'), function(evt) {
    evt.stop();
    if(this.oActiveDivBubble) {
        this.oActiveDivBubble.hide();
    }
    this.oActiveDivBubble = $('exampleDiv2Bubble');
    this.oActiveDivBubble .show();
}.bind(this));

もちろん、これは、たとえば同じクラスを持つすべての要素を取得し、それらを反復処理し、同じイベント処理関数をそれぞれに適用することで、さらに一般化できます。

いずれにせよ、これが役立つことを願っています。

于 2008-10-02T11:33:21.947 に答える
1

参考までに: Firefox 3 の時点で、この議論にかなり関連する変更があります。同期 XMLHttpRequest リクエストを引き起こす実行スレッドが切り離され (これが、同期リクエスト中にインターフェースがそこでフリーズしない理由です)、実行が続行されます。同期要求が完了すると、そのスレッドも続行されます。それらは同時に実行されることはありませんが、同期プロシージャ (リクエスト) が発生している間に単一のスレッドが停止するという前提に依存することは、もはや適用できません。

于 2008-10-02T12:41:08.633 に答える
0

ディスプレイの更新速度が十分でない可能性があります。使用している JS ライブラリによっては、ポップアップの「表示」効果を少し遅らせることができる場合があります。

于 2008-10-02T11:32:43.337 に答える
0

多かれ少なかれ、これが作業バージョンです。mouseoverアイテムを作成するとき、イベントを添付します。

var self = this;
SimileAjax.DOM.registerEvent(labelElmtData.elmt, "mouseover", function (elt, domEvt, target) {
    return self._onHover(labelElmtData.elmt, domEvt, evt);
});

これは、タイムアウトを設定する関数を呼び出します (別のアイテムの既存のタイムアウトが最初にキャンセルされます)。

MyPlan.EventPainter.prototype._onHover = function(target, domEvt, evt) {            
    ... calculate x and y ...
    domEvt.cancelBubble = true;
    SimileAjax.DOM.cancelEvent(domEvt);
    this._futureShowBubble(x, y, evt);

    return false;
}
MyPlan.EventPainter.prototype._futureShowBubble = function (x, y, evt) {
    if (this._futurePopup) {
        if (evt.getID() == this._futurePopup.evt.getID()) {
            return;
        } else {
            /* We had queued a different event's pop-up; this must now be cancelled. */
            window.clearTimeout(this._futurePopup.timeoutID);
        } 
    }
    this._futurePopup = {
        x: x,
        y: y,
        evt: evt
    };    
    var self = this;
    this._futurePopup.timeoutID =  window.setTimeout(function () {
            self._onTimeout();
    }, this._popupTimeout);
}

これは、キャンセルされる前にバブルが発生した場合のバブルを示しています。

MyPlan.EventPainter.prototype._onTimeout = function () {
    this._showBubble(this._futurePopup.x, this._futurePopup.y, this._futurePopup.evt);

};

MyPlan.EventPainter.prototype._showBubble = function(x, y, evt) {
    if (this._futurePopup) {
        window.clearTimeout(this._futurePopup.timeoutID);
        this._futurePopup = null;
    }        
    ...

    SimileAjax.WindowManager.cancelPopups();
    SimileAjax.Graphics.createBubbleForContentAndPoint(...);
};

タイムアウトを 100 ミリ秒ではなく 200 ミリ秒に設定したので、これはうまくいくようです。タイムアウトが短すぎるとマルチバブルが発生する理由はわかりませんが、新しく追加された要素がレイアウトされている間、ウィンドウイベントのキューイングまたは何かがまだ発生している可能性があります.

于 2008-10-02T13:24:57.530 に答える