innerHTML在每个keydown事件中都不会改变

时间:2017-10-15 02:47:10

标签: javascript html greasemonkey

以下代码旨在将元素(myInput)的innerHTML更改为另一个元素(// ==UserScript== // @name Duolingo // @include *://duolingo.com/* // @include *://www.duolingo.com/* // ==/UserScript== setTimeout(()=>{ let myInput = document.querySelector('._7q434._1qCW5._2fPEB._3_NyK._1Juqt._3WbPm'); let myNote = document.createElement('div'); document.body.appendChild(myNote); myNote.setAttribute("style", "position: fixed; bottom: 0; right: 0; display: block; width: 400px; height: 400px; background: orange; color: #000"); myInput.addEventListener('keydown', (k)=>{ if ( k.keyCode === 13 ) { myNote.innerHTML += myInput.value + '<br>'; } }); }, 2000); )的值,每次 <按> em>返回 键:

innerHTML

目的

我在duolingo.com(一个学习像法语这样的mind2mind语言的网站)的Greasemonkey中运行代码,在文本问题会话中,例如“翻译这句话”。

代码的目的是创建一个小的橙色背景框,其中包含我在Duolingo问题中尝试过的输入,因为Duolingo没有保存这些。

使用脚本,我可以保存它们,如果我重新输入一个语言问题,以后再使用它们,因为它可以节省一些时间重新输入大部分句子。

问题

代码失败,因为innerHTML只更改了一次。如果值再次发生变化并且我压制 返回 ,则不会发生任何事情。

重现

使用duolingo.com上的Greasemonkey(或类似程序)中的代码重现。

问题

为什么addEventListener只会被更改一次?鉴于return一直在倾听,为什么它只能工作一次?

使用return false进行更改或添加setTimeout(()=>{ window.myCss =`.note {position: fixed; bottom: 0; right: 0; width: 400px; height: 400px; background: orange}`; style = document.createElement("style"); style.type = "text/css"; style.styleSheet ? style.styleSheet.cssText = myCss : style.appendChild(document.createTextNode(myCss) ); head = document.head || document.getElementsByTagName("head")[0]; head.appendChild(style); let note = document.createElement('div'); note.classList.add('note'); document.querySelector('body').appendChild(note); let savedValue; document.addEventListener('keydown', (e)=>{ let target = e.target; if (target.nodeName === 'textarea') { savedValue = e.target.value; } }); if (k.keyCode === 13) { setTimeout(()=>{ document.querySelector('textarea').value = savedValue; }, 100); } }, 2500); 无效。

可能需要另外一种方法来添加一个包含每次按下值的新元素。

Mobius更新:

Mobius,这是我使用的代码,但没有用:

html

我在控制台中没有任何错误。

我尝试阅读文章,我理解在原始示例中我喋喋不休而不是捕获(我应该通过每次从textarea元素转到BServico.write(new byte[] { 28, 46 }); //Cancels Chinese character mode //TEST for (int i = 0; i < 20; i++) { String text = String.format("%d - %s - çüáéíóúñåæø\n", i, Integer.toHexString(i)); BServico.write(new byte[] { 0x1B, 0x74, (byte)i }); try { BServico.write(text.getBytes("ISO-8859-1")); } catch (Exception ex) { // } } 元素来捕获任何处理程序重新捕捉它的处理程序,但我看不出如何从中改进代码。也许我现在读的不好,因为我心情不好......

3 个答案:

答案 0 :(得分:3)

duolingo中的测验是根据我的判断编写的,因此很可能你添加事件监听器的元素不再存在。有几种方法可以解决这个问题,但最好的方法是使用事件冒泡(可能在捕获阶段)来监听不会被替换的内容,例如tools: context = "activity name"元素,并等待来自元素的事件符合您的需求。

您的代码将如下所示:

body

答案 1 :(得分:1)

代码失败(删除拼写错误后),因为它将事件监听器添加到网页覆盖每个新问题的文本区域。当textarea被覆盖时,它会破坏您添加的上一个事件侦听器。它还会使该代码中myInput的值孤立。

在持久性容器或整个主体上使用更智能的事件侦听器。并根据需要刷新myInput

还有其他问题:

  1. ._7q434._1qCW5._2fPEB._3_NyK._1Juqt._3WbPm 是一个非常脆弱的选择器,并会在下次网站代码更改时中断。它在我看到的某些页面上也不起作用。

    textarea[data-test]可能会奏效。或者甚至textarea也可以满足代码的其余部分。

  2. setTimeout是一种等待元素的脆弱方式,而且是already causing you grief。请改用waitForKeyElementsMutationObserver或类似名称。但在您的情况下,由于您正在等待用户交互,您可能不需要任何其他延迟机制。

  3. 将所有内容放在一起,您的用户脚本将类似于:

    // ==UserScript==
    // @name        Duolingo, answer text recycler
    // @match       *://*.duolingo.com/*
    // @run-at      document-idle
    // ==/UserScript==
    let myNote = document.createElement ('div');
    document.body.appendChild (myNote);
    myNote.setAttribute (
        "style",
        "position: fixed; bottom: 0; right: 0; width: 400px; height: 400px; background: orange; overflow: auto;"
    );
    
    document.addEventListener ('keydown', (zEvent) => {
        if (zEvent.keyCode === 13) {
            if (zEvent.target.nodeName === 'TEXTAREA') {
                let myInput = document.querySelector ('textarea[data-test]');
                if (myInput) {
                    myNote.innerHTML += myInput.value + '<br>';
                }
            }
        }
    } );
    

答案 2 :(得分:0)

&#13;
&#13;
// ==UserScript==
// @name        Duolingo
// @namespace   nms
// @include     *://duolingo.com/*
// @include     *://www.duolingo.com/*
// @version     1
// @grant       none
// ==/UserScript==

setTimeout(()=>{
    // Style:

        /*let myCss =`
            .note {position: fixed; bottom: 0; right: 0; width: 400px; height: 400px; background: orange}
        `;*/
      let myCss =`
            .note {position: fixed; top: 100px; left:100px; bottom: 100px; right: 100px; width: 200px; height: 200px; background: orange}
        `;  

        style = document.createElement("style");
        style.type = "text/css";
        style.styleSheet ? style.styleSheet.cssText = myCss : style.appendChild(document.createTextNode(myCss) );

        head = document.head || document.getElementsByTagName("head")[0];
        head.appendChild(style);

    // Behavior:

        let myNote = document.createElement('div');
        myNote.classList.add('note');
        document.querySelector('body').appendChild(myNote);
        let myInputField = document.querySelector('textarea');

        myInputField.addEventListener('keydown', (k)=>{
            if ( k.keyCode === 13 ) {
                myNote.innerHTML = myInputField.value;
            }
        });
}, 2000);
&#13;
<textarea></textarea>
<br>
<div id="myNote">

</div>
&#13;
&#13;
&#13;

如果您在StackOverflow的完整页面视图中运行原始代码,则代码运行正常。我改变了橙色矩形的css,以便在非完整页面视图中更好地查看结果,它也可以工作。注意:我使用的是Google Chrome版本49.0.2623.112米。