
上一讲是动画相关的知识,内容还是很多的,今天来看看动作(Actions)
一、use 指令
Actions
本质上是元素级的生命周期函数。 它们对以下事情很有用:
- 与第三方库的接口
- 延迟加载的图像
- 工具提示
- 添加自定义事件处理程序
例子
App
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
| <script> let showModal = true; </script>
<button on:click={() => (showModal = true)}>Show Modal</button> {#if showModal} <div class="box" on:outclick={() => (showModal = false)}> Click outside me! </div> {/if}
<style> .box { --width: 100px; --height: 100px; position: absolute; width: var(--width); height: var(--height); left: calc(50% - var(--width) / 2); top: calc(50% - var(--height) / 2); display: flex; align-items: center; padding: 8px; border-radius: 4px; background-color: #ff3e00; color: #fff; text-align: center; font-weight: bold; } </style>
|
click_outside.js
1 2 3 4 5 6 7 8 9
| export function clickOutside(node) { return { destroy() { } }; }
|
在上面的这个例子中,我们希望用户点击橙色模态框外部时关闭它。 它有一个用于 outclick
事件的事件处理程序,但它不是原生 DOM
事件。 我们必须自己触发它。 首先,在App
中导入 clickOutside
函数…
1
| import { clickOutside } from "./click_outside.js";
|
然后将其与元素一起使用:
1 2 3
| <div class="box" use:clickOutside on:outclick="{() => (showModal = false)}"> Click outside me! </div>
|
打开 click_outside.js
文件。 与转换函数一样,动作函数接收一个节点(这是应用动作的元素)和一些可选参数,并返回一个动作对象。 该对象可以有一个销毁函数,该函数在元素卸载时调用。
当用户点击橙色框外时,我们希望触发 outclick
事件。 一种可能的实现如下所示:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| export function clickOutside(node) { const handleClick = (event) => { if (!node.contains(event.target)) { node.dispatchEvent(new CustomEvent("outclick")); } };
document.addEventListener("click", handleClick, true);
return { destroy() { document.removeEventListener("click", handleClick, true); }, }; }
|
更新 clickOutside
函数,单击按钮以显示模态框,然后单击外部将其关闭。
REPL
二、附加参数
正如 transition
过渡效果和 animate
动画一样,动作(Action)
也支持附带参数,动作函数会与它所在的元素一起被调用。
例子
App
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| <script> import { longpress } from './longpress.js';
let pressed = false; let duration = 2000; </script>
<label> <input type=range bind:value={duration} max={2000} step={100}> {duration}ms </label>
<button use:longpress on:longpress="{() => pressed = true}" on:mouseenter="{() => pressed = false}" >press and hold</button>
{#if pressed} <p>congratulations, you pressed and held for {duration}ms</p> {/if}
|
longpress.js
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
| export function longpress(node, duration) { let timer; const handleMousedown = () => { timer = setTimeout(() => { node.dispatchEvent( new CustomEvent('longpress') ); }, 500); }; const handleMouseup = () => { clearTimeout(timer) };
node.addEventListener('mousedown', handleMousedown); node.addEventListener('mouseup', handleMouseup);
return { destroy() { node.removeEventListener('mousedown', handleMousedown); node.removeEventListener('mouseup', handleMouseup); } }; }
|
在这例子里,我们使用了一个长按动作,只要用户按下并按住按钮给定的持续时间,就会触发一个具有相同名称的事件。 现在,如果您切换到 longpress.js
文件,您会看到它被硬编码为 500
毫秒。
我们可以更改动作函数以接受持续时间作为第二个参数,并将该 duration
传递给 setTimeout
调用:
1 2 3 4 5 6 7 8 9 10 11 12 13
| export function longpress(node, duration) {
const handleMousedown = () => { timer = setTimeout(() => { node.dispatchEvent( new CustomEvent('longpress') ); }, duration); };
}
|
回到 App.svelte
,我们可以将 duration
值传递给操作:
1
| <button use:longpress={duration}
|
这几乎可以运行的——该事件现在仅在 2 秒后触发。 但是,如果您向下滑动持续时间,仍然需要2秒钟。说白了就是改变滑块并没有更新duration
的值。
为了改变这一点,我们可以在 longpress.js
中添加一个更新方法。 每当参数更改时都会调用它:
1 2 3 4 5 6
| return { update(newDuration) { duration = newDuration; }, };
|
到现在才是action的比较完整的api形式:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
| export function longpress(node, duration) { let timer; const handleMousedown = () => { timer = setTimeout(() => { node.dispatchEvent( new CustomEvent('longpress') ); }, duration); }; const handleMouseup = () => { clearTimeout(timer) };
node.addEventListener('mousedown', handleMousedown); node.addEventListener('mouseup', handleMouseup);
return { update(newDuration) { duration = newDuration; }, destroy() { node.removeEventListener('mousedown', handleMousedown); node.removeEventListener('mouseup', handleMouseup); } }; }
|
如果您需要将多个参数传递给一个动作,请将它们组合成一个对象,如使用:longpress={{duration, spiciness}}
REPL
总结
从action的学习我们知道,use传递的第一个参数就是DOM节点,之前学习绑定
这一章节的时候我们知道可以使用bind:this={el}
来获取DOM节点,action 所不同的是,它有更强的封装性和复用性,将逻辑代码拆分到 JS 文件中供反复应用。
Action 作为一个方法用于标签被创建时调用。调用destroy函数返回表示标签被销毁。
Action 可以含有参数。如果返回的值含有update 方法, 在对 Svelte 标记的内容更新之后,只要update指定的参数发生变更,它都会立即应用变更。
Action 的use指令很好使用,可以用来抽离复用的代码。