vue3-ts
0. overview
vue3 composition api 기초 사용법
잘못된 내용이 있을 가능성 100%
자세하고 정확한 내용은 공식문서 확인
* 2. name을 제외한 샘플코드는 <script setup lang="ts"></script>
에 작성한 내용임
1. script tag
<!-- options api / setup()을 통한 composition api 사용 -->
<script>
</script>
<!-- lang="ts": typescript 사용(컴포넌트 내 script 태그는 모두 lang 값이 같아야함) -->
<script lang="ts">
</script>
<!-- setup: composition api 사용(sfc에서만 사용 가능) -->
<script setup lang="ts">
</script>
2. name
- name 속성은 options api로 설정
<script lang="ts">
export default { name: 'vue3-ts' };
</script>
3. import and use vue functions
import { ref, reactive, computed as com, onMounted as mounted, onUpdated } from 'vue';
const foo = ref('vue3');
// or
import * as vu from 'vue';
const bar = vu.ref('ts');
4. data
4-1. reactive
- object, array, Map, Set등 non-primitive 타입만 가능
- 속성을 destructuring하거나 함수의 파라미터로 전달하면 반응성이 없어짐
import { reactive } from 'vue';
const foo = reactive({
name: 'vue3'
});
const { name } = foo; // 반응형 아님
fun(foo.name);
function fun(name: string): void {
name = 'ts'; // 반응형 아님
}
4-2. ref(사용 추천)
- 모든 타입 가능
- script 에서
.value
로 접근해야함 - template 에서
.value
필요없음 - 속성을 destructuring하거나 함수의 파라미터로 전달해도 반응성이 살아있음
import { ref } from 'vue';
const foo = ref('vue3');
const bar = ref({
name: 'ts'
});
// in script
console.log(foo.value);
console.log(bar.value.name);
// in template
// <p>{{ foo }}</p>
// <p>{{ bar.name }}</p>
const { name } = bar.value; // 반응형
fun(bar.value.name);
function fun(name: string): void {
name = 'js'; // 반응형
}
4-3. with typescript
import { Ref, ref } from 'vue';
const foo: Ref<string> = ref('vue3');
// multi type binding
const foo1: Ref<string | number> = ref('ts'); // string ok
foo1.value = 1; // number ok
// or
const bar = ref<string>('vue3');
// multi type binding
const bar1 = ref<string | number>('ts'); // string ok
bar1.value = 1; // number ok
5. computed
5-1. get only
import { ref, computed } from 'vue';
const foo = ref('vue3');
const bar = computed((): string => {
return foo.value === 'vue3' ? 'composition api' : 'options api';
});
5-2. get, set(사용 비추천)
import { ref, computed } from 'vue';
const foo = ref('vue3');
const bar = computed({
get (): string {
return foo.value === 'vue3' ? 'composition api' : 'options api';
},
set (newValue: string): void {
foo.value = newValue;
}
});
6. watch
import { ref, watch } from 'vue';
const foo = ref('vue3');
watch(foo, (newValue: string): void => {
// your code...
});
// or
watch(foo, (newValue: string, oldValue: string): void => {
// your code...
});
const bar = ref({
name: 'ts'
});
// X
watch(bar.value.name, (newValue: string, oldValue: string): void => {
// your code...
});
// O
watch(() => bar.value.name, (newValue: string, oldValue: string): void => {
// your code...
});
7. refs
- 템플릿의 ref의 속성과 같은 이름의 반응형 변수를 null로 선언한다.
// <input ref="foo"></input>
import { ref, onMounted } from 'vue';
const foo = ref(null);
onMounted(() => {
foo.value.focus();
});
8. props
8-1. basic
- defineProps 사용
- 컴포넌트 내에서 한번만 사용 가능
defineProps(['foo', 'bar']);
// <p>{{ foo }}</p> // in template
// or
const props = defineProps([ 'foo' ]);
// <p>{{ props.foo }}</p> // in template
console.log(props.foo); // in script
// or
const props = defineProps({
foo: {
type: String,
required: true
},
bar: {
type: Number,
default: 1
}
});
8-2. with typescript
const props = defineProps<{
foo: string,
bar?: number
}>();
// or
interface Props {
foo: string;
bar?: number;
}
const props = defineProps<Props>();
// default value
const props = withDefaults(defineProps<Props>(), {
foo: 'foo'
});
9. emits
9-1. basic
- defineEmits 사용
- 컴포넌트 내에서 한번만 사용 가능
defineEmits([ 'foo', 'bar' ]);
// <button @click="$emit('bar')"></button> // in template
// or
const emits = defineEmits([ 'bar' ]);
// <button @click="$emit('bar')"></button> // in template
emits('bar'); // in script
9-2. with typescript
const emits = defineEmits<{
(e: 'foo', id: number): void
(e: 'bar', value: string): void
}>();
10. nextTick
import { nextTick } from 'vue';
function foo() {
nextTick(() => {
// your code
});
}
11. lifecycle hooks
import { onMounted, onUpdated } from 'vue';
onMounted(() => {
console.log('mounted');
});
onUpdated(() => {
console.log('mounted');
});
12. root emelent
- 컴포넌트 template 내 root element를 두개이상 사용할 수 있음
<!-- vue2 no -->
<!-- vue3 ok -->
<template>
<div></div>
<div></div>
</template>
13. VUE SFC coding style
script setup 방식 사용시.
파일 전체를 설명하는 주석 부터, 각 영역을 분리하는 가이드라인 주석
에 대한 예제입니다.가이드라인 주석
외의 주석은 기존 주석 다는 형식으로 진행하면 됩니다.
<!--
!! vue 파일에 대한 설명을 기술합니다. 아래는 샘플입니다.
template-pack 상세 화면
- 상단 template-pack 정보
- 하단 탭뷰
- Template tab
- 좌측 : template 목록 나열 (아코디언)
- 우측 : 선택된 template 상세
- Variable tab
- 변수 그룹 및 그룹내 변수 (아코디언)
-->
<template>
<div class="common-layout">
<el-container>
<el-main>
<el-container>
<el-scrollbar>
<el-main v-if="model" class="detail_main">
<!-- =========================================================================== 상단 template-pack 정보 -->
<el-row>
<el-col :span="24">
<el-row class="q-my-sm">
<el-col :span="12">
<el-button type="primary" @click="handleDeleteTmplPack">삭제</el-button>
</el-col>
<el-col :span="12" style="text-align: right">
<el-button type="primary" @click="handleSave">상태 저장</el-button>
</el-col>
</el-row>
</el-col>
</el-row>
<el-tabs v-model="activeTab">
<!-- =================================================================================== Template tab-->
<el-tab-pane label="Template" name="tmpl">
<el-row class="full-height">
<el-col :span="24">
<div class="row full-height">
<div class="detail_content q-pa-md col-9">
<template-detail :tmpl="currentTemplate" v-if="currentTemplate"></template-detail>
</div>
</div>
</el-col>
</el-row>
</el-tab-pane>
<!-- ================================================================================== Variables tab-->
<el-tab-pane label="Variables" name="variableGroups">
<el-row justify="end">
<el-col :span="12" style="text-align: right">
<el-button type="primary" @click="handleNewVarGroup">변수 그룹 추가</el-button>
</el-col>
</el-row>
</el-tab-pane>
</el-tabs>
</el-main>
</el-scrollbar>
</el-container>
</el-main>
</el-container>
</div>
</template>
<script lang="ts" setup>
import {inject, onMounted, Ref, ref, watch} from 'vue';
// region =================================================================================================== initialize
// ------------------------------------------------------------------------- props
interface Props {
table?: Table,
tmplPack?: TemplatePack,
projectConfig?: ProjectConfig
}
const props = withDefaults(defineProps<Props>(), {});
// ------------------------------------------------------------------------- models
const model: Ref<Table|null> = ref(null); // table 모델
const selected = ref([]); // 선택된 컬럼 목록
// 템플릿
const tmplPack:Ref<TemplatePack|undefined> = ref();
// ------------------------------------------------------------------------- services
const javaService = new JavaService();
// ------------------------------------------------------------------------- lifecycle, event, etc...
// declare PackEvents
// provides from template-pack.vue
const packMitt = inject<Emitter<PackEvents>>('PackEvents');
// declare TmplEvents
const tmplMitt = mitt<TmplEvents>();
provide('TmplEvents', tmplMitt);
tmplMitt.on('tmpl:save', (param:any) => {
packMitt?.emit('pack:update', model.value!);
});
onMounted(async () => {
await init();
});
watch(() => props.table, (val) => {
init();
});
// endregion |end| initialize
// region ====================================================================================================== methods
/**
* 초기화
*/
const init = async () => {
console.log('init!!!!!');
}
/**
* ...
*/
const filterDataType = (column:Column) => {
if(column.decimalDigits === 0) {
return `${column.type}(${column.size})`;
}
return `${column.type}(${column.size}, ${column.decimalDigits})`;
}
// ------------------------------------------------------------------------- event handler
/**
* ...
*/
const handleSave = () => {
tableMitt?.emit('tableSave', model.value!);
}
/**
* ...
*/
const handleGenerate = async () => {
console.log('generated!!')
}
// endregion |end| methods
</script>
<style scoped lang="scss">
</style>
다음은 간략 버전입니다.
<!--
-->
<template>
<div></div>
</template>
<script lang="ts" setup>
import {onMounted, Ref, ref} from 'vue';
// region =================================================================================================== initialize
// ------------------------------------------------------------------------- props
interface Props {
title?: string
}
const props = withDefaults(defineProps<Props>(), {});
// ------------------------------------------------------------------------- models
const model: Ref<string|null> = ref('sample');
// ------------------------------------------------------------------------- services
const greetingService = new GreetingService();
// ------------------------------------------------------------------------- lifecycle, event, etc...
onMounted(async () => {
console.log('mounted!!!!!');
});
// endregion |end| initialize
// region ====================================================================================================== methods
const init = async () => {
console.log('init!!!!!');
}
// ------------------------------------------------------------------------- event handler
const handleSave = () => {
console.log('saved!!!!!');
}
// endregion |end| methods
</script>
<style scoped lang="scss">
</style>
Ready for more?