그림판 같은 툴에서 요소를 화면에 동적으로 생성하는 기능이 필요한데 외부 라이브러리를 쓰는 AgGrid인 경우
vue의 컴포넌트로 등록되어 있어서 일반 요소와 다른 생성 로직이 필요했습니다.
1. 라이브러리 파일
//AgGrid.vue
<template>
<div style="height: 100%; width: 100%">
<div class="example-wrapper">
<div class="example-header" style="background: #ffdddd">Rows in this example do not move, only events are fired</div>
<ag-grid-vue
class="ag-theme-alpine"
style="height: 500px"
:column-defs="columnDefs"
:row-data="rowData"
:default-col-def="defaultColDef"
row-selection="multiple"
:animate-rows="true"
:row-drag-managed="true"
:enable-cell-change-flash="true"
@cell-clicked="onCellWasClicked"
@cell-changed="onCellWasChanged"
@cell-double-clicked="onCellWasDoubleClicked"
@cell-context-menu="onCellWasContextMenu"
@grid-ready="onGridReady"
@row-drag-enter="onRowDragEnter"
@row-drag-end="onRowDragEnd"
@row-drag-move="onRowDragMove"
@row-drag-leave="onRowDragLeave"
>
</ag-grid-vue>
</div>
</div>
</template>
<!-- animate-rows=true >> Moving Columns, Filtering Rows , Sorting Rows, Expanding , Collapsing Row Groups-->
<script>
import 'ag-grid-community/styles/ag-grid.css';
import 'ag-grid-community/styles/ag-theme-alpine.css';
import { AgGridVue } from 'ag-grid-vue3';
//import { reactive, onMounted, ref } from 'vue';
export default {
name: 'AgGrid',
components: {
AgGridVue
},
data: function () {
return {
columnDefs: [
{ field: 'athlete', rowDrag: true },
{ field: 'country' },
{ field: 'year', width: 100 },
{ field: 'date' },
{ field: 'sport' },
{ field: 'gold' },
{ field: 'silver' },
{ field: 'bronze' }
],
gridApi: null,
columnApi: null,
defaultColDef: {
width: 170,
sortable: true,
filter: true,
flex: 1,
minWidth: 100,
resizable: true
},
rowData: null
/*
cellWasClicked: event => {
// Example of consuming Grid Event
console.log('cell was clicked', event);
},
cellWasChanged: event => {
console.log('onCellWasChanged', event);
},
cellWasDoubleClicked: event => {
console.log('cellWasDoubleClicked', event);
},
cellWasContextMenu: event => {
console.log('cellWasContextMenu', event);
},
deselectRows: () => {
gridApi.value.deselectAll();
}
*/
};
},
created() {},
methods: {
onGridReady(params) {
this.gridApi = params.api;
this.gridColumnApi = params.columnApi;
let locale = this.$i18n.locale;
for (let i = 0; i < this.columnDefs.length; i++) {
let field = this.columnDefs[i]['field'];
let headerName = this.$i18n.t(field);
this.columnDefs[i]['headerName'] = headerName;
}
const updateData = data => params.api.setRowData(data);
fetch('https://www.ag-grid.com/example-assets/olympic-winners.json')
.then(resp => resp.json())
.then(data => updateData(data));
},
onCellWasClicked(e) {
// Example of consuming Grid Event
console.log('onCellWasClicked', e);
},
onCellWasChanged(e) {
console.log('onCellWasChanged', e);
},
onCellWasDoubleClicked(e) {
console.log('onCellWasDoubleClicked', e);
},
onCellWasContextMenu(e) {
console.log('onCellWasContextMenu', e);
},
deselectRows: () => {
gridApi.value.deselectAll();
},
onRowDragEnter(e) {
console.log('onRowDragEnter', e);
},
onRowDragEnd(e) {
console.log('onRowDragEnd', e);
},
onRowDragMove(e) {
console.log('onRowDragMove', e);
},
onRowDragLeave(e) {
console.log('onRowDragLeave', e);
}
}
};
</script>
<!--
<style scoped>
@import '@css/ag-grid/ag-grid.css';
@import '@css/ag-grid/ag-theme-alpine.css';
</style>
-->
<style lang="scss"></style>
2. agGrid를 여러군데서 커스텀해서 사용하기 위해 따로 sample파일을 만든 것 같습니다.
//AgGridSample.vue
<template>
<div>
<ul class="aggridsample">
<li style="height: 100px; width: 500px"><AgGrid></AgGrid></li>
</ul>
</div>
</template>
<script>
import AgGrid from '@/components/lib/aggrid/AgGrid.vue';
export default {
name: 'AgGridSample',
components: {
AgGrid
}
};
</script>
3. 컴포넌트를 사용하는 화면
v-for문을 사용하여 data()함수 안의 agGrids만큼 컴포넌트를 생성합니다.
//Editor.vue
<template>
<div id="center-board">
<div class="rulers">
<div class="rulersTop"></div>
<div style="display: flex; flex-direction: row">
<div class="rulersRight"></div>
<div id="workspace" @keydown="mainKeyDown($event)" @keyup="mainKeyUp($event)">
<div
id="htmleditormain"
class="editor"
tabindex="0"
@mousemove.prevent="mainMouseMove($event)"
@mouseup.prevent="mainMouseUp($event)"
@mousedown.prevent="mainMouseDown($event)"
@drop.prevent="dragDrop($event)"
@dragenter.prevent
@dragover.prevent
>
<div v-for="agGrid in agGrids" :id="agGrid.id" :key="agGrid.id">
<AgGridSample></AgGridSample>
</div>
</div>
</div>
</div>
</div>
<!-- Board -->
<div class=""></div>
</div>
</template>
<script>
import AgGridSample from '@/components/menu/AgGridSample.vue';
export default {
name: 'HTMLEditor',
props: {
command: {
type: Object,
default: null,
required: false
}
},
components: {
AgGridSample
},
data: {
return {
agGrids: [],
}
},
methods: {
async createElement (
name,
type,
top,
left) {
if (type === 'agGrid') {
let elemId = this.agGrids.length + 1;
const newAgGrid = { id: elemId };
this.agGrids.push(newAgGrid);
}
}
}
}
* 실패한 코드
1. defineCompoent 사용
Vue3의 defineCompoent를 이용해 컴포넌트를 동적으로 등록합니다.
mount하기 위해서 app전체를 다시 mount해야해서 실패.
//실패한 코드
async function init() {
const AgGridSample = await import('./AgGridSample.vue');
const AgGridComponent = Vue.defineComponent({
components: { AgGridSample },
mounted() {
const agGridInstance = this.$refs.newId.$el;
this.$refs.agGridContainer.appendChild(agGridInstance);
},
template: '<AgGridSample ref="' + newId + '"></AgGridSample>'
});
//const app = Vue.createApp(AgGridComponent);
//const mountedApp = app.mount('#app');
const agGridInstance = new AgGridComponent();
agGridInstance.$mount();
this.$refs.agGridContainer.appendChild(agGridInstance.$el);
}
init();
2. defineAsyncCoponent 사용
Vue 3에서는 defineAsyncComponent 함수를 사용하여 비동기적으로 컴포넌트를 등록할 수 있습니다. 이 함수는 Promise를 반환하며, 비동기적으로 로딩된 컴포넌트를 렌더링합니다.
setup함수 실행 시점에서 vue의 import가 완료되지 않아서 실패.
//실패한 코드2
<template>
<div>
<button @click="loadAgGridComponent">Load AgGrid Component</button>
<component :is="component"></component>
</div>
</template>
<script>
import { defineAsyncComponent, ref } from 'vue';
export default {
name: 'HTMLEditor',
setup() {
const component = ref(null);
const loadAgGridComponent = async () => {
const AgGridComponent = await defineAsyncComponent(() => import('./AgGridSample.vue'));
component.value = AgGridComponent;
};
return {
component,
loadAgGridComponent
};
}
};
</script>
위 코드에서는 defineAsyncComponent 함수를 사용하여 AgGridSample.vue 파일을 비동기적으로 로딩합니다. loadAgGridComponent 메소드에서 이 함수를 사용하여 컴포넌트를 로딩하고, 이후 component 변수에 할당합니다. 마지막으로 component 변수를 <component> 태그의 is 속성에 바인딩하여 동적으로 컴포넌트를 렌더링합니다.
* :is는 동적 컴포넌트를 생성하기 위해 사용되는 속성입니다. 이 속성을 사용하면 런타임에 컴포넌트를 변경할 수 있습니다.
예를 들어, component 변수에 MyComponent라는 컴포넌트를 할당했다면 :is="component"는 MyComponent 컴포넌트를 렌더링합니다.
:is 속성 대신 다른 이름을 사용하려면 해당 속성을 props로 전달해야 합니다. 예를 들어, <MyComponent /> 대신 <DynamicComponent component="MyComponent" />와 같이 사용할 수 있습니다. 이 경우, DynamicComponent 컴포넌트는 component prop을 받아들이고, 해당 prop을 사용하여 동적으로 컴포넌트를 렌더링할 수 있습니다.
'Frontend > vue3' 카테고리의 다른 글
[Vue] 다른 컴포넌트에서 발생한 이벤트 수신 방법 (AgGrid api) (0) | 2023.04.03 |
---|---|
[Vue3] TypeError: Cannot read property 'insertBefore' of null (1) | 2023.03.31 |
AngularJS -> VueJS 변환 ($scope에 대하여) (0) | 2023.03.08 |
[Vue.js] 모듈화 (0) | 2023.03.08 |
[Vue.js] 경로를 나타내는 기호 (0) | 2023.03.08 |