써치킴의 우당탕탕 개발 블로그

[Vue.js][Ch4][영화검색 사이트] Vue 플러그인(이미지 로드 이벤트) 본문

완벽하게 Vue.js

[Vue.js][Ch4][영화검색 사이트] Vue 플러그인(이미지 로드 이벤트)

써치킴 2022. 4. 28. 21:34

검색 후 로딩될 때, 개별적인 이미지가 로드되는 로딩 애니메이션을 추가할 것이다.

  • Vue.js 3버전 공식 홈페이지 > 재사용성 & 컴포지션 > 플러그인 > 플러그인 작성법 참고

1 . Movieitem.vie > imageLoading 이라는 데이터 생성

data() {
  return {
    imageLoading: true
  }
},
  • imageLoading의 초기값은 true => 이미지 로딩 중인 상태이다.

2. 이미지가 준비되어 로드가 완료되면 실행하는 메소드 생성

methods: {
  init() {
    const img = document.createElement('img');    // img 요소를 생성해서 메모리에 저장
    img.src = this.movie.Poster;
    img.addEventListener('load', () => {          // 이미지가 준비되어 로드가 완료되면 콜백함수 실행
      this.imageLoading = false;
    });
  }
}
  • 이미지가 준비되어 로드가 완료되면 imageLoading은 false로 치환한다. => 이미지 로딩이 끝났다.

콜백 함수로 화살표 함수를 사용하면

this는 vue 파일 내에서 사용하는 데이터나 메소드에 접근 할 수 있다.

그러나 화살표 함수가 아닌 일반적인 function 함수를 사용한다면 

this는 호출된 곳에서의 this로 해석되기 때문에 data 옵션에 정의된 imageLoding 데이터에 접근 할 수 없다.

따라서,

vue 파일 내에서는 function 키워드 대신 화살표 함수를 많이 사용할 것이다.

 

3. Loader 컴포넌트 추가 + Loader 태그 추가

<!-- imageLoading이 true일 때, Loader 출력
    / size = 1.5 : size는 1.5rem 
    / absolute = true : 부모 요소(div)의 가운데에 배치 -->   
<Loader 
  v-if="imageLoading"
  :size="1.5" 
  absolute />
  • imageLoding이 true일 때, 로딩 애니메이션 출력

4. MovieItem 컴포넌트가 연결된 직후에 init 메소드 실행

mounted() {       // MovieItem 컴포넌트가 연결이 된 직후에 
  this.init();    // init 메소드 실행
},
  • HTML 구조와 연결된 직후에 실행 => mounted 메소드 사용
  • init 메소드처럼 HTML 구조를 다뤄서 무엇인가 할 때는, mounted 사용 권장!

이렇게 만든 로직을 플러그인을 사용하여 다른 프로젝트에도 사용할 수 있도록 정리해보자.

1. 비동기로 동작하는 loadImage 플러그인 생성 (loadImage.js)

export default {    // 객체 데이터 기본 내보내기
  install(app) {
    app.config.globalProperties.$loadImage = (src) => {    // src를 인수로 받아서 매개변수로 사용
      return new Promise(resolve => {
        const img = document.createElement('img');    // img 요소를 생성해서 메모리에 저장
        img.src = src;
        img.addEventListener('load', () => {          // 이미지가 준비되어 로드가 완료되면 콜백함수 실행
          // 로드가 완료되었다.
          resolve();
        });
      }) 
    }
  }
}

2. 플러그인 등록 > main.js

// App.vue 파일을 main.js에서 시작

import { createApp } from 'vue'   // 객체구조분해를 통해서 바로 createApp 가져옴
import App from './App'
import router from './routes'    // router 연결을 위해 import
import store from './store'      // store 연결을 위해 import
import loadImage from './plugins/loadImage'      // plugin 연결을 위해 import

// html에서 app이라는 id를 가지고 있는 요소에 vue.js 프로젝트를 연결
// .use : 현재 프로젝트에서 특정한 플러그인을 연결할 때 사용
createApp(App)
  .use(router)    // $route, $router
  .use(store)     // $store
  .use(loadImage) // $loadImage
  .mount('#app')

3. 플러그인 사용 > MovieItem.vue

methods: {
  async init() {
    await this.$loadImage(this.movie.Poster);   // 이미지 로딩이 완료되면
    this.imageLoading = false;                  // false 처리
  }
}
  • 비동기로 loadImage 메서드 사용

영화 상세 정보 페이지 > 포스터 이미지도 플러그인을 이용해 로딩 애니메이션을 추가해보자 

1. imageLoading 데이터 추가

data() {
  return {
    imageLoading: true
  }
},

2. Loader 태그 추가

<Loader  
  v-if="imageLoading"
  absolute />

3. requestDiffSizeImage 메소드 수정

requestDiffSizeImage(url, size = 700) {           // size 기본값 : 700
  const src = url.replace('SX300',`SX${size}`);   // 이미지 사이즈를 바꿔서 전송
  this.$loadImage(src)
    .then(() => {
      this.imageLoading = false;
    });
  return src;
}
  • this.$loadImage 메서드와 return src가 별개로 동작하게 .then 비동기 방식으로 구현

출력

! $이 붙어있으면 플러그인으로 되어 있는 내용이라고 유추할 수 있다.

Comments