thymeleaf에서 fragment로 vue 컴포넌트 만들기
회원 정보 화면에서 하위에 여러개의 상세 탭을 두고 공통 정보를 컴포넌트화 하려고 했다.
지금 가진 구조에서 최대한 구조를 바꾸지 않고, 간단하게 fragment로 컴포넌트를 만들었다.
이전에도 이런 상황에 있었을때 구조를 바꾸지 않고 해결하는 방법을 모색하다 해결하지 못하고 지나갔었는데, 이번엔 간단한 방법으로 해결했다!
condition
- 각각의 페이지는 싱글 Vue로 선언되어있음.
- 공통 요소는 각각의 페이지에서 각자 API를 호출하고 있었음(새로운 항목이 추가될때마다 1개씩 10번 추가해야하는 상황 발생)
(실패ㅜㅜ) solve1 - fragment로 Vue 로 생성된 인스턴스 안에 새로운 Vue를 생성하기
* 실패입니다. 따라하지마세요 *
다분히 엘리먼트의 이름을 바꿔 생성하면 vue 인스턴스 안에 또 다른 인스턴스를 생성하여 독립적으로 vue가 생성될거란 생각.. 이것은 아주 실패다..
- fragment의 변수들이 undefined로 나오는 현상
- 새로운 변수가 템플릿에 렌더링 되지 않음
- 값이 변경되었을때 값이 업데이트 되지 않음
gpt의 조언
- $forceUpdate()를 사용해보세요! -> 실패..
- this.$set(... 를 사용해보세요! -> 실패..
이 방법은 어떻게 해서 해결한다고 해도 좋은 방법이 아닌 것 같아 다른 방법을 찾기로 했다.
가능하다고 하더라도 다른 사람들도 쉽게 사용하고, 변경할 수 있도록 해야하는데, 이 방법은 좋은 방법이 되지 못할 것 같았다.
vue 안의 vue가 문제라면, vue로 선언하지 않고, 순수 자바스크립트로 API 통신을 하는 방법
또한 실패.. axios 통신 부분할때 UID를 가져와야하는 부분이 있는데, 이부분에서부터 막혀버렸다.
생각보다 쉽지않았다 ㅠㅠㅠㅠ
일단, 접근 방식 자체가 잘못된 것 같아서 차분히 다시 생각을 해봤다.
새로운 객체로 선언해서 정상적으로 렌더링이 안된다면, fragment를 선언한 기저의 vue를 확장하여 사용하는 방식으로 해보자!
해서 생각한게 Vue.component() 방식이다. fragment 개념이 일련의 스크립트를 삽입하는 방식이라고 생각했을떄
최초 선언한 Vue를 확장하는 방식이 용이하겠다는 생각이 들었다.
fragment를 Vue의 컴포넌트로 확장하여 생성하기
vue에서 컴포넌트를 선언할때, Vue.component() 방식을 사용하여 선언하면,
- vue 자체의 기능을 온전히 사용 가능함.
- 기존의 vue를 확장하기 때문에 파라미터를 전달받기에 용이함
- 렌더링될때 최초의 vue와 동일한 뎁스에서 생성됨
올바른 방식이 아닐 수도 있긴 하지만, 일단 해보기로 했다!
base html
-- template
<div id="app" class="contents">
<h2 class="indent">회원정보</h2>
<div th:include="${파일경로} :: ${fragment이름}(param1=${param1}, param2=${param2})"></div>
-- script
var app = new Vue({
el: '#app',
기저에서 Vue 를 가지고 element를 잡아 vue 인스턴스를 생성한다.
그리고 그 내부에 th:include로 fragment를 삽입한다.
fragment에 파라미터를 위와 같은 형식으로 전달할 수 있다.
전달할 파라미터가 없다면
<div th:include="${파일경로} :: ${fragment이름}"></div>
fragment html
fragment에서는 fragment이름이 선언된 범위내의 소스를 가져오기 때문에,
<body th:fragment="${fragment이름}">
<cge-component></cge-component>
<script th:inline="javascript" type="text/javascript">
...
</script>
스크립트태그와 vue 태그를 모두 감싸야줘야해서 body 태그에 fragment 명을 붙여주었다.
그리고 스크립트 태그 안에서 Vue의 컴포넌트를 동적으로 생성한다.
Vue.component('cge-component', {
template : `<div>
{{ cge }}
------------- html ----------
</div>`,
data(){
return {
cge:'data data !'
}
}
methods : {
func1(){
console.log('111);
}
},
mounted(){
this.func1();
}
}
vue 컴포넌트는 동일하게 하위에 데이터 선언부, 메소드 선언부를 기존의 방식과 동일하게 작성하면 된다.
결과적으로 이런 구조로 렌더링이 된다!
정상적으로 파라미터를 전달 받을 수 있고, 정상적으로 vue를 확장하여 컴포넌트를 선언하여 사용할 수 있었다.
fragment의 개념만 잘 알면 어렵지 않은 문제였는데, fragment, vue, html, js 를 다 섞어서 기능을 사용하려고보니 여러가지로 복잡해진 것 같다.
오히려 이럴 수록 심플하게 생각하는게 올바른 방법인것 같다. 지금은 이렇게 작성했지만, 다음번엔 또 다르게 작성해보면 좋을 것 같다.