Agora é possível passar um observável que é uma ótima maneira de estender a biblioteca. No entanto, é um pouco limitado, pois os usos não conseguem acessar a imagem de forma simples.
Um dos problemas mais comuns é quando o usuário não usa a janela para rolar ou usa uma biblioteca de 3 partes que adiciona camadas de rolagem extras (por exemplo, iônico, design de material ng, etc), e às vezes pode ser difícil de encontrar qual elemento realmente rola. Uma maneira de resolver isso poderia ser usar Intersection Observer
(que também pode aumentar o desempenho). Por exemplo.
@Component({
selector: 'intersection-observer',
template: `<img #img [defaultImage]="defaultImage" [lazyLoad]="image" [scrollObservable]="subject">`,
})
export class IntersectionObserverComponent {
@ViewChild('img') img;
subject = new Subject();
defaultImage = 'https://www.placecage.com/1000/1000';
image = 'https://images.unsplash.com/photo-1467932760935-519284fc87fa?dpr=2&auto=compress,format&fit=crop&w=1199&h=800&q=80';
ngAfterViewInit() {
const config = {
rootMargin: '50px 50px',
threshold: 0.01
};
function onIntersection(entries) {
entries.forEach(entry => {
if (entry.intersectionRatio > 0) {
observer.unobserve(entry.target);
this.subject.next();
}
});
}
const observer = new IntersectionObserver(onIntersection, config);
observer.observe(this.img.nativeElement);
}
}
No entanto, isso é bastante complicado.
O que podemos fazer é aceitar uma função como scrollObservable
, algo como:
if (!this.scrollObservable) {
const windowTarget = isWindowDefined() ? window : undefined;
scrollObservable = getScrollListener(this.scrollTarget || windowTarget);
} else if (typeof this.scrollObservable === 'function') {
scrollObservable = this.scrollObservable(image, offset) // and maybe more
} else {
scrollObservable = this.scrollObservable.startWith('');
}
Não podemos reescrever o componente acima para:
@Component({
selector: 'intersection-observer',
template: `<img [defaultImage]="defaultImage" [lazyLoad]="image"
[scrollObservable]="startLazyload" offest="50">`,
})
export class IntersectionObserverComponent {
defaultImage = 'https://www.placecage.com/1000/1000';
image = 'https://images.unsplash.com/photo-1467932760935-519284fc87fa?dpr=2&auto=compress,format&fit=crop&w=1199&h=800&q=80';
startLazyload(image, offset) {
Observable.create(observer => {
const intersectionObserver = new IntersectionObserver(entries => {
entries.forEach(entry => {
if (entry.intersectionRatio > 0) {
observer.next();
}
});
}, {
rootMargin: offset ? `${offset}px` : undefined,
threshold: 0.01
});
intersectionObserver.observe(image);
return () => observer.unobserve(image);
});
}
}
Melhor, mas ainda um pouco barulhento, especialmente quando o usuário deseja usar IntersectionObserver
em todas as imagens.
Uma maneira de resolver isso poderia ser passar um Observável padrão em NgModule
:
import { intersectionObserverLazyLoad } from 'some-place';
@NgModule({
declarations: [ AppComponent ],
imports: [ BrowserModule, lazyLoadImage({
observable: intersectionObserverLazyLoad
})],
bootstrap: [ AppComponent ]
})
export class MyAppModule {}
Não podemos reescrever o componente acima para:
@Component({
selector: 'intersection-observer',
template: `<img [defaultImage]="defaultImage" [lazyLoad]="image" offest="50">`,
})
export class IntersectionObserverComponent {
defaultImage = 'https://www.placecage.com/1000/1000';
image = 'https://images.unsplash.com/photo-1467932760935-519284fc87fa?dpr=2&auto=compress,format&fit=crop&w=1199&h=800&q=80';
}
A capacidade de passar funções padrão no NgModule também pode abrir portas para criar funções personalizadas para isVisible
e loadImage
mas isso é uma história posterior.
Resolveria: # 287, # 195, # 286, # 285, # 275, # 259 e mais. A maioria dos problemas é resolvida de outras maneiras, mas seria bom se pudéssemos dar ao usuário mais flexibilidade ao criar um observável.
O que você acha @sapierens , @rimlin?
@tjoskar pelo que entendi, você deseja aprimorar scrollObservable
fornecendo função como opção para scrollObservable
, que retornará Observable, que é responsável por emitir o evento de carregamento de imagem? Se for, eu acho que é uma ideia muito legal!
Mas acho melhor usar objeto em vez de enumerar argumentos:
...
} else if (typeof this.scrollObservable === 'function') {
scrollObservable = this.scrollObservable({
image,
offset
});
} else {
...
fornecer função como opção para scrollObservable, que retornará Observable, que é responsável por emitir o evento de carregamento de imagem
Correto, também posso renomear scrollObservable
mas isso seria uma alteração importante.
eu acho que é melhor usar objeto em vez de enumerar argumentos
Concordar!
Acho que é uma boa ideia, especialmente passar por um observador padrão.
eu acho que é melhor usar objeto em vez de enumerar argumentos
Eu também concordo com isso.
Corrigido no # 365 e na versão 2.1.0
Comentários muito úteis
@tjoskar pelo que entendi, você deseja aprimorar
scrollObservable
fornecendo função como opção parascrollObservable
, que retornará Observable, que é responsável por emitir o evento de carregamento de imagem? Se for, eu acho que é uma ideia muito legal!Mas acho melhor usar objeto em vez de enumerar argumentos: