36

わかりました、私は数時間この混乱を解明しようとしてきましたが、犬が尻尾を追いかけているように、どこにも行き着きません. これが状況です。

私は自分の UI に Knockout.js を使用しています。これはそれだけでうまく機能します。ただし、ドロップダウンとチェックボックスをきれいに見せるサードパーティのコードを使用しようとしています。実際、これがサードパーティのライブラリなのか、デザイナーが書いたものなのかさえわかりません。このコードは、実際のチェックボックスを隠し<span />、 CSS を介してチェックボックスを模倣した偽物に置き換えます。clickスパンのイベントは、実際のチェックボックスのイベントをトリガーしますchange:

// this code updates the fake UI
this._changeEvent = function() {
    self.isChecked = self.$input.is(':checked');
    self._updateHTML(false, true);
    jQuery(self).trigger('change');
};

// when the user clicks the fake checkbox, we trigger change on the real checkbox
this.$fake.on('click', function(e) {
    e.preventDefault();
    self.$input.click().trigger('change');
});

// Bind _changeEvent to the real checkbox
this.$input.change(this._changeEvent);

Knockout はそのイベント ハンドラーをリッスンするため、これは実際には Knockout.js で機能します。つまり、ユーザーが偽のチェックボックスをクリックすると、バインドされた Knockout モデルが更新されます。ただし、うまくいかないのはモデルの更新です。私が電話した場合:

model.SomeValue(!curValue); // SomeValue is bound to a checkbox, flip its value

モデルは更新されますが、偽の UI は更新されません。この問題を追跡ko.bindingHandlers.checked.updateして、次のことを行うコードにたどり着きました。

// When bound to anything other value (not an array), the checkbox being checked represents the value being trueish
element.checked = value;

基本的に、element.checkedプロパティは設定されますが、イベントは発生しません。したがって、_changeEvent関数が呼び出されることはありません。ko.bindingHandlers.checked.updateそこで、組み込み関数のコピーである独自の関数を実装しました。理論的には、これは私がする必要があるすべてです:

   ko.bindingHandlers.checked.update = function (element, valueAccessor)
   {
      var value = ko.utils.unwrapObservable(valueAccessor());

      if (element.type == "checkbox")
      {
         if (value instanceof Array)
         {
            // When bound to an array, the checkbox being checked represents its value being present in that array
            element.checked = ko.utils.arrayIndexOf(value, element.value) >= 0;
         }
         else
         {
            // When bound to anything other value (not an array), the checkbox being checked represents the value being trueish
            //element.checked = value;
            $(element).prop('checked', value).trigger('change'); // <--- this should work!
         }
      }
      else if (element.type == "radio")
      {
         element.checked = (element.value == value);
      }
   };

を設定するelement.checkedのではなく、change イベントを呼び出し.prop('checked', value)てトリガーします。ただし、これは機能していません。これが私がこれまでに知っていることです:

  1. 式から Knockout.js を削除すると、$(element).prop('checked', value).trigger('change');完全に正常に動作します。そのため、knockout.js は何らかの方法でイベントを台無しにしています。そのイベントハンドラーのバインドを解除していますか?
  2. 偽のチェックボックス バインディング コード$(element)と同じであることを確認しました。this.$inputこの要素に他の expando プロパティを設定すると、それらが表示されます。
  3. イベントがまだバインドされているかどうかを確認するために、Knockout.js と jQuery にデバッグしようとするいくつかのアプローチを試みましたが、このアプローチでは実際にはどこにも行きませんでした。私の推測では、Knockout.js がどうにかしてchangeイベント ハンドラーを独自の内部ハンドラーに置き換え、既存のバインディングが削除されたということです。これを確認する方法はまだ見つかっていません。

私の質問:主に、この問題の解決策を探しています。Knockout.jschangeは、モデルが適用される前に存在していた既存のイベントを削除しますか? このコードをデバッグし、何が起こっているのかを正確に把握するための次のステップは何ですか?

4

6 に答える 6

0

チェックボックス オブジェクトを jQuery プラグインとして作成し、ノックアウト カスタム バインディングを作成してビューモデルにバインドしてみてください。私はまさにそれを行うjsfiddleをセットアップしました: http://jsfiddle.net/markhagers/zee4z/3/

$(function () {
    var viewModel = {
        truthyValue1: ko.observable(false),
        truthyValue2: ko.observable(true)
    };

    ko.applyBindings(viewModel);
});

(このスニペットを追加する必要がありました。または、回答が受け入れられませんでした。完全なコード例については、jsfiddle を参照してください)。申し訳ありませんが、多くのコードのように見えますが、プラグイン部分はもともとスタンドアロンの jquery プラグインであり、後でノックアウト バインディングが追加されました。その中の一部のコードは、ノックアウト バインディングによって廃止されました。混乱を減らすために、独自のファイルに入れることができます。カスタム バインディングの作成については、ノックアウト Web サイトに記載されています。

于 2013-08-16T11:16:51.510 に答える
0

あなたが抱えている問題は、ノックアウトと別のコード セット (チェックボックスの CSS の変更など) からのイベントの競合によるものではなく、Javascript スレッドの競合とスレッドが処理されます。

Javascript はブラウザーで単一のスレッドとして処理されます。すべてのプロセスが順次実行され、シーケンスを中断するイベントによってイベントが失敗する可能性があります。各関数を個別に呼び出すことができても、両方をスクリプトに含めると干渉が発生する場合は、チェックボックスの CSS 変更をトリガーする onclick または onmousedown イベントがノックアウト スクリプトに干渉する可能性があります。この「単一スレッド」では、すべてのイベントが別の実行に影響を与える可能性があり、マウスの動きさえも影響します。

この ( http://ejohn.org/blog/how-javascript-timers-work/ ) の例は、タイマーを使用したこのアイデアを示していますが、現在の状況は同じ問題に苦しんでいる可能性があると思います。

それを解決するには、次のような短い関数を作成します。

関数 doBoth(checkboxid){

$("#checkboxid").addclass("prettychecked");

$("#checkboxid").prop('checked', true);

}

重要な点は、マウス イベントが中断する可能性がなく、各アクションが順番に実行されることです。

お役に立てれば!

于 2013-09-09T20:52:28.527 に答える
0

ブレーンストーミングですが、このサードパーティ コントロールはイベント名前空間を使用して開発されたのでしょうか? あなたが示唆しているように、ノックアウトとこのコントロールが何らかの方法でデフォルトの「変更」イベントをめぐって争っている可能性があります。ウィジェットとアプリケーションを開発するとき、jQuery を使用してイベントをバインドするときは常にイベント名前空間を使用します。

「myWidget」名前空間を使用した例:

$('#element').on('change.myWidget', function(e) {
  // handle the event
}

私は完全にベースから外れている可能性があります。

于 2013-08-21T14:46:10.437 に答える
0

Try triggering and listening also for a custom event:

element.checked = value;
element.dispatchEvent(new Event("forcedChange"));
于 2013-08-15T12:37:10.843 に答える
0

ちょっと考えただけです。あなたのデザイナーは、この行でクリックと変更イベントをトリガーしているようです:

self.$input.click().trigger('change');

それは試してみることではないでしょうか?変更イベントではなく、クリック イベントにバインドされている可能性があります。あなたのelseステートメントでこれを試してください:

$(element).prop('checked', value).click().trigger('change'); // <--- this should work!

.click() が行うことを私が理解していること: マウスクリックを模倣し、同時にクリックイベントをトリガーします (Duh?)。

ラジオやチェックボックスの場合のように、イベントを変更ではなくクリックにバインドするコーダーがいることを知っています。これは、正しいタイミングで発生する可能性が高いためです (IE7 では、変更イベントは非常に奇妙な方法で発生します)。

ちょっと考えただけで、試してみる価値があるかもしれません。それが役に立てば幸い!

編集: イベントとカスタム イベントの名前空間に関する回答を見ました。これもあなたを助けることができます.それがあまりにも大きな変化でないことを願っています.

/J.

于 2013-08-27T08:19:02.850 に答える