Skip to content

Instantly share code, notes, and snippets.

@minikomi
Last active July 14, 2018 21:30
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save minikomi/a761e8eaf2f15bf0b1caf89cde19ecd8 to your computer and use it in GitHub Desktop.
Save minikomi/a761e8eaf2f15bf0b1caf89cde19ecd8 to your computer and use it in GitHub Desktop.
Lazy loading image for reagent
(ns frontend.lazy
(:require [reagent.core :as r]
[goog.dom :as gdom]
[goog.events.EventType :as event-type]
[goog.events :as events])
(:import goog.async.Throttle))
(defonce initialized-lazy-load (atom false))
(defonce lazy-els (atom {}))
(defonce lazy-loaded (r/atom #{}))
(defn is-scrolled-into-view [el]
(let [el-top (.-top (.getBoundingClientRect el))]
(and (<= 0 el-top)
(>= (.-innerHeight js/window) el-top))))
(defn init-scroll-listener [f]
(let [thr (Throttle. #(f (.-y (gdom/getDocumentScroll))) 300)]
(events/listen js/window event-type/SCROLL #(.fire thr)))
(f (.-y (gdom/getDocumentScroll))))
(defn unregister-lazy-load [el]
(swap! lazy-els dissoc el))
(defn check-offsets [_]
(doseq [[el data] @lazy-els]
(when (is-scrolled-into-view el)
(set! (.-src (:img-obj data)) (:src data))
(unregister-lazy-load el))))
(defn register-lazy-load [src el]
(when-not @initialized-lazy-load
(reset! initialized-lazy-load true)
(init-scroll-listener check-offsets))
(when-not (@lazy-loaded src)
(let [img-obj (js/Image.)]
(set! (.-onload img-obj)
(fn [_]
(swap! lazy-loaded conj src)))
(if (is-scrolled-into-view el)
(set! (.-src img-obj) src)
(swap! lazy-els assoc el {:img-obj img-obj :src src})))))
(defn -mount-or-update [this _]
(register-lazy-load (:src (r/props this)) (r/dom-node this)))
(defn lazy-loading-image [{:keys [wrapper-class src alt]}]
(r/create-class
{:component-did-mount
-mount-or-update
:component-did-update
-mount-or-update
:component-will-unmount
(fn [this _]
(unregister-lazy-load (r/dom-node this)))
:reagent-render
(fn [{:keys [wrapper-class src alt]}]
[:span.lazy-wrapper
{:class wrapper-class}
(if-not (get @lazy-loaded src)
[:span.loader]
[:img.loaded {:src src :alt alt}])])}))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment