[Nuxt.js]기능 개발 히스토리

babypig·2022년 10월 14일
1

Nuxt.js

목록 보기
4/10
post-thumbnail

📌 주절주절

프로젝트 진행 중이라 개인 공부가 더뎌지고 있어서 개발하면서 기록 남길겸 작성해본다,

⚙️ Computed로 store state 가져와 Dropdown 옵션 적용하기

Dropdown 기본구조


<div class="dropdown" :class="{ 'is-open': isOpen }" @click="onStopPropagation">
    <div v-if="isHasSlotText" class="label">
      <slot />
    </div>
    <div class="dropdown-wrap">
      <button
        class="dropdown-btn"
        type="button"
        :style="{
          width: `${width}rem`
        }"
        @click="onToggleMenu"
      >
        {{ selectedLabel || defaultText }}
      </button>
      <div class="dropdown-icon">
        <i class="ic-expand-more" />
      </div>
      <div v-if="isOpen && optionList && optionList[0]" class="dropdown-menu">
        <button v-for="item in optionList" :key="item.value" type="button" @click="onSelected(item)">
          {{ item.label }}
        </button>
      </div>
    </div>
  </div>

<script>
	export default {
  name: 'SDropdown',
  props: {
    value: {
      type: [String, Number, Boolean, null],
      required: false,
      default: null
    },
    // optionList: [{ value: '', label: '' }]
    optionList: {
      type: Array,
      required: false,
      default: () => []
    },
    defaultText: {
      type: String,
      required: false,
      default: '옵션선택'
    },
    // value: x-small | small | normal | large
    wSize: {
      type: String,
      required: false,
      default: 'normal'
    }
  },
  data() {
    return {
      width: 15.2,
      isOpen: false
    };
  },
  computed: {
    isHasSlotText() {
      return !!this.$slots.default;
    },
    selectedLabel() {
      const targetValue = this.value;
      const isHasNullValue = !!this.optionList.find((item) => item.value === null);
      const targetOption = this.optionList.find((item) => item.value === targetValue);

      return isHasNullValue || (targetValue != null && targetOption) ? targetOption.label : null;
    }
  },
  created() {
    let width = 15.2;

    switch (this.wSize) {
      case 'x-small':
        width = 9.5;
        break;
      case 'small':
        width = 12.2;
        break;
      case 'normal':
        width = 15.2;
        break;
      default:
        width = 20;
        break;
    }
    this.width = width;
  },
  mounted() {
    document.addEventListener('click', () => {
      this.isOpen = false;
    });
  },
  methods: {
    onStopPropagation(e) {
      e.stopPropagation();
    },
    onToggleMenu() {
      this.isOpen = !this.isOpen;
    },
    onSelected({ value }) {
      this.isOpen = false;
      this.$emit('input', value);
      this.$emit('change');
    }
  }
};
</script>

optionList를 computed hallOptionList로 연결하여 내려줌
store에 hallList를 전역으로 설정한 후 받아와 map 함수를 이용하여 value와 label에 넣어주며, unshift를 활용하여 전체 값도 추가한다.

<Dropdown v-model="queryOptions.hall" :option-list="hallOptionList">:</SDropdown>

<script>
computed: {
    hallOptionList() {
      const hallList = this.$store.state.HALL_LIST.map((hall) => ({
        value: hall,
        label: `${hall}`
      }));

      hallList.unshift({ value: null, label: '전체' });

      return hallList;
    }
  },
</script>

⚙️ Modal에 props로 index 보내기

기본구조

<template>
  <transition name="fade">
    <div v-if="isShow" class="modal-wrap">
      <div class="modal-inner">
        <div class="modal">
          <div class="head">
            <button type="button" class="close-btn" @click="$emit('close')">
              <i class="ic-close" />
            </button>
          </div>
          <div class="body">
            <div class="contents-info mb-24">
              <div class="representative-img mr-16">
                <img src="" alt="" />
              </div>
              <div class="works-info">
                <p class="mt-1m">{{ docentData.title }}</p>
                <p class="mt-2r">{{ docentData.writer }}</p>
                <p class="mt-2r">{{ docentData.position }}</p>
                <div>
                  <audio class="player" controls></audio>
                </div>
              </div>
            </div>
            <div>
              <p>
                {{ docentData.intro }}
              </p>
            </div>
          </div>
          <div class="foot">
            <div class="map-img">
              <img src="" alt="" />
            </div>
          </div>
        </div>
      </div>
    </div>
  </transition>
</template>

<script>
import { disableBodyScroll, clearAllBodyScrollLocks } from 'body-scroll-lock';
export default {
  name: 'DocentModal',
  props: {
    isShow: {
      type: Boolean,
      required: false,
      default: false
    },
    docentData: {
      type: Object,
      required: false,
      default: () => null
    }
  },
  data() {
    return {};
  },
  watch: {
    isShow(newValue) {
      if (newValue) {
        disableBodyScroll(document);
      } else {
        clearAllBodyScrollLocks();
      }
    }
  },
  beforeDestroy() {
    clearAllBodyScrollLocks();
  }
};
</script>

리스트 클릭 시 Modal이 나오며 index에 따른 data를 넣어줘야한다,
그래서 리스트를 클릭 시 index를 넣어주고 computed로 index를 담을 변수를 선언 후
return 하여 data에 해당 index를 넣어준다.

<tr v-for="(item, index) in data" :key="item.id" @click="openDocentModal(index)">
                <td>
                  <div>{{ docentData.startCount + index }}</div>
                </td>           
</tr>

<script>
data() {
    return {
      docentData: null,
      modal: {
        isDocent: false
      },
      selectedDocentIndex: null,
    };
  },
computed: {
    selectedDocentData() {
      const selectedDocentIndex = this.selectedDocentIndex;
      return selectedDocentIndex != null ? this.docentData.content[selectedDocentIndex] : null;
    }
  },
  methods: {
    openDocentModal(index) {
      this.selectedDocentIndex = index;
      this.modal.isDocent = true;
    },
}
</script>
profile
babypig

0개의 댓글