mirror of
https://github.com/sveltejs/svelte.git
synced 2024-12-01 17:30:59 +01:00
implement event modifiers
This commit is contained in:
parent
8ec02b336d
commit
82b1b75afe
@ -595,12 +595,7 @@ export default class Element extends Node {
|
||||
|
||||
if (modifier === 'passive') {
|
||||
if (passiveEvents.has(handler.name)) {
|
||||
const usesEvent = (
|
||||
handler.callee.name === 'event' ||
|
||||
handler.args.some(x => x.usesEvent)
|
||||
);
|
||||
|
||||
if (!usesEvent) {
|
||||
if (!handler.usesEventObject) {
|
||||
component.warn(handler, {
|
||||
code: 'redundant-event-modifier',
|
||||
message: `Touch event handlers that don't use the 'event' object are passive by default`
|
||||
@ -623,6 +618,11 @@ export default class Element extends Node {
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
if (passiveEvents.has(handler.name) && !handler.usesEventObject) {
|
||||
// touch/wheel events should be passive by default
|
||||
handler.modifiers.add('passive');
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -16,6 +16,7 @@ export default class EventHandler extends Node {
|
||||
|
||||
usesComponent: boolean;
|
||||
usesContext: boolean;
|
||||
usesEventObject: boolean;
|
||||
isCustomEvent: boolean;
|
||||
shouldHoist: boolean;
|
||||
|
||||
@ -42,11 +43,13 @@ export default class EventHandler extends Node {
|
||||
|
||||
this.usesComponent = !validCalleeObjects.has(this.callee.name);
|
||||
this.usesContext = false;
|
||||
this.usesEventObject = this.callee.name === 'event';
|
||||
|
||||
this.args = info.expression.arguments.map(param => {
|
||||
const expression = new Expression(component, this, scope, param);
|
||||
addToSet(this.dependencies, expression.dependencies);
|
||||
if (expression.usesContext) this.usesContext = true;
|
||||
if (expression.usesEvent) this.usesEventObject = true;
|
||||
return expression;
|
||||
});
|
||||
|
||||
@ -58,6 +61,7 @@ export default class EventHandler extends Node {
|
||||
this.args = null;
|
||||
this.usesComponent = true;
|
||||
this.usesContext = false;
|
||||
this.usesEventObject = true;
|
||||
|
||||
this.snippet = null; // TODO handle shorthand events here?
|
||||
}
|
||||
|
@ -649,8 +649,13 @@ export default class ElementWrapper extends Wrapper {
|
||||
${handlerName}.destroy();
|
||||
`);
|
||||
} else {
|
||||
const modifiers = [];
|
||||
if (handler.modifiers.has('preventDefault')) modifiers.push('event.preventDefault();');
|
||||
if (handler.modifiers.has('stopPropagation')) modifiers.push('event.stopPropagation();');
|
||||
|
||||
const handlerFunction = deindent`
|
||||
function ${handlerName}(event) {
|
||||
${modifiers}
|
||||
${handlerBody}
|
||||
}
|
||||
`;
|
||||
@ -661,13 +666,28 @@ export default class ElementWrapper extends Wrapper {
|
||||
block.builders.init.addBlock(handlerFunction);
|
||||
}
|
||||
|
||||
block.builders.hydrate.addLine(
|
||||
`@addListener(${this.var}, "${handler.name}", ${handlerName});`
|
||||
);
|
||||
const opts = ['passive', 'once', 'capture'].filter(mod => handler.modifiers.has(mod));
|
||||
if (opts.length) {
|
||||
const optString = (opts.length === 1 && opts[0] === 'capture')
|
||||
? 'true'
|
||||
: `{ ${opts.map(opt => `${opt}: true`).join(', ')} }`;
|
||||
|
||||
block.builders.destroy.addLine(
|
||||
`@removeListener(${this.var}, "${handler.name}", ${handlerName});`
|
||||
);
|
||||
block.builders.hydrate.addLine(
|
||||
`@addListener(${this.var}, "${handler.name}", ${handlerName}, ${optString});`
|
||||
);
|
||||
|
||||
block.builders.destroy.addLine(
|
||||
`@removeListener(${this.var}, "${handler.name}", ${handlerName}, ${optString});`
|
||||
);
|
||||
} else {
|
||||
block.builders.hydrate.addLine(
|
||||
`@addListener(${this.var}, "${handler.name}", ${handlerName});`
|
||||
);
|
||||
|
||||
block.builders.destroy.addLine(
|
||||
`@removeListener(${this.var}, "${handler.name}", ${handlerName});`
|
||||
);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
91
test/js/samples/event-modifiers/expected.js
Normal file
91
test/js/samples/event-modifiers/expected.js
Normal file
@ -0,0 +1,91 @@
|
||||
/* generated by Svelte vX.Y.Z */
|
||||
import { addListener, append, assign, createElement, createText, detachNode, init, insert, noop, proto, removeListener } from "svelte/shared.js";
|
||||
|
||||
var methods = {
|
||||
handleTouchstart() {
|
||||
// ...
|
||||
},
|
||||
|
||||
handleClick() {
|
||||
// ...
|
||||
}
|
||||
};
|
||||
|
||||
function create_main_fragment(component, ctx) {
|
||||
var div, button0, text1, button1, text3, button2;
|
||||
|
||||
function click_handler(event) {
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
component.handleClick();
|
||||
}
|
||||
|
||||
function click_handler_1(event) {
|
||||
component.handleClick();
|
||||
}
|
||||
|
||||
function click_handler_2(event) {
|
||||
component.handleClick();
|
||||
}
|
||||
|
||||
function touchstart_handler(event) {
|
||||
component.handleTouchstart();
|
||||
}
|
||||
|
||||
return {
|
||||
c() {
|
||||
div = createElement("div");
|
||||
button0 = createElement("button");
|
||||
button0.textContent = "click me";
|
||||
text1 = createText("\n\t");
|
||||
button1 = createElement("button");
|
||||
button1.textContent = "or me";
|
||||
text3 = createText("\n\t");
|
||||
button2 = createElement("button");
|
||||
button2.textContent = "or me!";
|
||||
addListener(button0, "click", click_handler);
|
||||
addListener(button1, "click", click_handler_1, { once: true, capture: true });
|
||||
addListener(button2, "click", click_handler_2, true);
|
||||
addListener(div, "touchstart", touchstart_handler, { passive: true });
|
||||
},
|
||||
|
||||
m(target, anchor) {
|
||||
insert(target, div, anchor);
|
||||
append(div, button0);
|
||||
append(div, text1);
|
||||
append(div, button1);
|
||||
append(div, text3);
|
||||
append(div, button2);
|
||||
},
|
||||
|
||||
p: noop,
|
||||
|
||||
d(detach) {
|
||||
if (detach) {
|
||||
detachNode(div);
|
||||
}
|
||||
|
||||
removeListener(button0, "click", click_handler);
|
||||
removeListener(button1, "click", click_handler_1, { once: true, capture: true });
|
||||
removeListener(button2, "click", click_handler_2, true);
|
||||
removeListener(div, "touchstart", touchstart_handler, { passive: true });
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
function SvelteComponent(options) {
|
||||
init(this, options);
|
||||
this._state = assign({}, options.data);
|
||||
this._intro = true;
|
||||
|
||||
this._fragment = create_main_fragment(this, this._state);
|
||||
|
||||
if (options.target) {
|
||||
this._fragment.c();
|
||||
this._mount(options.target, options.anchor);
|
||||
}
|
||||
}
|
||||
|
||||
assign(SvelteComponent.prototype, proto);
|
||||
assign(SvelteComponent.prototype, methods);
|
||||
export default SvelteComponent;
|
19
test/js/samples/event-modifiers/input.html
Normal file
19
test/js/samples/event-modifiers/input.html
Normal file
@ -0,0 +1,19 @@
|
||||
<div on:touchstart="handleTouchstart()">
|
||||
<button on:click|stopPropagation|preventDefault="handleClick()">click me</button>
|
||||
<button on:click|once|capture="handleClick()">or me</button>
|
||||
<button on:click|capture="handleClick()">or me!</button>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
methods: {
|
||||
handleTouchstart() {
|
||||
// ...
|
||||
},
|
||||
|
||||
handleClick() {
|
||||
// ...
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
@ -15,6 +15,7 @@
|
||||
"end": 45,
|
||||
"type": "EventHandler",
|
||||
"name": "click",
|
||||
"modifiers": [],
|
||||
"expression": {
|
||||
"type": "CallExpression",
|
||||
"start": 18,
|
||||
|
Loading…
Reference in New Issue
Block a user