fix preview
This commit is contained in:
@@ -42,18 +42,19 @@
|
|||||||
</n-flex>
|
</n-flex>
|
||||||
</n-flex>
|
</n-flex>
|
||||||
<div class="iframe-wrapper" :style="iframeWrapperStyle">
|
<div class="iframe-wrapper" :style="iframeWrapperStyle">
|
||||||
<iframe class="iframe" ref="iframe"></iframe>
|
<iframe class="iframe" :srcdoc="previewContent"></iframe>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { watchDebounced } from "@vueuse/core"
|
import { watchDebounced } from "@vueuse/core"
|
||||||
import { computed, onMounted, useTemplateRef, ref } from "vue"
|
import { computed, onMounted, ref } from "vue"
|
||||||
import { useRouter } from "vue-router"
|
import { useRouter } from "vue-router"
|
||||||
import { Submission } from "../../api"
|
import { Submission } from "../../api"
|
||||||
import { submission } from "../../store/submission"
|
import { submission } from "../../store/submission"
|
||||||
import { useMessage } from "naive-ui"
|
import { useMessage } from "naive-ui"
|
||||||
import { Icon } from "@iconify/vue"
|
import { Icon } from "@iconify/vue"
|
||||||
import copy from "copy-text-to-clipboard"
|
import copy from "copy-text-to-clipboard"
|
||||||
|
import { buildPreviewDocument } from "../../utils/previewDocument"
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
html: string
|
html: string
|
||||||
@@ -91,7 +92,9 @@ const layoutConfig: Record<
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
const layoutIndex = ref(0)
|
const layoutIndex = ref(0)
|
||||||
const layoutIcon = computed(() => layoutConfig[layouts[layoutIndex.value]!].icon)
|
const layoutIcon = computed(
|
||||||
|
() => layoutConfig[layouts[layoutIndex.value]!].icon,
|
||||||
|
)
|
||||||
const layoutLabel = computed(
|
const layoutLabel = computed(
|
||||||
() => layoutConfig[layouts[layoutIndex.value]!].label,
|
() => layoutConfig[layouts[layoutIndex.value]!].label,
|
||||||
)
|
)
|
||||||
@@ -105,35 +108,20 @@ function cycleLayout() {
|
|||||||
const message = useMessage()
|
const message = useMessage()
|
||||||
const router = useRouter()
|
const router = useRouter()
|
||||||
|
|
||||||
const iframe = useTemplateRef<HTMLIFrameElement>("iframe")
|
|
||||||
const showDL = computed(() => props.html || props.css || props.js)
|
const showDL = computed(() => props.html || props.css || props.js)
|
||||||
|
const previewContent = ref("")
|
||||||
|
|
||||||
function getContent() {
|
function getContent() {
|
||||||
return `<!DOCTYPE html>
|
return buildPreviewDocument({
|
||||||
<html lang="zh-Hans-CN">
|
html: props.html,
|
||||||
<head>
|
css: props.css,
|
||||||
<meta charset="UTF-8" />
|
js: props.js,
|
||||||
<title>预览</title>
|
assetBaseUrl: props.assetBaseUrl,
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
})
|
||||||
${props.assetBaseUrl ? `<base href="${props.assetBaseUrl}">` : ""}
|
|
||||||
<style>${props.css}</style>
|
|
||||||
<link rel="stylesheet" href="/normalize.min.css" />
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
${props.html}
|
|
||||||
<script>${props.js}<\/script>
|
|
||||||
</body>
|
|
||||||
</html>`
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function preview() {
|
function preview() {
|
||||||
if (!iframe.value) return
|
previewContent.value = getContent()
|
||||||
const doc = iframe.value.contentDocument
|
|
||||||
if (doc) {
|
|
||||||
doc.open()
|
|
||||||
doc.write(getContent())
|
|
||||||
doc.close()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function download() {
|
function download() {
|
||||||
@@ -155,7 +143,7 @@ function open() {
|
|||||||
})
|
})
|
||||||
window.open(data.href, "_blank")
|
window.open(data.href, "_blank")
|
||||||
} else {
|
} else {
|
||||||
const newTab = window.open("/usercontent.html")
|
const newTab = window.open("about:blank", "_blank")
|
||||||
if (!newTab) return
|
if (!newTab) return
|
||||||
newTab.document.open()
|
newTab.document.open()
|
||||||
newTab.document.write(getContent())
|
newTab.document.write(getContent())
|
||||||
@@ -183,10 +171,14 @@ async function updateScore(score: number) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
watchDebounced(() => [props.html, props.css, props.js], preview, {
|
watchDebounced(
|
||||||
debounce: 500,
|
() => [props.html, props.css, props.js, props.assetBaseUrl],
|
||||||
maxWait: 1000,
|
preview,
|
||||||
})
|
{
|
||||||
|
debounce: 500,
|
||||||
|
maxWait: 1000,
|
||||||
|
},
|
||||||
|
)
|
||||||
onMounted(preview)
|
onMounted(preview)
|
||||||
</script>
|
</script>
|
||||||
<style scoped>
|
<style scoped>
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
import { onMounted, useTemplateRef } from "vue"
|
import { onMounted, useTemplateRef } from "vue"
|
||||||
import { Submission } from "../api"
|
import { Submission } from "../api"
|
||||||
import type { SubmissionAll } from "../utils/type"
|
import type { SubmissionAll } from "../utils/type"
|
||||||
|
import { buildPreviewDocument } from "../utils/previewDocument"
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
id: string
|
id: string
|
||||||
@@ -18,20 +19,13 @@ async function init() {
|
|||||||
const doc = iframe.value.contentDocument
|
const doc = iframe.value.contentDocument
|
||||||
if (doc) {
|
if (doc) {
|
||||||
doc.open()
|
doc.open()
|
||||||
doc.write(`<!DOCTYPE html>
|
doc.write(
|
||||||
<html lang="zh-Hans-CN">
|
buildPreviewDocument({
|
||||||
<head>
|
html: submission.html,
|
||||||
<meta charset="UTF-8" />
|
css: submission.css,
|
||||||
<title>预览</title>
|
js: submission.js,
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
}),
|
||||||
<style>${submission.css}</style>
|
)
|
||||||
<link rel="stylesheet" href="/normalize.min.css" />
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
${submission.html}
|
|
||||||
<script>${submission.js}<\/script>
|
|
||||||
</body>
|
|
||||||
</html>`)
|
|
||||||
doc.close()
|
doc.close()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
29
src/utils/previewDocument.ts
Normal file
29
src/utils/previewDocument.ts
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
interface PreviewDocumentOptions {
|
||||||
|
html: string
|
||||||
|
css: string
|
||||||
|
js: string
|
||||||
|
assetBaseUrl?: string
|
||||||
|
}
|
||||||
|
|
||||||
|
export function buildPreviewDocument({
|
||||||
|
html,
|
||||||
|
css,
|
||||||
|
js,
|
||||||
|
assetBaseUrl,
|
||||||
|
}: PreviewDocumentOptions) {
|
||||||
|
return `<!DOCTYPE html>
|
||||||
|
<html lang="zh-Hans-CN">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8" />
|
||||||
|
<title>预览</title>
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
${assetBaseUrl ? `<base href="${assetBaseUrl}">` : ""}
|
||||||
|
<style>${css}</style>
|
||||||
|
<link rel="stylesheet" href="/normalize.min.css" />
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
${html}
|
||||||
|
<script>${js}<\/script>
|
||||||
|
</body>
|
||||||
|
</html>`
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user