https://velog.io/@katanazero86/Intersection-Observer-API
저번에 IntersectionObserver API 에 대한 글을 작성하였습니다.
오늘은 이 해당 API를 이용하여 vue 에서 image lazy loading 구현을 해보도록 하겠습니다. 😎
// 전역 사용자 정의 디렉티브 v-customfocus 등록
Vue.directive('customfocus', {
// 바인딩 된 엘리먼트가 DOM에 삽입되었을 때...
inserted: function (el) {
// 엘리먼트에 포커스를 줍니다
el.focus()
}
})
directives: {
customfocus: {
// 디렉티브 정의
inserted: function (el) {
el.focus()
}
}
}
<input v-customfocus>
bind : 지시어가 요소에 바인드 될때 1번 호출된다.
inserted : 요소가 부모 DOM에 삽입되면 호출된다.
update : 컴포넌트가 업데이트 되었지만, 하위 컴포넌트가 업데이트 되지 않아도 호출된다.
componentUpdated : 컴포넌트와 하위 컴포넌트가 업데이트 되면 호출된다.
unbind : 바인드가 해제가 되는 경우 호출된다.
el : 지시어가 바인딩된 엘리먼트 요소
binding : 객체
- name : 지시어 이름
- value : 예) v-color="red" 전달받은 값
- oldValue : 이전값(update, componentUpdated 에서만 사용가능)
- expression : 표현식 문자열
- arg : 예) v-sticky:bottom -> "bottom"
- modifiers : 예) v-format.underline -> { underline: true }
vnode : 가상DOM node
oldVnode : 이전 가상DOM node
Vue.directive("color", function(el, binding, vnode) {
el.style.color = binding.value;
});
Vue.directive("format", function(el, binding, vnode) {
const modifiers = binding.modifiers;
if (modifiers.underline) {
el.style.textDecoration = "underline";
}
});
<div v-color="'red'">Show this</div>
<span v-format.underline>guide</span>
// v-lazyload
Vue.directive('lazyload', {
inserted(el, binding, vnode) {
},
});
inserted(el) {
function imageLoad(targetElement) {
const imgElement = targetElement;
// data-lazy 에 지정된 이미지 경로를 <img src=""> 에 셋팅 합니다.
imgElement.setAttribute('src', imgElement.getAttribute('data-lazy'));
imgElement.onload = function() {
imgElement.removeAttribute('data-lazy');
};
}
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);
},
window.IntersectionObserver ? callIntersectionApi() : imageLoad(el); 검사를 통해, API 지원여부를 확인합니다. 지원하지 않는다면 바로 이미지를 불러옵니다.
API 지원시, IntersectionObserver callback 함수 작성 및 option 객체 작성 후 인스턴스를 생성해줍니다. 인스턴스 생성 후 observe() 를 호출하여 관찰대상 엘리먼트를 지정합니다.
교차영역에 관찰이 되어 callback 이 실행이 되면, isIntersecting 속성을 통해 검사 후 imageLoad() 를 호출합니다. 그리고 해당 엘리먼트에 대한 감시를 해제해줍니다.
<img :data-lazy="info.imgUrl" v-lazyload>
초기에 이미지를 셋팅할때, 위와같이 구성합니다. 이미지가 실제 안보이는 영역에는 랜더링이 되어있지 않기 때문에 성능이 좋습니다.
data-lazy 속성을 읽어서, src에 지정해주고 onload가 완료되면 해당 속성을 삭제해줍니다.
덕분에 좋은 정보 알게되었습니다. 감사합니다!