SvelteKit带iframe的JS在线编辑器脚本执行问题咨询
HTML/CSS/JS在线编辑器自定义脚本无法执行问题的解决
问题背景
开发支持用户编写自定义脚本的HTML/CSS/JS在线编辑器时,在iframe中通过writeln写入<script>标签先是报错,修改后无报错但脚本完全不执行,怀疑是SvelteKit安全配置限制了脚本运行。
当前使用的SvelteKit代码:
<script lang="ts"> import { onMount } from "svelte"; import { testjson } from "$src/stores/store1"; onMount(async () => { const getEl = id => document.getElementById(id) const iFrame = getEl('iFrame').contentWindow.document const htmlTextArea = getEl('htmlTextarea') const cssTextArea = getEl('cssTextarea') const jsTextArea = getEl('jsTextarea') document.body.onkeyup = function() { iFrame.open() iFrame.writeln( htmlTextArea.value + '<style>' + cssTextArea.value + '</style>' + '<script>' + jsTextArea.value + '</script>' ) iFrame.close() } }) </script>
对应HTML结构:
<body> <div class="container"> <h3>HTML/CSS/JS Playground</h3> <div class="row"> <div class="col-12"> <ul id="myTab" class="nav nav-tabs"> <li class="active"><a href="#html" data-toggle="tab"> HTML</a></li> <li><a href="#css" data-toggle="tab">CSS</a></li> <li><a href="#js" data-toggle="tab">JS</a></li> </ul> <div id="myTabContent" class="tab-content"> <div class="tab-pane fade in active" id="html"> <p> <textarea style="float:left" id="htmlTextarea"></textarea> </p> </div> <div class="tab-pane fade" id="css"> <p> <textarea style="float:left" id="cssTextarea"></textarea> </p> </div> <div class="tab-pane fade" id="js"> <p> <textarea style="float:left" id="jsTextarea"></textarea> </p> </div> </div> </div> <div class="col-12"> <div> <iframe id="iFrame"></iframe> </div> </div> </div> </div> </body>
解决步骤
1. 修复iframe脚本注入写法
直接用writeln写入<script>标签可能触发浏览器解析截断(比如</script>被提前识别为闭合标签),改用创建脚本元素的方式注入:
document.body.onkeyup = function() { const iframeWin = getEl('iFrame').contentWindow; const iframeDoc = iframeWin.document; // 清空并写入HTML和CSS iframeDoc.open(); iframeDoc.write(`${htmlTextArea.value}<style>${cssTextArea.value}</style>`); iframeDoc.close(); // 单独创建脚本元素注入JS代码 const scriptEl = iframeDoc.createElement('script'); scriptEl.textContent = jsTextArea.value; iframeDoc.body.appendChild(scriptEl); }
2. 调整SvelteKit的CSP安全策略
SvelteKit默认的内容安全策略(CSP)会限制内联脚本执行,需要修改配置允许用户自定义脚本:
方法一:通过布局文件设置CSP头
在src/routes/+layout.server.ts中添加CSP配置:
export function handle({ event, resolve }) { return resolve(event, { headers: { 'Content-Security-Policy': ` default-src 'self'; frame-src 'self' data:; script-src 'self' 'unsafe-inline' 'unsafe-eval'; style-src 'self' 'unsafe-inline'; `.replace(/\n/g, '') } }); }
方法二:修改svelte.config.js配置
如果使用Node.js等适配器,可直接在配置文件中设置CSP:
import adapter from '@sveltejs/adapter-node'; /** @type {import('@sveltejs/kit').Config} */ const config = { kit: { adapter: adapter(), csp: { mode: 'auto', directives: { 'default-src': ['self'], 'frame-src': ['self', 'data:'], 'script-src': ['self', 'unsafe-inline', 'unsafe-eval'], 'style-src': ['self', 'unsafe-inline'] } } } }; export default config;
3. 检查iframe沙箱属性
如果iframe设置了sandbox属性,必须包含allow-scripts值才能允许脚本执行:
<iframe id="iFrame" sandbox="allow-scripts allow-same-origin"></iframe>
注:allow-same-origin用于让iframe访问同域资源,可根据需求选择是否添加。
验证方式
在JS文本框输入测试代码(如document.body.style.background='red'或console.log('测试脚本执行')),触发keyup事件后查看iframe效果,同时检查浏览器控制台是否有报错。
内容的提问来源于stack exchange,提问作者Bitdom8
相关产品推荐
相关产品推荐

