Reputation: 1
I am currently using quasar v2(vuejs3) and the gold-layout 2.5.0 version.
(I also tried vue-golden-layout, but I gave up because it was difficult to use in quasar v2)
project structure
components
- TestCom.vue : simple component with only div and h2
- WebEditor.vue : part where the monaco editor is defined, and it works normally when the golden layout is not used.
layouts
- GoldenLayout.vue : The page where I want to use the Golden-layout package.
App.vue
I imported other components in Golden Layout.vue and registered in Golden-layout. There is no error message when running, but the contents of the components are not visible.
Is there a right way to register the component in Golden layout?
layouts/GoldenLayout.vue
<template>
<div>
<link type="text/css" rel="stylesheet" href="//golden-layout.com/assets/css/goldenlayout-base.css" />
<link type="text/css" rel="stylesheet" href="//golden-layout.com/assets/css/goldenlayout-light-theme.css" />
<div ref ="test"></div>
</div>
</template>
<script>
import {shallowRef , ref, onMounted, onUnmounted, h } from "vue";
import { GoldenLayout } from "golden-layout/src/index";
import WebEditor from "components/WebEditor.vue";
import TestCom from "components/TestCom.vue"
export default {
name: 'App',
components: {
},
setup(props) {
let c = () => h(WebEditor, {
code : "import java.util.*;\nimport java.io.*;\n\npublic class Main{\n public static void main(String[] args) throws IOException {\n BufferedReader re = new BufferedReader(new InputStreamReader(System.in));\n \n int a = Integer.parseInt(re.readLine());\n int b = Integer.parseInt(re.readLine());\n\n System.out.println(a+b);\n re.close();\n }\n}",
language : "java",
readonly : false
});
let d = () => h(TestCom);
const test = ref(undefined);
let goldenLayout;
const config = {
content:
[
{
type: 'row',
content:
[
{
type: 'component',
componentName: 'WebEditor',
componentType : 'WebEditor'
},
{
type: 'component',
componentName: 'TestCom',
componentType : 'TestCom'
}
]
}
]
}
onMounted(() => {
goldenLayout = new GoldenLayout(test);
goldenLayout.registerComponent('WebEditor', c);
goldenLayout.registerComponent('TestCom', d);
goldenLayout.init();
goldenLayout.loadLayout(config);
});
onUnmounted(() => {
goldenLayout.destroy();
});
return {
test
};
}
};
</script>
<style scoped>
</style>
components/TestCom.vue
<template>
<div>
<h2 style="height:200px">Test</h2>
</div>
</template>
<script>
export default {
setup () {
return {}
}
}
</script>
<style lang="scss" scoped>
</style>
componets/WebEditor.vue
<template>
<div>
<div ref="editorDiv" style="height: 100%; width:100%"></div>
<div><h2 @click="updateEditor">refresh</h2></div>
</div>
</template>
<script>
// package.json
// "monaco-editor": "^0.33.0",
// "monaco-editor-webpack-plugin": "^7.0.1",
// quasar.confg
// const MonacoWebpackPlugin = require('monaco-editor-webpack-plugin');
// module.exports = configure(function (/* ctx */) {
// return {
// plugins: [new MonacoWebpackPlugin()],
import { ref, onMounted } from "vue";
import * as monaco from 'monaco-editor';
export default {
// example
//
// <web-editor code="import java.util.*" language="java" :readOnly="false"></web-editor>
name : 'WebEditor',
props :{
code : String, // "import java.util.*;\nimport java.io.*;\n\npublic class Main{\n public static void main(String[] args) throws IOException {\n BufferedReader re = new BufferedReader(new InputStreamReader(System.in));\n \n int a = Integer.parseInt(re.readLine());\n int b = Integer.parseInt(re.readLine());\n\n System.out.println(a+b);\n re.close();\n }\n}"
language : String, // "java", "c", "python"
readOnly : Boolean, // "false"
},
setup (props) {
const editorDiv = ref(undefined);
let monacoEditor;
let editorCode = JSON.parse(JSON.stringify(props.code));
let editorLanguage = JSON.parse(JSON.stringify(props.language));
let editorReadOnly = JSON.parse(JSON.stringify(props.readOnly));
onMounted(() => {
monacoEditor = monaco.editor.create(editorDiv.value,{
// model: null,
readOnly: editorReadOnly,
value: editorCode,
language: editorLanguage,
// theme: 'vs', //light version
theme: 'vs-dark',
tabSize: 2,
fontFamily: "Consolas",
// fontFamily: 'D2Coding',
// fontFamily: 'IBM Plex Mono',
fontSize: 12,
});
});
const updateEditor = () => {
editorCode = monacoEditor.getValue();
monacoEditor.dispose();
monacoEditor = monaco.editor.create(editorDiv.value,{
// model: null,
readOnly: editorReadOnly,
value: editorCode,
// c,cpp,java,javascript,python
language: editorLanguage,
// theme: 'vs', //light version
theme: 'vs-dark',
tabSize: 2,
fontFamily: "Consolas",
fontSize: 12,
});
};
return {
editorDiv,
monacoEditor,
editorCode,
editorLanguage,
editorReadOnly,
updateEditor
};
}
}
</script>
<style lang="scss" scoped>
</style>
This is my first time asking a question in stackoverflow. If you feel that I made a mistake or lack explanation for the problem, please let me know right away.
Upvotes: 0
Views: 620
Reputation: 973
Unfortunately, the official documentation points to this code, which uses "Golden Layout’s virtual component (virtual via events binding)", but I wasn't able to understand it correctly.
To solve this myself, I created a GoldenLayoutVue.vue
component that takes care of the lifecycle of GoldenLayout
s:
It's not the recommended solution, so it's a hack and it might funny with persistent state (although as far as I can tell, it works fine).
<template>
<div ref="goldenLayoutEl" style="width: 100%; height: 100%"></div>
</template>
<script setup lang="ts">
import { onMounted, onUnmounted, ref, useSlots } from 'vue'
import { GoldenLayout, LayoutConfig } from 'golden-layout'
import 'golden-layout/dist/css/goldenlayout-base.css'
import 'golden-layout/dist/css/themes/goldenlayout-light-theme.css'
import { createVNode, render } from 'vue'
// Vue 2 can mount through a built-in function, but since Vue 3,
// that has been removed. I used the 'mount' function from here:
// https://github.com/pearofducks/mount-vue-component/blob/master/index.js
export function vueMount(component, { props, children, element, app } = {}) {
let el = element
let vNode = createVNode(component, props, children)
if (app && app._context) vNode.appContext = app._context
if (el) render(vNode, el)
else if (typeof document !== 'undefined' ) render(vNode, el = document.createElement('div'))
const destroy = () => {
if (el) render(null, el)
el = null
vNode = null
}
return { vNode, destroy, el }
}
const { layoutConfig } = defineProps<{
layoutConfig: LayoutConfig
}>()
const slots = useSlots()
let goldenLayoutEl = ref<null>(null)
let goldenLayout: GoldenLayout | null = null
let destroyArr: (() => void)[] = []
onMounted(async () => {
if (!goldenLayoutEl.value) throw new Error('goldenLayoutEl not truthy')
goldenLayout = new GoldenLayout(goldenLayoutEl.value)
// iterate over all the slots, and mount the component to the
// DOM element that GoldenLayout automatically creates for us
for (const [name, component] of Object.entries(slots)) {
goldenLayout.registerComponentFactoryFunction(name, (container, state) => {
const { vNode, destroy, el } = vueMount(component, {
element: container.element,
})
destroyArr.push(destroy)
})
}
goldenLayout.loadLayout(layoutConfig)
})
onUnmounted(() => {
for (const fn of destroyArr) {
fn()
}
})
// Resize
const _onResize = () => {
if (goldenLayoutEl.value && goldenLayout) {
const rect = goldenLayoutEl.value.getBoundingClientRect()
goldenLayout.setSize(rect.width, rect.height)
}
}
onMounted(() => {
_onResize()
window.addEventListener('resize', _onResize)
})
onUnmounted(() => {
window.removeEventListener('resize', _onResize)
})
</script>
Use the component like so:
<template>
<GoldenLayoutVue :layoutConfig="goldenLayoutConfig">
<template #ComponentA>
<h1>Left</h1>
</template>
<template #ComponentB>
<h1>Right</h1>
</template>
</GoldenLayoutVue>
</template>
<script setup>
import GoldenLayoutVue from './GoldenLayoutVue.vue'
const goldenLayoutConfig = {
root: {
type: 'row',
content: [
{
title: 'My Component 1',
type: 'component',
componentType: 'ComponentA',
componentState: { text: 'Component 1' },
size: '50%',
},
{
title: 'My Component 2',
type: 'component',
componentType: 'ComponentB',
componentState: { text: 'Component 2' },
},
],
},
}
</script>
Notice how both the slot name (<template #ComponentA>
) and the property in the layoutConfig (componentType: 'ComponentA'
) match exactly.
Upvotes: 0