Actions(Svelte的自定义指令)
- 本质上就是元素级别的生命周期,可以类比vue的directives。
- 在元素上使用use:xxx的方式使用一个action,action的实现方式与普通函数类似
- action函数中通常需要return一个deatroy()函数以便在组件卸载时触发相关事件,例如定时器或者事件监听等
- action一般使用dispatchEvent的方式来暴露action.js中的事件,可以在外部使用"on:事件名" 的形式来监听对应抛出的事件
- 如果绑定的action需要传递一些参数可以使用 use:xxx={a,b,c}的形式传递,在action.js中使用直接设置形参就可以了
// app.svelte
<script>
import { spring } from 'svelte/motion';
const coords = spring({ x: 0, y: 0 }, {
stiffness: 0.2,
damping: 0.4
});
function handlePanStart() {
coords.stiffness = coords.damping = 1;
}
function handlePanMove(event) {
coords.update($coords => ({
x: $coords.x + event.detail.dx,
y: $coords.y + event.detail.dy
}));
}
function handlePanEnd(event) {
coords.stiffness = 0.2;
coords.damping = 0.4;
coords.set({ x: 0, y: 0 });
}
</script>
<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);
border-radius: 4px;
background-color: #ff3e00;
cursor: move;
}
</style>
<div class="box"
on:panstart={handlePanStart}
on:panmove={handlePanMove}
on:panend={handlePanEnd}
style="transform:
translate({$coords.x}px,{$coords.y}px)
rotate({$coords.x * 0.2}deg)"
></div>
// pannable.js
export function pannable(node) {
let x;
let y;
function handleMousedown(event) {
x = event.clientX;
y = event.clientY;
node.dispatchEvent(new CustomEvent('panstart', {
detail: { x, y }
}));
window.addEventListener('mousemove', handleMousemove);
window.addEventListener('mouseup', handleMouseup);
}
function handleMousemove(event) {
const dx = event.clientX - x;
const dy = event.clientY - y;
x = event.clientX;
y = event.clientY;
node.dispatchEvent(new CustomEvent('panmove', {
detail: { x, y, dx, dy }
}));
}
function handleMouseup(event) {
x = event.clientX;
y = event.clientY;
node.dispatchEvent(new CustomEvent('panend', {
detail: { x, y }
}));
window.removeEventListener('mousemove', handleMousemove);
window.removeEventListener('mouseup', handleMouseup);
}
node.addEventListener('mousedown', handleMousedown);
return {
destroy() {
node.removeEventListener('mousedown',handleMousedown);
}
};
}
Classes(类比vue的class绑定)
- 可以使用js表达式动态设置设置一个class
<button
class="{current === 'foo' ? 'selected' : ''}"
on:click="{() => current = 'foo'}"
>foo</button>
<button
class:selected="{current === 'foo'}"
on:click="{() => current = 'foo'}"
>foo</button>
<div class:big={big}>
<!-- ... -->
</div>
// 可以简写为:
<div class:big>
<!-- ... -->
</div>
组件Slot插槽
- slot是一个插槽出口,标记了父元素提供的插槽内容应该被渲染的位置
- Svelte插槽与vue插槽一样也有匿名插槽与具名插槽
- 匿名插槽会将组件内容渲染到默认位置,具名插槽会将在指定的位置替换内容
- $$slots是一个包含父组件左右插槽key值的对象,如果父组件中的具名插槽内容为空则不会有该插槽的入口,可以用来判断插槽内容是否存在。
- 可以使用 let:a={a} 来暴露组件内的内容,在{}中可以将插槽传递过来的参数重新命名使用。
// app.svelte
<script>
import ContactCard from './ContactCard.svelte';
</script>
<ContactCard>
<span slot="name">
P. Sherman
</span>
<span slot="address">
42 Wallaby Way<br>
Sydney
</span>
</ContactCard>
// contactCard.svelte
<style>
.contact-card {
width: 300px;
border: 1px solid #aaa;
border-radius: 2px;
box-shadow: 2px 2px 8px rgba(0,0,0,0.1);
padding: 1em;
}
h2 {
padding: 0 0 0.2em 0;
margin: 0 0 1em 0;
border-bottom: 1px solid #ff3e00
}
.address, .email {
padding: 0 0 0 1.5em;
background: 0 0 no-repeat;
background-size: 20px 20px;
margin: 0 0 0.5em 0;
line-height: 1.2;
}
.address { background-image: url(tutorial/icons/map-marker.svg) }
.email { background-image: url(tutorial/icons/email.svg) }
.missing { color: #999 }
</style>
<article class="contact-card">
<h2>
<slot name="name">
<span class="missing">Unknown name</span>
</slot>
</h2>
<div class="address">
<slot name="address">
<span class="missing">Unknown address</span>
</slot>
</div>
<div class="email">
<slot name="email">
<span class="missing">Unknown email</span>
</slot>
</div>
</article>
context API
- setContext(key,context)
- getContext(key)
- contextAPI提供了一个机制可以让组件实现在不使用props及各种繁杂的events下实现互相通信
待续。。。。。