본문 바로가기
Programming/Vue

[실습] 뷰(Vue)로 공지사항/게시판 구현하기 - 기본(테이블) 화면 기능 개발

by 돌방로그 2023. 2. 2.


오늘의 Vue.js 실습 목표는 "공지사항/게시판 만들어보기!" 입니다.

본 게시글에서 다루는 사항은 공지사항/게시판 기본(테이블) 화면의 기능을 구현하는 과정입니다.

Spring Boot로 구현한 REST API를 통해 DB 데이터를 조작하는 과정은 별도의 포스팅에서 다룰 예정입니다.

 


공지사항/게시판 구현하기 - 기본(리스트/테이블) 화면

사전 준비

아래 사항에 대해서 사전 준비가 완료되지 않으신 분들은 아래 링크를 참조하여 사전 준비를 진행합니다.

 


결과 이미지

구현하기에 앞서 본 글을 따라하시면 아래와 같이 공지사항 기본(리스트, 테이블) 화면의 레이아웃이 구성되는 것을 확인하실 수 있습니다.

▶ 초기 화면

▶ 테이블에서 한 행을 선택한 경우

▶ 삭제 버튼을 클릭한 경우

 


소스 코드

src\components\user-web\notice\NoticeList.vue

전체 코드를 확인하실 분들은 아래 더보기를 클릭해주세요.

더보기
<template>
  <div class="ma-md-5">
    <div class="d-flex justify-end mt-5">
      <!-- For Notice List Manipulation > Register  -->
      <v-btn
        text
        outlined
        class="mx-md-1 elevation-2"
        :disabled="!hasSelectedRow()"
        @click="viewNotice"
        >VIEW DETAIL
      </v-btn>

      <!-- For Notice List Manipulation > Register  -->
      <v-btn text outlined class="mx-md-1 elevation-2" @click="registerNotice"
        >REGISTER
      </v-btn>

      <!-- For Notice List Manipulation > Modify  -->
      <v-btn
        text
        outlined
        class="mx-md-1 elevation-2"
        :disabled="!hasSelectedRow()"
        @click="modifyNotice"
        >MODIFY
      </v-btn>

      <!-- For Notice List Manipulation > Delete  -->
      <v-dialog v-model="dialogDelete" persistent max-width="290">
        <template v-slot:activator="{ on, attrs }">
          <v-btn
            text
            outlined
            class="mx-md-1 elevation-2"
            :disabled="!hasSelectedRow()"
            v-bind="attrs"
            v-on="on"
            >DELETE
          </v-btn>
        </template>
        <v-card>
          <v-card-title class="text-h5">
            Are you sure you want to delete this notice?
          </v-card-title>
          <v-card-text
            >Deleted notices cannot be restored, and are immediately reflected
            on the user portal after deletion.</v-card-text
          >
          <v-card-actions>
            <v-spacer></v-spacer>
            <v-btn color="blue darken-1" text @click="dialogDelete = false">
              Cancel
            </v-btn>
            <v-btn color="blue darken-1" text @click="deleteNotice">
              Confirm
            </v-btn>
          </v-card-actions>
        </v-card>
      </v-dialog>
    </div>

    <!-- For Notice List -->
    <v-data-table
      single-select
      show-select
      class="mt-md-2 elevation-5"
      v-model="selectedRow"
      :headers="headers"
      :items="data"
      :items-per-page="10"
    >
    </v-data-table>
  </div>
</template>

<script>
const MODE_VIEW = "VIEW";
const MODE_REGISTER = "REGISTER";
const MODE_MODIFY = "MODIFY";
const MODE_DELETE = "DELETE";

export default {
  data() {
    return {
      selectedRow: [],
      dialogDelete: false,

      // For Notice List
      headers: [
        {
          text: "Category",
          value: "category",
        },
        {
          text: "Title",
          value: "title",
        },
        {
          text: "Date",
          value: "date",
        },
        {
          text: "Name",
          value: "name",
        },
      ],
      data: [
        {
          id: "1",
          category: "Competition",
          title: "The 3rd Competition Open!",
          date: "2022/11/01",
          name: "SYSTEM",
        },
        {
          id: "2",
          category: "System Check",
          title: "2022/12/10 System Check",
          date: "2022/12/01",
          name: "SYSTEM",
        },
        {
          id: "3",
          category: "System Check",
          title: "2022/12/15 System Check",
          date: "2022/12/10",
          name: "SYSTEM",
        },
        {
          id: "4",
          category: "System Check",
          title: "2023/01/01 System Check",
          date: "2022/12/21",
          name: "SYSTEM",
        },
        {
          id: "5",
          category: "Competiton",
          title: "The 4th Competition Open!",
          date: "2023/01/01",
          name: "SYSTEM",
        },
        {
          id: "6",
          category: "Etc",
          title: "Test Announcement",
          date: "2023/01/05",
          name: "SYSTEM",
        },
      ],
    };
  },
  methods: {
    hasSelectedRow: function () {
      return this.selectedRow.length > 0;
    },
    changeMode: function (mode, notice) {
      this.$emit("changeMode", mode, notice);
    },
    viewNotice: function () {
      this.changeMode(MODE_VIEW, this.selectedRow);
    },
    registerNotice: function () {
      if (this.hasSelectedRow()) {
        this.selectedRow = [];
      }
      this.changeMode(MODE_REGISTER, this.selectedRow);
    },
    modifyNotice: function () {
      this.changeMode(MODE_MODIFY, this.selectedRow);
    },
    deleteNotice: function () {
      this.dialogDelete = false;

      this.changeMode(MODE_DELETE, this.selectedRow);
    },
  },
};
</script>

<style>
tr.v-data-table__selected {
  background: lightgoldenrodyellow !important;
}
</style>

 

<template>

<template>
  <div class="ma-md-5">
    <div class="d-flex justify-end mt-5">
      <!-- For Notice List Manipulation > Detail View  -->
      <v-btn
        ...
        :disabled="!hasSelectedRow()"
        @click="viewNotice"
        >VIEW DETAIL
      </v-btn>

      <!-- For Notice List Manipulation > Register  -->
      <v-btn 
        ... 
        @click="registerNotice"
        >REGISTER
      </v-btn>

      <!-- For Notice List Manipulation > Modify  -->
      <v-btn
        ...
        :disabled="!hasSelectedRow()"
        @click="modifyNotice"
        >MODIFY
      </v-btn>

      <!-- For Notice List Manipulation > Delete  -->
      <v-dialog v-model="dialogDelete" persistent max-width="290">
        <template v-slot:activator="{ on, attrs }">
          <v-btn
            ...
            :disabled="!hasSelectedRow()"
            v-bind="attrs"
            v-on="on"
            >DELETE
          </v-btn>
        </template>
        <v-card>
          <v-card-title class="text-h5">
            Are you sure you want to delete this notice?
          </v-card-title>
          <v-card-text
            >Deleted notices cannot be restored, and are immediately reflected
            on the user portal after deletion.</v-card-text
          >
          <v-card-actions>
            <v-spacer></v-spacer>
            <v-btn color="blue darken-1" text @click="dialogDelete = false">
              Cancel
            </v-btn>
            <v-btn color="blue darken-1" text @click="deleteNotice">
              Confirm
            </v-btn>
          </v-card-actions>
        </v-card>
      </v-dialog>
    </div>

    <!-- For Notice List -->
    <v-data-table
      ...
      v-model="selectedRow"
      ...
    >
    </v-data-table>
  </div>
</template>
  • UI
    • :disabled = 버튼 요소의 Enable 상태를 테이블의 행 선택 여부를 감지하여 변화되도록 함수 호출 코드 정의
    • 삭제 버튼 = 버튼 클릭시 팝업창이 띄워지도록 관련 코드 추가
  • Event
    • @click = 버튼 요소에 이벤트 발생시 호출할 함수를 연결하는 코드 정의
    • v-model = 버튼 외 요소에 변경된 값을 감지하는 코드 정의

 

<script>

<script>
const MODE_VIEW = "VIEW";
const MODE_REGISTER = "REGISTER";
const MODE_MODIFY = "MODIFY";
const MODE_DELETE = "DELETE";

export default {
  data() {
    return {
      selectedRow: [],
      dialogDelete: false,

      // For Notice List
      headers: [
        ...
      ],
      data: [
        ...
      ]
    };
  },
  methods: {
    hasSelectedRow: function () {
      return this.selectedRow.length > 0;
    },
    changeMode: function (mode, notice) {
      this.$emit("changeMode", mode, notice);
    },
    viewNotice: function () {
      this.changeMode(MODE_VIEW, this.selectedRow);
    },
    registerNotice: function () {
      if (this.hasSelectedRow()) {
        this.selectedRow = [];
      }
      this.changeMode(MODE_REGISTER, this.selectedRow);
    },
    modifyNotice: function () {
      this.changeMode(MODE_MODIFY, this.selectedRow);
    },
    deleteNotice: function () {
      this.dialogDelete = false;

      this.changeMode(MODE_DELETE, this.selectedRow);
    },
  },
};
</script>
  • data 영역
    • selectedRow: 테이블에서 선택된 행 정보가 담긴 변수
    • dialogDelete: 삭제 버튼 클릭시 팝업되는 다이얼로그의 활성 여부 정보가 담긴 변수
  • methods 영역
    • hasSelectedRow(): 테이블에서 선택된 행이 있는지 확인하는 함수
    • changeMode(): 모드 변경에 따른 상위 컴포넌트에 정보를 전달하는 함수
      • 전달 정보: 조작 모드(등록, 삭제, 수정, 상세보기), 선택된 공지사항/게시글 정보
    • viewNotice(): '상세보기' 관련 처리 함수
    • registerNotice(): '등록' 관련 처리 함수
      • 테이블에 선택된 행이 있으면 선택 취소 처리
    • modifyNotice(): '수정' 관련 처리 함수
    • deleteNotice(): '삭제' 관련 처리 함수
      • 팝업된 다이얼로그를 표시 해지하도록 dialogDelete의 변수값 false 설정
  • 참고 사항 
    • script에 선언된 const 변수(MODE_%)를 NoticeList.vue, NoticeDetail.vue, BaseNotice.vue에서 각각 관리하는 것이 아닌 하나의 파일에서 관리하고 사용할 수 있도록 변경하는 작업이 필요합니다.

 

<style>

<style>
tr.v-data-table__selected {
  background: lightgoldenrodyellow !important;
}
</style>
  • 테이블에서 한 행이 클릭되었을 때 표시될 background 정보 설정

 


References

댓글