8

私は大まかに次のようなコードを持っています(関係がないので、いくつかの部分を削除しました):

Library.focus = function(event) {
    var element, paragraph;

    element = event.srcElement;

    paragraph = document.createElement("p");
    paragraph.innerText = element.innerText;

    element.parentNode.insertBefore(paragraph, element);        // Line #1
    element.parentNode.removeChild(element);                    // Line #2
};

私が抱えている問題は、行番号2として番号を付けた最後の呼び出しがこれをスローすることです:

Uncaught Error: NOT_FOUND_ERR: DOM Exception 8

前の行 #1 が正常に機能し、その前に段落ノードが挿入されていることに注意してください。Element は既存の要素であり、element.parentNode と element.parentNode.removeChild の両方も存在します。

要素は定義上、そのparentNodeの子であるため、これは非論理的です。ここで StackOverflow が私を助けてくれるのではないでしょうか?

4

3 に答える 3

8

mdn docsから:

子が実際には要素ノードの子ではない場合、メソッドは例外をスローします。これは、呼び出し時に子が実際には要素の子であったが、要素を削除しようとしたときに呼び出されたイベントハンドラーによって削除された場合にも発生します(例:ぼかし)。

このエラーはjsfiddleで再現できます

基本的に、要素にフォーカスを合わせます。これにより、削除がトリガーされ、ブラーがトリガーされ、要素が移動します。これにより、要素は親ではなくなります。

于 2012-07-22T12:50:31.347 に答える
2

onblur ハンドラーで、別のハンドラー (onfocus、keydown など) で削除しようとしている同じノードを変更しようとしている場合、removeChild実際にノードを削除する前に、最初の呼び出しで onblur ハンドラーが起動されます。次に、onblur ハンドラーがノードを変更してその親が変更されると、制御が onblur ハンドラーからremoveChildonfocus ハンドラーの呼び出しに戻り、ノードの削除が試行され、説明した例外で失敗します。

onfocus ハンドラーを呼び出す前に子の存在をいくらでもチェックしてremoveChildも無駄です。これは、これらのチェックが onblur ハンドラーがトリガーされる前に行われるためです。

イベント処理とノードの変更を再配置する以外に、try catch ブロックで例外を処理するのがおそらく最善の策です。

removeChild次のコードは、onfocus で実際に子を削除する前に、onblur イベント ハンドラーがどのように実行されるかを示しています。jsfiddleにもあります

html

<div id="iParent">
    <input id="i">
</div>

js

var input = document.querySelector("#i"),
inputParent = document.querySelector('#iParent');

input.onblur = function() {
    console.log('onblur : input ' + (input.parentNode ? 'has' : 'doesnt have') 
            + ' a parent BEFORE delete');
    try {
        inputParent.removeChild(input);
    } catch (err) {
        console.log('onblur : removeChild failed, input ' 
                + (input.parentNode ? 'has' : 'doesnt have') + ' a parent');
        return false;
    }
    console.log('onblur : child removed');
};

input.onfocus = function() {
    console.log('onfocus : input ' + (input.parentNode ? 'has' : 'doesnt have') 
            + ' a parent BEFORE delete');
    try {
        inputParent.removeChild(input);
    } catch (err) {
        console.log('onfocus : removeChild failed, input ' 
                + (input.parentNode ? 'has' : 'doesnt have') + ' a parent');
        return false;
    }
    console.log('onfocus : child removed');
};​

入力フィールドにフォーカスした後のコンソール出力は

onfocus : input has a parent BEFORE delete
onblur : input has a parent BEFORE delete
onblur : child removed
onfocus : removeChild failed, input doesnt have a parent 
于 2012-11-18T00:21:32.573 に答える
0

Library.focus関数のパラメーターとしてイベントを渡さないでください。それが動作します。

Library.focus = function() {
    var element, paragraph;

    element = event.srcElement;

    paragraph = document.createElement("p");
    paragraph.innerText = element.innerText;

    element.parentNode.insertBefore(paragraph, element);        // Line #1
    element.parentNode.removeChild(element);                    // Line #2
};
于 2012-07-22T12:48:54.807 に答える