masonry.js 1.7 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152
  1. import { clamp } from "./utils.js";
  2. export function setupMasonries(options = {}, selector = ".masonry") {
  3. options = {
  4. minColumnWidth: 300,
  5. maxColumns: 6,
  6. ...options
  7. };
  8. const masonryContainers = document.querySelectorAll(selector);
  9. for (let i = 0; i < masonryContainers.length; i++) {
  10. const container = masonryContainers[i];
  11. const items = Array.from(container.children);
  12. let previousColumnsCount = 0;
  13. const render = function() {
  14. const columnsCount = clamp(
  15. Math.floor(container.offsetWidth / options.minColumnWidth),
  16. 1,
  17. Math.min(options.maxColumns, items.length)
  18. );
  19. if (columnsCount === previousColumnsCount) {
  20. return;
  21. } else {
  22. container.textContent = "";
  23. previousColumnsCount = columnsCount;
  24. }
  25. const columnsFragment = document.createDocumentFragment();
  26. for (let i = 0; i < columnsCount; i++) {
  27. const column = document.createElement("div");
  28. column.className = "masonry-column";
  29. columnsFragment.append(column);
  30. }
  31. // poor man's masonry
  32. // TODO: add an option that allows placing items in the
  33. // shortest column instead of iterating the columns in order
  34. for (let i = 0; i < items.length; i++) {
  35. columnsFragment.children[i % columnsCount].appendChild(items[i]);
  36. }
  37. container.append(columnsFragment);
  38. };
  39. const observer = new ResizeObserver(() => requestAnimationFrame(render));
  40. observer.observe(container);
  41. }
  42. }