fix scroll bindings

pull/1890/head
Rich Harris 7 years ago
parent e23822b5d8
commit 6a398b0b51

@ -1,3 +1,7 @@
<script>
let sy;
</script>
<!-- this binds `sy` to the current value of `window.scrollY` --> <!-- this binds `sy` to the current value of `window.scrollY` -->
<svelte:window bind:scrollY={sy}/> <svelte:window bind:scrollY={sy}/>

@ -112,7 +112,7 @@
<title>Svelte • The magical disappearing UI framework</title> <title>Svelte • The magical disappearing UI framework</title>
</svelte:head> </svelte:head>
<!-- <svelte:window bind:scrollY={sy}/> --> <svelte:window bind:scrollY={sy}/>
<img alt="Svelte logo" class="logo" src="logo.svg" style="transform: translate(0,{sy * 0.2}px)"> <img alt="Svelte logo" class="logo" src="logo.svg" style="transform: translate(0,{sy * 0.2}px)">

@ -21,7 +21,8 @@ self.addEventListener('message', async event => {
}); });
const commonCompilerOptions = { const commonCompilerOptions = {
dev: false dev: false,
css: false
}; };
function compile({ source, options, entry }) { function compile({ source, options, entry }) {

@ -68,9 +68,9 @@ export default class WindowWrapper extends Wrapper {
}); });
}); });
const lock = block.getUniqueName(`window_updating`); const scrolling = block.getUniqueName(`scrolling`);
const clear = block.getUniqueName(`clear_window_updating`); const clear_scrolling = block.getUniqueName(`clear_scrolling`);
const timeout = block.getUniqueName(`window_updating_timeout`); const scrolling_timeout = block.getUniqueName(`scrolling_timeout`);
Object.keys(events).forEach(event => { Object.keys(events).forEach(event => {
const handler_name = block.getUniqueName(`onwindow${event}`); const handler_name = block.getUniqueName(`onwindow${event}`);
@ -78,9 +78,9 @@ export default class WindowWrapper extends Wrapper {
if (event === 'scroll') { if (event === 'scroll') {
// TODO other bidirectional bindings... // TODO other bidirectional bindings...
block.addVariable(lock, 'false'); block.addVariable(scrolling, 'false');
block.addVariable(clear, `function() { ${lock} = false; }`); block.addVariable(clear_scrolling, `() => { ${scrolling} = false }`);
block.addVariable(timeout); block.addVariable(scrolling_timeout);
const condition = [ const condition = [
bindings.scrollX && `"${bindings.scrollX}" in this._state`, bindings.scrollX && `"${bindings.scrollX}" in this._state`,
@ -97,58 +97,61 @@ export default class WindowWrapper extends Wrapper {
${x && `${x} = window.pageXOffset;`} ${x && `${x} = window.pageXOffset;`}
${y && `${y} = window.pageYOffset;`} ${y && `${y} = window.pageYOffset;`}
`); `);
block.event_listeners.push(deindent`
@addListener(window, "${event}", () => {
${scrolling} = true;
clearTimeout(${scrolling_timeout});
${scrolling_timeout} = setTimeout(${clear_scrolling}, 100);
ctx.${handler_name}();
})
`);
} else { } else {
props.forEach(prop => { props.forEach(prop => {
renderer.metaBindings.addLine( renderer.metaBindings.addLine(
`this._state.${prop.name} = window.${prop.value};` `this._state.${prop.name} = window.${prop.value};`
); );
}); });
block.event_listeners.push(deindent`
@addListener(window, "${event}", ctx.${handler_name});
`);
} }
component.declarations.push(handler_name); component.declarations.push(handler_name);
component.template_references.add(handler_name); component.template_references.add(handler_name);
component.partly_hoisted.push(deindent` component.partly_hoisted.push(deindent`
function ${handler_name}() { function ${handler_name}() {
${event === 'scroll' && deindent`
if (${lock}) return;
${lock} = true;
`}
${props.map(prop => `${prop.name} = window.${prop.value}; $$make_dirty('${prop.name}');`)} ${props.map(prop => `${prop.name} = window.${prop.value}; $$make_dirty('${prop.name}');`)}
${event === 'scroll' && `${lock} = false;`}
} }
`); `);
block.builders.init.addBlock(deindent` block.builders.init.addBlock(deindent`
window.addEventListener("${event}", ctx.${handler_name});
@add_render_callback(ctx.${handler_name}); @add_render_callback(ctx.${handler_name});
`); `);
block.builders.destroy.addBlock(deindent`
window.removeEventListener("${event}", ctx.${handler_name});
`);
component.has_reactive_assignments = true; component.has_reactive_assignments = true;
}); });
// special case... might need to abstract this out if we add more special cases // special case... might need to abstract this out if we add more special cases
if (bindings.scrollX || bindings.scrollY) { if (bindings.scrollX || bindings.scrollY) {
block.builders.init.addBlock(deindent` block.builders.update.addBlock(deindent`
#component.$on("state", ({ changed, current }) => { if (${
if (${ [bindings.scrollX, bindings.scrollY].filter(Boolean).map(
[bindings.scrollX, bindings.scrollY].map( b => `changed.${b}`
binding => binding && `changed["${binding}"]` ).join(' || ')
).filter(Boolean).join(' || ') } && !${scrolling}) {
} && !${lock}) { ${scrolling} = true;
${lock} = true; clearTimeout(${scrolling_timeout});
clearTimeout(${timeout}); window.scrollTo(${
window.scrollTo(${ bindings.scrollX ? `current["${bindings.scrollX}"]` : `window.pageXOffset`
bindings.scrollX ? `current["${bindings.scrollX}"]` : `window.pageXOffset` }, ${
}, ${ bindings.scrollY ? `current["${bindings.scrollY}"]` : `window.pageYOffset`
bindings.scrollY ? `current["${bindings.scrollY}"]` : `window.pageYOffset` });
}); ${scrolling_timeout} = setTimeout(${clear_scrolling}, 100);
${timeout} = setTimeout(${clear}, 100); }
}
});
`); `);
} }

@ -1,26 +1,22 @@
/* generated by Svelte vX.Y.Z */ /* generated by Svelte vX.Y.Z */
import { SvelteComponent as SvelteComponent_1, add_render_callback, append, createElement, createText, detachNode, flush, init, insert, run, safe_not_equal, setData } from "svelte/internal"; import { SvelteComponent as SvelteComponent_1, addListener, add_render_callback, append, createElement, createText, detachNode, flush, init, insert, run, safe_not_equal, setData } from "svelte/internal";
function create_fragment(component, ctx) { function create_fragment(component, ctx) {
var window_updating = false, clear_window_updating = function() { window_updating = false; }, window_updating_timeout, p, text0, text1, current; var scrolling = false, clear_scrolling = () => { scrolling = false }, scrolling_timeout, p, text0, text1, current, dispose;
window.addEventListener("scroll", ctx.onwindowscroll);
add_render_callback(ctx.onwindowscroll); add_render_callback(ctx.onwindowscroll);
component.$on("state", ({ changed, current }) => {
if (changed["y"] && !window_updating) {
window_updating = true;
clearTimeout(window_updating_timeout);
window.scrollTo(window.pageXOffset, current["y"]);
window_updating_timeout = setTimeout(clear_window_updating, 100);
}
});
return { return {
c() { c() {
p = createElement("p"); p = createElement("p");
text0 = createText("scrolled to "); text0 = createText("scrolled to ");
text1 = createText(ctx.y); text1 = createText(ctx.y);
dispose = addListener(window, "scroll", () => {
scrolling = true;
clearTimeout(scrolling_timeout);
scrolling_timeout = setTimeout(clear_scrolling, 100);
ctx.onwindowscroll();
});
}, },
m(target, anchor) { m(target, anchor) {
@ -31,6 +27,13 @@ function create_fragment(component, ctx) {
}, },
p(changed, ctx) { p(changed, ctx) {
if (changed.y && !scrolling) {
scrolling = true;
clearTimeout(scrolling_timeout);
window.scrollTo(window.pageXOffset, current["y"]);
scrolling_timeout = setTimeout(clear_scrolling, 100);
}
if (changed.y) { if (changed.y) {
setData(text1, ctx.y); setData(text1, ctx.y);
} }
@ -44,11 +47,11 @@ function create_fragment(component, ctx) {
o: run, o: run,
d(detach) { d(detach) {
window.removeEventListener("scroll", ctx.onwindowscroll);
if (detach) { if (detach) {
detachNode(p); detachNode(p);
} }
dispose();
} }
}; };
} }
@ -57,10 +60,7 @@ function define($$self, $$props, $$make_dirty) {
let { y } = $$props; let { y } = $$props;
function onwindowscroll() { function onwindowscroll() {
if (window_updating) return;
window_updating = true;
y = window.pageYOffset; $$make_dirty('y'); y = window.pageYOffset; $$make_dirty('y');
window_updating = false;
} }
$$self.$$.get = () => ({ y, onwindowscroll }); $$self.$$.get = () => ({ y, onwindowscroll });

Loading…
Cancel
Save