[Vue] Vue3 TodoList

DongEun·2023년 1월 28일
3
post-thumbnail

Vue3로 TodoList 만들기!

Vue3는 여기까지만 하고,, 다음글부터 Vue2에 typescript를 공부 할 예정이에요.


gh-pages : https://kimdongeun12.github.io/vue3-practice/
github : https://github.com/kimdongeun12/vue3-practice

폴더 구조

├─ src
│  ├─ App.vue
│  ├─ main.ts
│  └─ views
│     └─ todo
│        ├─ TodoList.vue // Todo의 View
│        ├─ TodoListWrap.vue // Todo의 List를 담고 있음
│        └─ TodoListWrite.vue // 리스트 작성 , 수정을 담당

폴더 구조는 위와같이 구성을했어요

TodoList.vue

<template>
  <v-container>
    <TodoListWrap
      :Todolists="Todolists"
      @isChecked="isChecked"
      @deleteTodo="deleteTodo"
      @showDialog="showDialog"
    />
    <v-btn
      class="floating"
      icon="mdi-pencil"
      size="small"
      @click="showDialog()"
    />
    <v-dialog v-model="dialog">
      <TodoListWrite
        :dialog="dialog"
        :edits="edits"
        :editTodo="edits.edit ? Todolists[edits.idx] : {}"
        @hideDialog="hideDialog"
        @submitDialog="submitDialog"
        @editSubmitDialog="editSubmitDialog"
      />
    </v-dialog>
  </v-container>
</template>

export default defineComponent({
  ...
  methods: {
    showDialog(idx?: number) {
      this.dialog = true;
      if (idx !== undefined) {
        this.edits.idx = idx;
        this.edits.edit = true;
      } else {
        this.edits.idx = 0;
        this.edits.edit = false;
      }
    }
  },
  ...
});
</script>

<style lang="scss" scoped>
.floating {
  position: fixed;
  right: 24px;
  bottom: 24px;
}
</style>

TodoListWrap.vue

<template>
  <div class="listsWrap">
    <v-card
      class="mx-auto my-list"
      v-for="(item, idx) in Todolists"
      :key="idx"
      :class="{ 'mx-auto active': item?.checked }"
      width="400"
    >
      <template v-slot:title>
        <v-btn
          variant="text"
          icon="mdi-check"
          size="small"
          @click="$emit('isChecked', idx)"
        />
        {{ item?.title }}
      </template>

      <v-card-text> {{ item?.contents }} </v-card-text>
      <v-card-actions class="justify-end">
        <v-btn variant="outlined" @click="$emit('showDialog', idx)">
          수정
        </v-btn>
        <v-btn variant="outlined" @click="$emit('deleteTodo', idx)">
          삭제
        </v-btn>
      </v-card-actions>
    </v-card>
    <div class="text-center" v-if="Todolists?.length === 0">
      할 일 목록이 없습니다.<br />
      우측 아래 버튼을 클릭하여 추가해주세요.
    </div>
  </div>
</template>

<script lang="ts">
import { defineComponent } from "vue";

export default defineComponent({
  name: "TodoListWrap",
  components: {},
  props: {
    Todolists: Object,
  },
  data() {
    return {};
  },
});
</script>
<style lang="scss" scoped>
.listsWrap {
  display: block;
  & > div + div {
    margin-top: 20px;
  }
  .active:deep .v-card-title .v-btn__content {
    color: #ff0000;
  }
}
</style>

파일을 작성하는데 그렇게 중요하다고 느끼는건 별로 없지만 작업하면서 2가지정도 느낀게 있는데 css에서는 scoped를 이용하여 작업을 하는경우가 대다수인데 가끔식 Vuetify에서 스타일이 안먹히는 경우가 있어요 그때는 :deep 을 사용하면 해결이 되더라구요 정답은 아니지만 저같은경우는 v-card의 아이템 체크아이콘 색상을 변경해야할때 사용했어요.

props같은 개념은 React와 조금 비슷하면서도 다르다고 느꼈어요
:아이템명 바인드로 props를 전달 할 수 있으며 Function같이 이벤트를 넘길때에는
@함수명 으로 넘길 메소드를 넘기시면되요 자식한테 넘긴 메소드는
emit('함수명' , 전달할 값)으로 사용 할 수 있어요

아직 제가 많이 해보지를 않아서 양반향 바인딩이 얼마나 편리한지는 모르겠어요 하지만 단반향으로만 줄 수 있던 react보다 처음으로 vue를 입문 할 때는 편리한거 같아요

자세한 코드는 상단의 깃허브를 이용하여 확인해주시면 될거같아요
오늘도 좋은하루 되세요 ;)

profile
다채로운 프론트엔드 개발자

0개의 댓글