自定义指令
use:pannable 自定义指令给指定元素绑定拖动事件
// 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);
}
};
}
<script>
import { spring } from 'svelte/motion';
import { pannable } from './pannable.js';
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"
use:pannable
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>
添加指令参数
// longpress.js
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);
}
};
}
// app.svelte
<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={duration}
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}
class 样式绑定
class="{current === 'foo' ? 'active' : ''}"
简写 class:active="{current === 'bar'}"
<script>
let current = 'foo';
</script>
<style>
button {
display: block;
}
.active {
background-color: #ff3e00;
color: white;
}
</style>
<button
class="{current === 'foo' ? 'active' : ''}"
on:click="{() => current = 'foo'}"
>foo</button>
<button
class:active="{current === 'bar'}"
on:click="{() => current = 'bar'}"
>bar</button>
<button
class="{current === 'baz' ? 'active' : ''}"
on:click="{() => current = 'baz'}"
>baz</button>
绑定变量
<script>
let big = false;
</script>
<style>
.big {
font-size: 4em;
}
</style>
<label>
<input type=checkbox bind:checked={big}>
big
</label>
<div class:big={big}>
some {big ? 'big' : 'small'} text
</div>
<div class:big> // 简写
some {big ? 'big' : 'small'} text
</div>
Slot 插槽代码片段
类似vue 的功能
// Box.svelte
<style>
.box {
width: 300px;
border: 1px solid #aaa;
border-radius: 2px;
box-shadow: 2px 2px 8px rgba(0,0,0,0.1);
padding: 1em;
margin: 0 0 1em 0;
}
</style>
<div class="box">
<slot></slot>
</div>
// app.svelte
<script>
import Box from './Box.svelte';
</script>
<Box>
nihao
</Box>
slot默认值
<div class="box">
<slot>
<em>no content was provided</em>
</slot>
</div>
命名的Slot
<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>
<ContactCard>
<span slot="name">
P. Sherman
</span>
<span slot="address">
42 Wallaby Way<br>
Sydney
</span>
</ContactCard>
slots Props 插槽的属性
// Hovering.js
<script>
let hovering;
function enter() {
hovering = true;
}
function leave() {
hovering = false;
}
</script>
<div on:mouseenter={enter} on:mouseleave={leave}>
<slot hovering={hovering}></slot>
</div>
// app.svelte
<script>
import Hoverable from './Hoverable.svelte';
</script>
<style>
div {
padding: 1em;
margin: 0 0 1em 0;
background-color: #eee;
}
.active {
background-color: #ff3e00;
color: white;
}
</style>
<Hoverable let:hovering={active}>
<div class:active>
{#if active}
<p>I am being hovered upon.</p>
{:else}
<p>Hover over me!</p>
{/if}
</div>
</Hoverable>
Context 上下文的API
setContent(key,context)或getContent(key)
import { onMount, setContext } from 'svelte';
import { mapbox, key } from './mapbox.js';
setContext(key, {
getMap: () => map
});
import { getContext } from 'svelte';
import { mapbox, key } from './mapbox.js';
const { getMap } = getContext(key);
const map = getMap();
最好有个key 管理的模块
const key = {};
与store 进行对比
context是只读,并且只作用与父组件和子孙节点
store 支持读写。可以在任何上下文中使用。
<svelte:self />
用于递归组件
// Folder.svelte
<script>
import File from './File.svelte';
export let expanded = false;
export let name;
export let files;
function toggle() {
expanded = !expanded;
}
</script>
<style>
span {
padding: 0 0 0 1.5em;
background: url(tutorial/icons/folder.svg) 0 0.1em no-repeat;
background-size: 1em 1em;
font-weight: bold;
cursor: pointer;
}
.expanded {
background-image: url(tutorial/icons/folder-open.svg);
}
ul {
padding: 0.2em 0 0 0.5em;
margin: 0 0 0 0.5em;
list-style: none;
border-left: 1px solid #eee;
}
li {
padding: 0.2em 0;
}
</style>
<span class:expanded on:click={toggle}>{name}</span>
{#if expanded}
<ul>
{#each files as file}
<li>
{#if file.type === 'folder'}
<svelte:self {...file}/>
{:else}
<File {...file}/>
{/if}
</li>
{/each}
</ul>
{/if}
<script>
export let name;
$: type = name.slice(name.lastIndexOf('.') + 1);
</script>
<style>
span {
padding: 0 0 0 1.5em;
background: 0 0.1em no-repeat;
background-size: 1em 1em;
}
</style>
<span style="background-image: url(tutorial/icons/{type}.svg)">{name}</span>
<script>
import Folder from './Folder.svelte';
let root = [
{
type: 'folder',
name: 'Important work stuff',
files: [
{ type: 'file', name: 'quarterly-results.xlsx' }
]
},
{
type: 'folder',
name: 'Animal GIFs',
files: [
{
type: 'folder',
name: 'Dogs',
files: [
{ type: 'file', name: 'treadmill.gif' },
{ type: 'file', name: 'rope-jumping.gif' }
]
},
{
type: 'folder',
name: 'Goats',
files: [
{ type: 'file', name: 'parkour.gif' },
{ type: 'file', name: 'rampage.gif' }
]
},
{ type: 'file', name: 'cat-roomba.gif' },
{ type: 'file', name: 'duck-shuffle.gif' },
{ type: 'file', name: 'monkey-on-a-pig.gif' }
]
},
{ type: 'file', name: 'TODO.md' }
];
</script>
<Folder name="Home" files={root} expanded/>
<svelte:component />
动态组/件 类似vue的<component/> 组件
{#if selected.color === 'red'}
<RedThing/>
{:else if selected.color === 'green'}
<GreenThing/>
{:else if selected.color === 'blue'}
<BlueThing/>
{/if}
// 效果等同于
<svelte:component this={selected.component}/>
<svelte:window />
给window全局对象添加事件
<svelte:window on:keydown={handleKeydown}/>
可以bind的属性
- innerWidth(只读)
- innerHeight(只读)
- outerWidth(只读)
- outerHeight (只读)
- scrollX
- scrollY
- online :window.navigator.onLine的简称 (只读)
<svelte:body />
操作document.body
<svelte:body
on:mouseenter={handleMouseenter}
on:mouseleave={handleMouseleave}
/>
<svelte:head />
操作<head>
<svelte:head>
<link rel="stylesheet" href="tutorial/dark-theme.css">
</svelte:head>
<svelte:options>
允许您指定编译器选项
<svelte:options immutable={true}/>
immutable={true}
—您从不使用可变数据,因此编译器可以执行简单的引用相等性检查以确定值是否已更改immutable={false}
—默认值。Svelte对于可变对象是否已更改将更加保守accessors={true}
-为组件的props添加getter和setteraccessors={false}
—默认namespace="..."
—最常使用此组件的名称空间"svg"
tag="..."
—将此组件编译为自定义元素时使用的名称
组件代码共享区域
<script context="module"> 通过标签组件公共区域
<script context="module">
let current;
</script>
组件模块导出
<script context="module">
const elements = new Set();
export function stopAll() {
elements.forEach(element => {
element.pause();
});
}
</script>
<script>
import AudioPlayer, { stopAll } from './AudioPlayer.svelte';
</script>
<button on:click={stopAll}>
stop all audio
</button>
Debugging
会触发浏览器开发工具的调试功能
{@debug user}
<h1>Hello {user.firstname}!</h1>