현재 진행하고 있는 프로젝트는 첫화면에 많은 이미지 리소스를 요청한다. (쇼핑몰)
이때 최초에 lazy loading이 적용되어 있지 않아, 사용자가 보고 있지 않은 화면에 대한 리소스도 모두 요청해 가져오고 있었다. 이에 custom directive를 만들어 img태그에 이 directive를 추가하면 lazy loading이 적용될 수 있도록 만들어 누구나 적용할 수 있게 만들어 두었다. 현재 Vue2 를 이용하여 개발중이다.
Lazy Loading 이란?
페이지에서 실제로 필요할 때까지 리소스의 로딩을 미루는 것으로 웹 최적화에 많이 쓰인다. 실제로 사용자가 페이지를 보고 있는 타이밍에 이미지를 로딩한다. 또한 이미지 말고 다른 파일 (ex. js파일) 에도 적용 될 수 있다. 현재 이 글에서는 우선적으로 이미지만 다루려고 한다.
Custom Directive란?
vue에서는 v-show v-if 같은 기본 디렉티브가 주어져 손쉽게 Dom을 조작할 수 있다. 뿐만 아니라 기본 디렉티브 이외에 사용자가 커스텀하여 디렉티브를 제작할 수도 있는데, element를 매개변수로 받아 dom을 조작하는 커스텀 디렉티브를 만들어 사용 할 수 있다.
적용법
일단 img태그에 data-src라는 속성을 만들어서 이미지 리소스를 할당합니다. (속성 이름은 마음대로 하셔도 좋습니다)
이후 자바스크립트에서 제공하는 Intersection Observer API르르 이용하여 타겟 element와 document의 viewport 사이의 intersection 내의 변화를 비동기적으로 관찰하여 타겟 element가 사용자의 viewport에 들어왔을 때, data-src에 할당 했던 이미지 리소스를 src속성에 재 할당하여 이미지를 로드하고, data-src 속성을 제거합니다.
Intersection Observer는 최신버전의 크롬과 사파리에서는 작동하지만 IE에서는 작동하지 않고 있음을 주의해야합니다. 저희 서비스는 모바일 웹앱 서비스로 크롬과 사파리로만 서비스 하고 있기 때문에 Intersection Observer를 사용하여 개발하는 것이 적절하다고 판단하여 아래와 같은 코드를 적용시켰습니다.
directives: {
lazyload: {
inserted(el) {
function imageLoad(targetElement) {
const imgElement = targetElement;
imgElement.setAttribute("src", imgElement.getAttribute("data-src"));
imgElement.onload = function () {
imgElement.removeAttribute("data-src");
};
}
function callIntersectionApi() {
const options = { root: null, threshold: 0.5, rootMargin: "0px" };
const lazyLoadCallback = (entries, observer) => {
entries.forEach((entry) => {
if (entry.isIntersecting) {
imageLoad(entry.target);
observer.unobserve(entry.target);
}
});
};
const lazyLoadingIO = new IntersectionObserver(lazyLoadCallback, options);
lazyLoadingIO.observe(el);
}
window.IntersectionObserver ? callIntersectionApi() : imageLoad(el);
},
},
},
Intersection Observer를 생성 할때 options에 들어가는 넣은 요소들은 다음과 같습니다.
1. root : 대상 객체의 가시성을 확인할 때 사용되는 뷰포트 요소입니다. 이는 대상 객체의 조상 요소여야 합니다. 기본값은 브라우저 뷰포트이며, root 값이 null 이거나 지정되지 않을 때 기본값으로 설정됩니다.
2. threshold : observer의 콜백이 실행될 대상 요소의 가시성 퍼센티지를 나타내는 단일 숫자 혹은 숫자 배열입니다. 만일 50%만큼 요소가 보여졌을 때를 탐지하고 싶다면, 값을 0.5로 설정하면 됩니다. 기본값은 0이며(이는 요소가 1픽셀이라도 보이자 마자 콜백이 실행됨을 의미합니다). 1.0은 요소의 모든 픽셀이 화면에 노출되기 전에는 콜백을 실행시키지 않음을 의미합니다.
3. rootMargin : root 가 가진 여백입니다. 이 속성의 값은 CSS의 margin 속성과 유사합니다. e.g. "10px 20px 30px 40px" (top, right, bottom, left). 이 값은 퍼센티지가 될 수 있습니다. 이것은 root 요소의 각 측면의 bounding box를 수축시키거나 증가시키며, 교차성을 계산하기 전에 적용됩니다. 기본값은 0입니다.
https://developer.mozilla.org/ko/docs/Web/API/Intersection_Observer_API
여기서 더 많은 예제를 보실수 있습니다 :)
'프론트엔드 > vue.js' 카테고리의 다른 글
ChunkLoadError 해결기 (1) 문제점 파악 및 테스트 과정 (0) | 2022.03.31 |
---|---|
[SPA] 뒤로 가기 스크롤 유지에 관하여(2) (0) | 2021.12.27 |
[SPA] 뒤로 가기 스크롤 유지에 관하여(1) (0) | 2021.12.15 |
웹 최적화 2. vue.js 라우터 code splitting 적용하기 (0) | 2021.12.06 |
웹 최적화 1. webpack-bundle-analyzer 플러그인을 이용하여 시각화 하기 (0) | 2021.12.01 |