JS: innerHTML inconsistency

JS: innerHTML inconsistency

本文关键字:inconsistency innerHTML JS      更新时间:2023-09-26

我使用的是Google Chrome版本43.0.2357.130。我试图使用innerHTML将输出附加到HTML元素,这是在循环中完成的。大多数情况下我都会得到预期的结果,但如果我反复点击"Generate"按钮,最终它会给我一个意想不到的结果。例如,其中一个密码会在随机的位置被截断。我在Chrome中使用了JS调试器,但这并没有多大帮助。然后,我尝试通过使用alert()函数和innerHTML属性来调试它,以便比较输出。与innerHTML不同,alert()弹出窗口中的输出从未被截断。

我在JS文件中用'/* problem code */'突出了我认为是问题代码。这些文件应该放在同一个目录中。下面是HTML和JS:

<!DOCTYPE html>
<html>
<head>
    <title>PassGen - Random Password Generator</title>
    <!--link rel="stylesheet" src="//normalize-css.googlecode.com/svn/trunk/normalize.css"-->
    <!--link href="css/main.css" rel="stylesheet" type="text/css"-->
    <!--script src="../app/js/jquery-2.1.4.js"></script-->
</head>
<body>
    <form>
        <h2>Password amount</h2>
        <input type="text" id="amount" name="amount" />
        <h2>Letter amount</h2>
        <input type="text" id="letters" name="letters" />
        <h2>Number amount </h2>
        <input type="text" id="numbers" />
        <h2>Symbol amount</h2>
        <input type="text" id="symbols" />
        <input onclick="generatePassword(); return false;" type="submit" value="Generate" />
    </form>
    <p id="output"></p>
    <script src="plain-app.js"></script>
</body>
</html>

// get the DOM element we will be using for the final output
var output = document.getElementById("output");
function generatePassword(amount) {
    clearPasswords();
    // get DOM form elements (user input)
    var amount = document.getElementById("amount").value;
    var letters = document.getElementById("letters").value;
    var numbers = document.getElementById("numbers").value;
    var symbols = document.getElementById("symbols").value;
    // populate character sets
    var letterSet = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
    var numberSet = "0123456789";
    var symbolSet = "~!@#$%^&*()-_+=><";
    var array = [];
    // if there is no password amount specified, create one password
    if(amount === undefined) {
        amount = 1;
    }
    for(var j = 0; j < amount; j++) {
        // random character sets to be concatenated later
        var rl = "";
        var rn = "";
        var rs = "";
        var tp = ""; // concatenated password before shuffling
        // 3 random letters
        for(var i = 0; i < letters; i++) {
            var rnd = Math.floor((Math.random() * 52));
            rl += letterSet[rnd];
        }
        // 3 random numbers
        for(var i = 0; i < numbers; i++) {
            var rnd = Math.floor((Math.random() * 10));
            rn += numberSet[rnd];
        }
        // 3 random symbols
        for(var i = 0; i < symbols; i++) {
            var rnd = Math.floor((Math.random() * 17));
            rs += symbolSet[rnd];
        }
        tp = rl + rn + rs; // string concatentation
        tp = tp.split(''); // transform string into an array
        // shuffling
        for(var i = 0; i < tp.length; i++) {
            var rnd = Math.floor(Math.random() * tp.length);
            var temp = tp[i];
            tp[i] = tp[rnd];
            tp[rnd] = temp;
        }
        // transform the array into a string
        tp = tp.join("");
        array[j] = tp; // for logging and debugging purposes
        // tp can be replaced with array[j], but still get the inconsistency
        /* PROBLEM CODE */
        output.innerHTML += (tp + "<br />");
        /* PROBLEM CODE */
        //alert(array[j]);
    }
    console.log(array);
    return array; // not useful?
}
// clear all password output
function clearPasswords() {
    while(output.hasChildNodes()) {
        output.removeChild(output.firstChild);
    } 
}

是否innerHTML有副作用,我不知道或我使用它不正确?它不应该用于追加吗?应该使用appendChild()吗?

问题是有些字符在HTML中有特殊的含义:<, >, &

因此,可以

  • 从列表中删除这些字符
  • 转义:&lt;, &gt;, &amp;

    output.innerHTML += tp.replace(/</g, '&lt;').replace(/>/g, '&gt;').replace(/&/g, '&amp;') + "<br />";
    
  • 将文本解析为文本而不是HTML,例如

    • 使用textContentwhite-space

      output.textContent += tp + "'n";
      
      #output { white-space: pre-line; }
      
    • 使用createTextNodeappendChild

      output.appendChild(document.createTextNode(tp));
      output.appendChild(document.crateElement('br'));
      

symbolSet。它包含字符<>。当随机选择它们并将它们添加到密码中时,当我将密码输出到屏幕时,浏览器试图将它们呈现为元素。为了解决这个问题,我只是从symbolSet中删除了两个字符,并更改了随机符号生成循环,以反映symbolSet的缩短长度。

我将两个有问题的代码段更改为

var symbolSet = "~!@#$%^&*()-_+=";

for(var i = 0; i < symbols; i++) {
    var rnd = Math.floor((Math.random() * 15)); // this end of this line
    rs += symbolSet[rnd];
}

此外,我将无用的if语句更改为(这可以应用于所有字段)

if(!isNumber(amount) || amount === 0) {
    amount = 1;
}

并添加了一个isNumber函数来检查所有字段上的有效输入。

function isNumber(obj) {
    return !isNaN(parseFloat(obj));
}