139 lines
3.1 KiB
Vue
139 lines
3.1 KiB
Vue
<template>
|
|
<Topbar />
|
|
<div class="playground">
|
|
<wc-tabs class="editor">
|
|
<wc-tab label="html" name="html">
|
|
<CodeEditor lang="html" :code="html" @change="updateCode" />
|
|
</wc-tab>
|
|
<wc-tab label="javascript" name="js">
|
|
<CodeEditor lang="js" :code="js" @change="updateCode" />
|
|
</wc-tab>
|
|
<wc-tab label="css" name="css">
|
|
<CodeEditor lang="css" :code="css" @change="updateCode" />
|
|
</wc-tab>
|
|
</wc-tabs>
|
|
<Preview :code="preview" />
|
|
</div>
|
|
</template>
|
|
|
|
<script>
|
|
import CodeEditor from '@/components/code-editor.vue'
|
|
import Topbar from './views/topbar.vue'
|
|
import Preview from './views/preview.vue'
|
|
|
|
import { gzip, ungzip } from '@bytedo/gzip'
|
|
|
|
const template = `<!doctype html>
|
|
<html lang="zh-CN">
|
|
<head>
|
|
<meta charset="utf-8">
|
|
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
|
|
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, minimum-scale=1, user-scalable=no">
|
|
<link rel="stylesheet" href="//jscdn.ink/@bd/ui/latest/css/reset-basic.css">
|
|
{{css}}
|
|
<script async src="//jscdn.ink/es-module-shims/1.6.3/es-module-shims.wasm.js"><\/script>
|
|
<script type="importmap">${JSON.stringify({
|
|
imports: {
|
|
vue: '//jscdn.ink/vue/3.2.47/vue.runtime.esm-browser.prod.js',
|
|
'vue-router': '//jscdn.ink/@bytedo/vue-router/4.1.6/vue-router.js',
|
|
fetch: '//jscdn.ink/@bytedo/fetch/latest/next.js',
|
|
'@bytedo/editor': '//jscdn.ink/@bytedo/editor/latest/index.js',
|
|
'@bytedo/gzip': '//jscdn.ink/@bytedo/gzip/latest/index.js',
|
|
'@bd/core': '//jscdn.ink/@bd/core/latest/index.js'
|
|
}
|
|
})}<\/script>
|
|
<script type="module">
|
|
{{js}}
|
|
<\/script>
|
|
</head>
|
|
<body>
|
|
{{html}}
|
|
<\/body>
|
|
<\/html>
|
|
`
|
|
|
|
export default {
|
|
components: { Topbar, CodeEditor, Preview },
|
|
data() {
|
|
return {
|
|
html: '',
|
|
js: '',
|
|
css: '',
|
|
preview: ''
|
|
}
|
|
},
|
|
|
|
mounted() {
|
|
//
|
|
this.$needUpdate = true
|
|
|
|
window.addEventListener('hashchange', ev => {
|
|
this.handleHashChange()
|
|
})
|
|
this.handleHashChange()
|
|
},
|
|
|
|
methods: {
|
|
handleHashChange() {
|
|
if (this.$needUpdate) {
|
|
let code = location.hash.slice(1)
|
|
if (code) {
|
|
try {
|
|
code = ungzip(code)
|
|
code = JSON.parse(code)
|
|
} catch (e) {}
|
|
}
|
|
|
|
this.html = code.html
|
|
this.js = code.js
|
|
this.css = code.css
|
|
this.updatePreview()
|
|
}
|
|
this.$needUpdate = true
|
|
},
|
|
|
|
updateCode(code, lang) {
|
|
this[lang] = code
|
|
this.updatePreview(true)
|
|
},
|
|
updatePreview(sync) {
|
|
let { html, js, css } = this
|
|
|
|
if (sync) {
|
|
let code = gzip(JSON.stringify({ html, js, css }))
|
|
this.$needUpdate = false
|
|
location.hash = code
|
|
}
|
|
|
|
this.preview = template
|
|
.replace('{{css}}', css)
|
|
.replace('{{html}}', html)
|
|
.replace('{{js}}', js)
|
|
}
|
|
}
|
|
}
|
|
</script>
|
|
|
|
<style lang="scss">
|
|
body {
|
|
line-height: 1.5;
|
|
font-size: 14px;
|
|
}
|
|
#app {
|
|
display: flex;
|
|
flex-direction: column;
|
|
height: 100vh;
|
|
color: var(--color-dark-1);
|
|
}
|
|
|
|
.playground {
|
|
overflow: hidden;
|
|
flex: 1;
|
|
display: flex;
|
|
}
|
|
|
|
.editor {
|
|
width: 50%;
|
|
}
|
|
</style>
|