在textarea中创建一个javascript函数

时间:2016-09-01 23:06:24

标签: javascript

我正在尝试创建一个html / css / javascript在线编辑器,供人们尝试使用小代码和类似的东西。 它实际上非常简单..你创建2 div&#39; s是textarea id="input"而另一个是div id="output"而你创建一个js函数,通过按下按钮将输入的内容推送到输出中,或者通过每2秒运行一次该函数使其生效 我运行代码,它适用于html和css,但是一旦我尝试在<script>里面的textarea标签内创建一个函数,它实际上并没有运行..就像它没有&#39;存在.. 我可以使用按钮运行小函数,如果我在onclick内编写动作但是定义一个函数,然后通过该按钮运行它不起作用

window.setInterval(function(){
    var y = document.getElementById("automatic").checked
    if (y==1){
        editorFunction()
    }
}, 1000);

function editorFunction(){
    var x = document.getElementById("input").value;
    document.getElementById("output").innerHTML = x;
}

我的问题是......有没有办法解决这个问题? 我真的希望页面保持静态..我不想将内容发送到数据库并创建一个新表单并在页面上呈现它...我想保持它尽可能简单 有人要求提供HTML ..我不认为这很重要但是在这里:

<body id="body">
<section class="container">
    <div class="row">
        <div class="col-sm-6">
            <textarea class="col-sm-12" id="input"></textarea>
        </div>
        <div class="col-sm-6">
            <div class="col-sm-12" id="output"></div>
        </div>
    </div>
</section>
<section>
    <div class="row">
        <div class="col-sm-3"></div>
        <div class="col-sm-6">
            <button onclick="editorFunction()">RUN</button>
            <input type="checkbox" id="automatic" checked>Submit the changes LIVE</input>
        </div>
    </div>
</section>
</body>

eval()仅在我想执行某个动作时才有效。我无法真正定义一个将留待以后使用的功能

2 个答案:

答案 0 :(得分:1)

根据Denis Ivanov的建议,我提出了这个解决方案:

function editorFunction(){
    var x = document.getElementById("input").value;
    var output=document.getElementById("output");
    output.innerHTML = x;
    var scripts=output.getElementsByTagName("SCRIPT");
    for (var i=0;i<scripts.length;i++)
    {
        var script=scripts[i];
        eval(script.textContent);
    }
}

但是我对自动模式有疑问:显然,当用户编写脚本函数时,它还不应该被测试。

<强>更新

支持定义功能(基于Makyen的建议):

function editorFunction(){
    var x = document.getElementById("input").value;
    var output=document.getElementById("output");
    output.innerHTML = x;
    var scripts=output.getElementsByTagName("SCRIPT");
    for (var i=0;i<scripts.length;i++)
    {
        var script=scripts[i];
        var x=eval(script.textContent);

        var scriptNew=document.createElement("SCRIPT");
        scriptNew.type=script.type;
        scriptNew.textContent=script.textContent;
        script.parentNode.insertBefore(scriptNew, script);
        script.parentNode.removeChild(script);
    }
}

答案 1 :(得分:1)

您需要专门处理<script>标记。作为文本插入的内容(例如innerHTML)被特别排除在运行脚本之外。这是security reasons

您可以使用innerHTML插入文字,然后在使用<script>创建新标记的同时删除插入的document.createElement('script')标记,在其中添加脚本的textContent标记您正在删除。然后将新创建的<script>标记插入文档

window.setInterval(function(){
    var y = document.getElementById("automatic").checked
    if (y==1){
        editorFunction()
    }
}, 1000);

function editorFunction(){
    var x = document.getElementById("input").value;
    var outputEl = document.getElementById("output");
    outputEl.innerHTML = x;
    //Get a NodeList of the <script> elements
    var scripts = outputEl.querySelectorAll('script');
    for(var i=0;i<scripts.length;i++){
        var oldScript = scripts[i];
        var newScript = document.createElement('script');
        //Copy the actual script
        newScript.textContent = oldScript.textContent;
        //Copy the oldScripts attributes
        var attrs = oldScript.attributes;
        for(var j=0;j<attrs.length;j++){
            newScript.setAttribute(attrs[j],oldScript.getAttribute(attrs[j]));
        }
        //Replace the non-functional oldScript with the newScript
        oldScript.parentNode.replaceChild(newScript,oldScript);
    }
}
<body id="body">
<section class="container">
    <div class="row">
        <div class="col-sm-6">
            <textarea class="col-sm-12" id="input"></textarea>
        </div>
        <div class="col-sm-6">
            <div class="col-sm-12" id="output"></div>
        </div>
    </div>
</section>
<section>
    <div class="row">
        <div class="col-sm-3"></div>
        <div class="col-sm-6">
            <button onclick="editorFunction()">RUN</button>
            <input type="checkbox" id="automatic" checked>Submit the changes LIVE</input>
        </div>
    </div>
</section>
</body>

建议更改:

  1. 使用事件处理程序,而不是间隔计时器:
    • 我会实现一种自动更新输出的不同方法。如果您要让输出跟随输入,那么您应该使用事件处理程序,而不是间隔计时器。
  2. 脚本存在时自动禁用实时/自动更新。
    • 尝试启用“LIVE”的第一个代码段并<script>console.log('This is a test');</script>它将重复输出到控制台。
  3. var detectScriptRegExp = /<script/ig;
    document.getElementById("input").addEventListener('input',function(){
        var autoCheckboxEl = document.getElementById("automatic");
        if (autoCheckboxEl.checked==true){
            editorFunction();
        }else if (autoCheckboxEl.disabled==true){
            detectScriptRegExp.lastIndex=0; //clear the RegExp
            if(!detectScriptRegExp.test(document.getElementById("input").value)){
                //Don't lock out LIVE if there is no <script>
                autoCheckboxEl.disabled=false;
            }
        }
    }, false);
    
    function editorFunction(){
        var autoCheckboxEl = document.getElementById("automatic");
        autoCheckboxEl.disabled = false;
        var x = document.getElementById("input").value;
        var outputEl = document.getElementById("output");
        outputEl.innerHTML = x;
        //Get a NodeList of the <script> elements
        var scripts = outputEl.querySelectorAll('script');
        for(var i=0;i<scripts.length;i++){
            var oldScript = scripts[i];
            var newScript = document.createElement('script');
            //Copy the actual script
            newScript.textContent = oldScript.textContent;
            //Copy the oldScripts attributes
            var attrs = oldScript.attributes;
            for(var j=0;j<attrs.length;j++){
                newScript.setAttribute(attrs[j],oldScript.getAttribute(attrs[j]));
            }
            //Replace the non-functional oldScript with the newScript
            oldScript.parentNode.replaceChild(newScript,oldScript);
            //Disable auto/live updates when there are scripts.
            //  This is needed, at least in a snippet. If you use console.log()
            //  the checkbox will rapidly be covered.
            autoCheckboxEl.checked = false;
            autoCheckboxEl.disabled = true;
        }
    }
    <body id="body">
    <section class="container">
        <div class="row">
            <div class="col-sm-6">
                <textarea class="col-sm-12" id="input"></textarea>
            </div>
            <div class="col-sm-6">
                <div class="col-sm-12" id="output"></div>
            </div>
        </div>
    </section>
    <section>
        <div class="row">
            <div class="col-sm-3"></div>
            <div class="col-sm-6">
                <button onclick="editorFunction()">RUN</button>
                <input type="checkbox" id="automatic" checked>Submit the changes LIVE</input>
            </div>
        </div>
    </section>
    <!-- Extra lines so we can scroll the snippet in case console output covers controls-->
    <br/><br/><br/><br/><br/><br/><br/><br/><br/><br/>
    </body>