본문 바로가기
영화 검색 사이트

[영화 검색 사이트] 로딩 애니메이션, Footer

by mikrw 2023. 2. 11.

https://getbootstrap.com/docs/5.3/components/spinners/

 

Spinners

Indicate the loading state of a component or page with Bootstrap spinners, built entirely with HTML, CSS, and no JavaScript.

getbootstrap.com

 

MovieList.vue

<template>
  <div class="container">
    <div
      :class="{ 'no-result': !movies.length }"
      class="inner">
      <div
        v-if="loading"
        class="spinner-border text-primary"></div>
      <div
        v-if="message"
        class="message">
        {{ message }}
      </div>
      <div
        v-else
        class="movies">
        <MovieItem
          v-for="movie in movies"
          :key="movie.imdbID"
          :movie="movie" />        
      </div>
    </div>
  </div>
</template>

movie.js

export default {
  // module!
  namespaced: true,
  // data!
  state: () => ({
    movies: [],
    message: 'Search for the movie title!',
    loading: false
  }),
  // computed!
  getters: {},
  // methods!
  // 변이
  mutations: {
    updateState(state, payload){
      Object.keys(payload).forEach(key => {
        state[key] = payload[key]
      })
    },
    resetMovies(state) {
      state.movies = []
    }
  },
  // 비동기
  actions: {
    async searchMovies({ state, commit }, payload) {
      if(state.loading) return

      commit('updateState', {
        message: '',
        loading: true
      })

      try {
        const res = await _fetchMovie({
          ...payload,
          page: 1
        })

        const { Search, totalResults } = res.data
        commit('updateState', {
          movies: _uniqBy(Search, 'imdbID')
        })

        const total = parseInt(totalResults, 10)
        const pageLength = Math.ceil(total / 10)
        if(pageLength > 1) {
          for(let page=2; page <= pageLength; page++){
            if(page > (payload.number / 10)) break
            const res = await _fetchMovie({
              ...payload,
              page
            })
            const { Search } = res.data
            commit('updateState', {
              movies: [...state.movies, ..._uniqBy(Search, 'imdbID')]
            })          
          }
        }
      } catch (message) {
        commit('updateState', {
          movies: [],
          message
        })
      } finally {
        commit('updateState', {
          loading: false
        })
      }

    }
  }
}

Footer.vue

<template>
  <footer>
    <Logo />
    <a
      href="https://mikrw.tistory.com/"
      target="_blank">
      (c){{ new Date().getFullYear() }} mikrw
    </a>
  </footer>
</template>

<script>
import Logo from '~/components/Logo';

export default {
  components: {
    Logo
  }
}
</script>

<style lang="scss" scoped>
  footer {
    padding: 70px 0;
    text-align: center;
    opacity: .3;
    .logo {
      display: block;
      margin-bottom: 4px;
    }
  }
</style>