Masonry: use MutationObserver instead

- originally tricks with the reactive system
This commit is contained in:
thislight 2024-11-23 13:00:36 +08:00
parent 18fa2810c4
commit 487de9237b
No known key found for this signature in database
GPG key ID: FCFE5192241CCD4E

View file

@ -5,10 +5,8 @@ import {
type Ref, type Ref,
createRenderEffect, createRenderEffect,
onCleanup, onCleanup,
children,
createEffect, createEffect,
createSignal, createSignal,
onMount,
} from "solid-js"; } from "solid-js";
import { Dynamic, type DynamicProps } from "solid-js/web"; import { Dynamic, type DynamicProps } from "solid-js/web";
import MasonryLayout from "masonry-layout"; import MasonryLayout from "masonry-layout";
@ -20,7 +18,6 @@ type MasonryContainer =
| Component<{ | Component<{
ref?: Ref<Element>; ref?: Ref<Element>;
class?: string; class?: string;
children?: JSX.Element;
}>; }>;
type ElementOf<T extends MasonryContainer> = type ElementOf<T extends MasonryContainer> =
@ -37,7 +34,10 @@ function forwardRef<T>(value: T, ref?: Ref<T>) {
(ref as (value: T) => void)(value); (ref as (value: T) => void)(value);
} }
function createMasonry(element: Element, options: () => MasonryLayout.Options) { function createCompatMasonry(
element: Element,
options: () => MasonryLayout.Options,
) {
const layout = new MasonryLayout(element, { const layout = new MasonryLayout(element, {
initLayout: false, initLayout: false,
}); });
@ -46,11 +46,21 @@ function createMasonry(element: Element, options: () => MasonryLayout.Options) {
const size = createElementSize(element); const size = createElementSize(element);
const treeMutObx = new MutationObserver(() => {
layout.reloadItems?.();
});
onCleanup(() => treeMutObx.disconnect());
createRenderEffect(() => { createRenderEffect(() => {
const opts = options(); const opts = options();
layout.option?.(opts); layout.option?.(opts);
}); });
createRenderEffect(() => {
treeMutObx.observe(element, { childList: true });
});
createRenderEffect(() => { createRenderEffect(() => {
const width = size.width; // only tracking width const width = size.width; // only tracking width
layout.layout?.(); layout.layout?.();
@ -61,8 +71,6 @@ function createMasonry(element: Element, options: () => MasonryLayout.Options) {
layout.layout?.(); layout.layout?.();
}); });
} }
return layout;
} }
const supportsCSSMasonryLayout = /* @__PURE__ */ CSS.supports( const supportsCSSMasonryLayout = /* @__PURE__ */ CSS.supports(
@ -85,9 +93,7 @@ if (import.meta.env.VITE_PLATFROM_MASONRY_ALWAYS_COMPAT) {
function MasonryCompat<T extends MasonryContainer>( function MasonryCompat<T extends MasonryContainer>(
oprops: DynamicProps<T> & { class?: string }, oprops: DynamicProps<T> & { class?: string },
) { ) {
const [props, rest] = splitProps(oprops, ["ref", "children", "class"]); const [props, rest] = splitProps(oprops, ["ref", "class"]);
const childrenComponents = children(() => props.children);
return ( return (
<Dynamic <Dynamic
@ -96,7 +102,7 @@ function MasonryCompat<T extends MasonryContainer>(
const [columnGap, setColumnGap] = createSignal<number>(); const [columnGap, setColumnGap] = createSignal<number>();
const layout = createMasonry(element, () => { createCompatMasonry(element, () => {
return { return {
gutter: columnGap(), gutter: columnGap(),
}; };
@ -115,18 +121,9 @@ function MasonryCompat<T extends MasonryContainer>(
setColumnGap(Number(colGap.slice(0, colGap.length - 2))); setColumnGap(Number(colGap.slice(0, colGap.length - 2)));
} }
}); });
createRenderEffect(() => {
childrenComponents(); // just tracks
setTimeout(() => {
layout.reloadItems?.();
layout.layout?.();
}, 0);
});
}} }}
class={`Masonry CompatMasonry ${props.class || ""}`} class={`Masonry CompatMasonry ${props.class || ""}`}
{...rest} {...rest}
children={childrenComponents}
/> />
); );
} }