[Nuxt.js] Draggable 컨트롤

babypig·2022년 10월 11일
1

Nuxt.js

목록 보기
3/10
post-thumbnail

📌 구현목표

vuedraggable 을 이용한 table 순번 변경하기

⚙️ 기본구조

props로 tabledData를 받아와 tableData를 cloneDeep 으로 객체 복사를 해주고 시작,
⛔ 주의할점 - vuedraggable의 기본 구조에 들어갈 template가 아닌 다른 template가 존재하면 제대로 된 값을 반환하지 못함, 데이터의 유무를 판단할 시에는 없는 데이터는 따로 빼서 분기처리해줘야함,

  <SPageable
      :table-data="cloneTableData"
      :is-hide-pagination="isProgress"
      @getTableData="
        (page) => {
          $emit('changePage', page);
        }
      "
    >
      <template #data="{ data }">
        <table class="admin-table">
          <thead>
            <tr>
              <th>순서</th>
              <th>썸네일</th>
              <th class="text-left">제목</th>
              <th>상태</th>
              <th>진행기간</th>
              <th>수정 일시</th>
              <th>노출 여부</th>
            </tr>
          </thead>
          <tbody v-if="!data || !data[0]">
            <tr>
              <td colspan="7"><div>데이터가 없습니다.</div></td>
            </tr>
          </tbody>
          <template v-if="cloneTableData.content && cloneTableData.content[0]">
            <draggable
              v-model="cloneTableData.content"
              tag="tbody"
              v-bind="dragOptions"
              :disabled="!isProgress"
              @change="changeDrag"
            >
              <tr v-for="(item, index) in data" :key="item.id" @click="onGoDetail(item.id)">
                <td>
                  <div>{{ cloneTableData.startCount + index }}</div>
                </td>
                <td>
                  <div class="img">
                    <img :src="`${$store.state.BASE_URL}${item.pcImage?.savedFileName}`" :alt="`${item.pcImageAlt}`" />
                  </div>
                </td>
                <td>
                  <div class="text-left">{{ item.title }}</div>
                </td>
                <td>
                  <div>{{ getState(item.state) }}</div>
                </td>
                <td>
                  <div>
                    <p>{{ item.startDate }} ~</p>
                    <p>{{ item.endDate }}</p>
                  </div>
                </td>
                <td>
                  <div>{{ item.lastModifiedDate }}</div>
                </td>
                <td @click.stop>
                  <div>
                    <SToggle v-model="item.isEnabled" @input="onEnabled(item.id, item.isEnabled)">{{
                      item.isEnabled ? '노출' : '미노출'
                    }}</SToggle>
                  </div>
                </td>
              </tr>
            </draggable>
          </template>
        </table>
      </template>
    </SPageable>
    
<script>
export default {
  name: 'SiteList',
  props: {
    tableData: {
      type: Object,
      required: false,
      default: () => null
    }
  },
  data() {
    return {
      id: null,
      titleText: '',
      baseUrl: '',
      emojiType: '',
      searchText: '',
      cloneTableData: cloneDeep(this.tableData),
      isProgress: true,
      isShowDisabled: false
    };
  },
</script>

1. Object의 내용이 변경됨을 감지하기 위한 Watch를 사용하여 감시 대상 데이터가 변했을 때, 처리 로직을 작성 (deep: true)

<script>
  watch: {
    tableData: {
      deep: true,
      handler(newValue) {
        this.cloneTableData = cloneDeep(newValue);
      }
    }
  },
</script>

2. change 이벤트 작성

vuedraggable 의 moved: 배열 내에서 이동된 요소의 정보를 포함합니다.
newIndex: 이동된 요소의 현재 인덱스
oldIndex: 이동된 요소의 이전 인덱스
element: 이동된 요소

이벤트 속성으로 list Index 변경 확인 후 params으로 보내줌,

  <draggable
     v-model="cloneTableData.content"
     tag="tbody"
     v-bind="dragOptions"
     :disabled="!isProgress"
     @change="changeDrag"
   >

<script>
 async changeDrag({ moved }) {
      const { newIndex, oldIndex } = moved;

      console.log('바뀐data: ', moved.element);
      console.log('newIndex: ', this.cloneTableData.content[newIndex]);
      console.log('oldIndex: ', this.cloneTableData.content[oldIndex]);

      const params = {
        isProgress: this.isProgress,
        isShowDisabled: this.isShowDisabled,
        dragId: this.cloneTableData.content[newIndex].id,
        dropId: this.cloneTableData.content[oldIndex].id
      };
        await this.$axios.$put(`/admin/popups/order`, null, { params });
    },
</script>

🔎 개발중 오류 발견 11/01

이동 시에 아래로 내리는 로직은 정상 작동했지만 아래에서 위로 올리는 작업 시 제대로 작동하지 않는것을 발견했다. index 계산식 작성 후 변경해줌.

<script>
 async changeDrag({ moved }) {
      const { newIndex, oldIndex } = moved;
   const diff = newIndex < oldIndex ? 1 : -1;
      console.log(this.cloneTableData.content.map((x) => `${x.id}`).join(','));
      const params = {
        isProgress: this.isProgress,
        isShowDisabled: this.isShowDisabled,
        dragId: moved.element.id,
        dropId: this.cloneTableData.content[newIndex + diff].id
      };
        await this.$axios.$put(`/admin/popups/order`, null, { params });
    },
</script>
profile
babypig

0개의 댓글