Svelte官网代码
1 基础
1.1 基础说明
Svelte 是一个构建 web 应用程序的工具。
在 Svelte 中,应用程序由一个或多个 组件(components)构成。组件是一个可重用的、自包含的代码块,它将 HTML、CSS 和 JavaScript 代码封装在一起并写入 .svelte后缀名的文件中。
1.2 添加数据
定义一个name
变量并在标签内将其引用。当然,我们也可以在花括号内放置一些简洁的JavaScript代码。
<script>
let name = 'China';
</script>
<h1>Hello world!</h1>
<h1>Hello { name }!</h1>
<h1>Hello { name.toUpperCase() }!</h1>
1.3 动态属性
花括号不仅可以控制文本,也可以控制元素属性。以img标签为例,src
变量为img的属性,name
变量为img的文本描述。当定义的变量名称与标签的属性名称一致时可将其进行缩写。
<script>
let src = 'tutorial/image.gif';
let name = 'Rick Astley';
</script>
<img src={src} alt="{name} dances.">
<img {src} alt="{name} dances.">
1.4 CSS样式
通过在组件中添加<style>
标签,为标签元素添加CSS样式。
<style>
p {
color: purple;
font-size: 20px;
}
.test {
color: red;
font-size: 20px;
}
</style>
<p>This is a paragraph.</p>
<span class="test">Error Message!</span>
1.5 嵌套组件
当一个组件的内容出现阅读困难时,可以将其分割成较小的组件通过导入的方式使用它们。这里要注意的是要求组件名称首字母大写如<Info/>
。
<script>
import Info from './Info.svelte';
</script>
<h1>Hello, what your name?</h1>
<Info/>
// ==Info.svelte=======================
<h1>Hi,I am LiLan!</h1>
1.6 HTML标签
字符串以纯文本形式插入,也就使一些特殊字符失去的特殊符号的意义。因此提供了特殊标记{@html ...}
帮助特殊符号的实现。
<script>
let string = `this string contains some <strong>HTML!!!</strong>`;
</script>
<p>{string}</p>
1.7 创建一个应用程序
看到这里,其实你就应该清楚的理解了,所谓的应用程序其实就是一个后缀名为.svelte的文件。在项目中也可以称之为页面或者有特定作用的组件,就是一个存放代码的文档。
2 反应性能力
2.1 赋值
如示例中通过赋值的方式更改变量count的值。
<script>
let count = 0;
function handleClick() {
count += 1;
}
</script>
<button on:click={handleClick}>
Clicked {count} {count === 1 ? 'time' : 'times'}
</button>
2.2 声明
可以通过 $: 变量
的方式声明一个变量并对其进行使用。
<script>
let count = 0;
$: doubled = count * 2;
function handleClick() {
count += 1;
}
</script>
<button on:click={handleClick}>
Clicked {count} {count === 1 ? 'time' : 'times'}
</button>
<p>{count} doubled is {doubled}</p>
2.3 语句
我们不仅通过 $:
的方式声明变量,还可以将一组语句组合成一个代码块,甚至是与 if
一起使用。
<script>
let count = 0;
$: if (count >= 10) {
console.log(`the count is ${count}`);
alert(`count is dangerously high!`);
count = 9;
}
function handleClick() {
count += 1;
}
</script>
<button on:click={handleClick}>
Clicked {count} {count === 1 ? 'time' : 'times'}
</button>
2.4 更新数组和对象
由于 Svelte 的反应性是由赋值语句触发的,因此使用数组的诸如 push
和 splice
之类的方法就不会触发自动更新。解决方法是添加一个多余的赋值语句如示例中的 numbers = numbers
。
PS:被更新的变量的名称必须出现在赋值语句的左侧。
<script>
let numbers = [1, 2, 3, 4];
function addNumber() {
// numbers.push(numbers.length + 1); numbers = numbers; // 等同如下
numbers = [...numbers, numbers.length + 1];
}
$: sum = numbers.reduce((t, n) => t + n, 0);
</script>
<p>{numbers.join(' + ')} = {sum}</p>
<button on:click={addNumber}>
Add a number
</button>
3 属性
3.1 变量定义
通过 export
关键字实现属性的流通,即可作为变量在当前组件中使用也支持调用组件对其进行赋值数据传递。
PS:①通过声明实现的变量仅限当前页面使用。
② export 的变量在组件内赋值后,优先级大于外部传入的。例如 Info.svelte
中 设置 answer = 2
,则p标签中取值为2而不是42。
③ 当变量存在初始值,而外层又没有传参,则会直接使用初始值。而定义了却没有传值的属性就是undefined。
<script>
import Info from './Info.svelte';
</script>
<Info answer={42} name={'Li'} age={20} />
<Info />
// ======Info.svelte
<script>
export let answer;
export let name;
export let age, num = 10;
answer = 2;
</script>
<p>print:{name},{answer},{age} years old. The number is {num}. </p>
3.2 属性传递
如果你想给组件传递一个对象属性,且不想逐个指定,那么就可以利用…
语法将其传递给组件。
<script>
import Info from './Info.svelte';
const pkg = {
name: 'svelte',
version: 3,
speed: 'blazing'
};
</script>
<Info name={pkg.name} version={pkg.version} speed={pkg.speed} />
<Info {...pkg}/>
4 逻辑
4.1 If 和 Else
当你想要根据不同的状态显示不同的按钮时,就可以使用if
块对按钮进行控制。当遇到两个相反的控制条件时,除了重复if
块,也可以搭配else
块使用,让逻辑理解更清晰。
PS:同HTML的标签相似的是,逻辑块的标签要以#
号开始,以/
作为结束。例如{#if}
和{/if}
。另一个特点则是作为持续作用的标签 {:else}
要以:
开始。
<script>
let user = { loggedIn: false };
function toggle() {
user.loggedIn = !user.loggedIn;
}
</script>
<button on:click={toggle}>
{#if user.loggedIn} Log out {/if}
{#if !user.loggedIn} Log in {/if}
</button>
{#if user.loggedIn}
<button on:click={toggle}>
Log out
</button>
{/if}
{#if !user.loggedIn}
<button on:click={toggle}>
Log in
</button>
{/if}
<button on:click={toggle}>
{#if user.loggedIn} Log out {:else} Log in {/if}
</button>
{#if user.loggedIn}
<button on:click={toggle}>
Log out
</button>
{:else}
<button on:click={toggle}>
Log in
</button>
{/if}
4.2 Else-if块
将多个条件链接在一起。
<script>
let x = 7;
</script>
{#if x > 10}
<p>{x} is greater than 10</p>
{:else if 5 > x}
<p>{x} is less than 5</p>
{:else}
<p>{x} is between 5 and 10</p>
{/if}
4.3 Each块
遍历数据列表。数组中的对象属性遍历可以表示为{#each cats as cat}
或{#each cats as cat, i}
或{#each cats as { id, name }, i}
,通常看个人习惯。
<script>
let cats = [
{ id: 'J---aiyznGQ', name: 'Keyboard Cat' },
{ id: 'z_AbfPXTKms', name: 'Maru' },
{ id: 'OUtn3pvWmpg', name: 'Henri The Existential Cat' }
];
</script>
<h1>The Famous Cats of YouTube</h1>
<ul>
{#each cats as { id, name }, i}
<li> {i + 1}: {name} </li>
{/each}
</ul>
4.4 Each块中的key属性
each
块中的key值是作为指定一个唯一标识符的作用,只有确保了数据的唯一性,才能保证所操作数据的准确性。通常情况下,当你需要修改each
块中的值时,它将会在 尾端 进行添加或删除条目,而你需要的是从上至下依次开始删除数据,这是key属性就发挥作用了。
<script>
import Thing from './Thing.svelte';
let things = [
{ id: 1, color: '#0d0887' },
{ id: 2, color: '#6a00a8' },
{ id: 3, color: '#b12a90' },
{ id: 4, color: '#e16462' },
{ id: 5, color: '#fca636' }
];
function handleClick() {
things = things.slice(1);
}
</script>
<button on:click={handleClick}>
Remove first thing
</button>
{#each things as thing (thing.id)}
<Thing current={thing.color}/>
{/each}
// ==== Thing.svelte
<script>
export let current;
const initial = current;
</script>
<p>
<span style="background-color: {initial}">initial</span>
<span style="background-color: {current}">current</span>
</p>
<style>
span {
display: inline-block;
padding: 0.2em 0.5em;
margin: 0 0.2em 0.2em 0;
width: 4em;
text-align: center;
border-radius: 0.2em;
color: white;
}
</style>
4.5 Await块
使用await处理promise数据。
<script>
let promise = getRandomNumber();
async function getRandomNumber() {
const res = await fetch(`tutorial/random-number`);
const text = await res.text();
if (res.ok) {
return text;
} else {
throw new Error(text);
}
}
function handleClick() {
promise = getRandomNumber();
}
</script>
<button on:click={handleClick}>
generate random number
</button>
{#await promise}
<p>...waiting</p>
{:then number}
<p>The number is {number}</p>
{:catch error}
<p style="color: red">{error.message}</p>
{/await}
5 事件
5.1 DOM events
使用on:指令监听元素上的任何事件,如下列:
<script>
let m = { x: 0, y: 0 };
function handleMousemove(event) {
m.x = event.clientX;
m.y = event.clientY;
}
</script>
<style>
div { width: 100%; height: 100%; }
</style>
<div on:mousemove={handleMousemove}>
The mouse position is {m.x} x {m.y}
</div>
5.2 Inline handlers
事件内联。
PS:支持不使用引号。
<div on:mousemove="{e => m = { x: e.clientX, y: e.clientY }}">
The mouse position is {m.x} x {m.y}
</div>
5.3 事件修饰符
DOM 事件处理程序具有额外的 修饰符(modifiers) 。
<button on:click|once={handleClick}>
Click me
</button>
所有修饰符列表(支持组合使用):
- preventDefault :调用event.preventDefault() ,在运行处理程序之前调用。比如,对客户端表单处理有用。
- stopPropagation :调用 event.stopPropagation(), 防止事件影响到下一个元素。
- passive : 优化了对 touch/wheel 事件的滚动表现(Svelte 会在合适的地方自动添加滚动条)。
- capture — 在 capture 阶段而不是bubbling 阶段触发事件处理程序 (MDN docs)
- once :运行一次事件处理程序后将其删除。
- self — 仅当 event.target 是其本身时才执行。
5.4 组件事件
createEventDispatcher
必须在首次实例化组件时调用它,—组件本身不支持如 setTimeout
之类的事件回调。 定义一个dispatch
进行连接,进而把组件实例化。
<script>
import Inner from './Inner.svelte';
function handleMessage(event) { console.log(event.detail.text); }
</script>
<Inner on:message={handleMessage}/>
// ==== Inner.svelte
<script>
import { createEventDispatcher } from 'svelte';
const dispatch = createEventDispatcher();
function sayHello() {
dispatch('message', { text: 'Hello!' });
}
</script>
<button on:click={sayHello}> Click to say hello </button>
5.5 事件转发
深层嵌套的组件如需监听事件需在中间件转发该事件。
PS:message没有赋予特定的值得情况下意味着转发所有massage事件。意味着Outer获取到的事件会全部转发给Inner组件。若有指定值,则转发给Inner组件的就是指定的事件。
<script>
import Outer from './Outer.svelte';
function handleMessage(event) {
alert(event.detail.text);
}
</script>
<Outer on:message={handleMessage}/> // ==>中间件
// ====Outer.svelte
// message没有赋予特定的值得情况下意味着转发所有massage事件。
<script>
import Inner from './Inner.svelte';
</script>
<Inner on:message/>
// ====Inner.svelte
<script>
import { createEventDispatcher } from 'svelte';
const dispatch = createEventDispatcher();
function sayHello() {dispatch('message', { text: 'Hello!' });}
</script>
<button on:click={sayHello}>
Click to say hello
</button>
5.6 DOM事件转发
在子组件的元素中添加click事件既可响应上层的事件方法。
<script>
import FancyButton from './FancyButton.svelte';
function handleClick() { alert('clicked'); }
</script>
<FancyButton on:click={handleClick}/>
// ==== FancyButton.svelte
<button on:click> Click me </button>
6 绑定
6.1 Text/Numeric inputs
数据绑定bind:变量名
,input输入框默认type=text
,数值类型type=number
,数值范围type=range
<script>
let name = 'world';
</script>
<input bind:value={name}>
<label>
<input type=number bind:value={a} min=0 max=10>
<input type=range bind:value={a} min=0 max=10>
</label>
<h1>Hello {name}!</h1>
6.2 绑定表单元素之复选框,单复按钮组,文本域,选择框,contenteditable
bind:checked
绑定选择状态,
bind:group
绑定组,radio互斥,checkbox为数组。
multiple
属性会将选择框选择的值从单值变成数组。
PS:绑定的变量名与值定义相同时,可简写。
let yes, value, html;
<input type=checkbox bind:checked={yes}>
<textarea bind:value={value}></textarea>
<textarea bind:value></textarea> // ===> 简写
<div contenteditable="true" bind:innerHTML={html} ></div>
let scoops = 100;
let flavours = ['Mint choc chip'];
let selected;
let menu1 = [100, 80, 90];
let menu2 = [ 'Cookies and cream', 'Mint choc chip', 'Raspberry ripple'];
let questions = [{ id: 1, text: `1+2` },{ id: 2, text: `3+2` },
{ id: 3, text: `5+2` }];
function handleClick() {}
{#each menu1 as num}
<label>
<input type=radio bind:group={scoops} value={num}>
{ num } scoop
</label>
{/each}
{#each menu2 as flavour}
<label>
<input type=checkbox bind:group={flavours} value={flavour}>
{flavour}
</label>
{/each}
<select multiple bind:value={selected} on:change="{handleClick}">
{#each questions as question}
<option value={question}>
{question.text}
</option>
{/each}
</select>
6.3 Each块
class:done
绑定done样式。
<script>
let todos = [
{ done: false, text: 'finish Svelte tutorial' },
{ done: false, text: 'build an app' },
{ done: false, text: 'world domination' }
];
function add() { todos = todos.concat({ done: false, text: '' }); }
function clear() { todos = todos.filter(t => !t.done); }
$: remaining = todos.filter(t => !t.done).length;
</script>
<style>
.done { opacity: 0.4; }
</style>
<h1>Todos</h1>
{#each todos as todo}
<div class:done={todo.done}>
<input type=checkbox bind:checked={todo.done} >
<input placeholder="What needs to be done?" bind:value={todo.text} >
</div>
{/each}
<p>{remaining} remaining</p>
<button on:click={add}> Add new </button>
<button on:click={clear}> Clear completed </button>
6.5 媒体标签
<video
poster="https://sveltejs.github.io/assets/caminandes-llamigos.jpg"
src="https://sveltejs.github.io/assets/caminandes-llamigos.mp4"
on:mousemove={handleMousemove}
on:mousedown={handleMousedown}
bind:currentTime={time}
bind:duration
bind:paused
></video>
//====说明
针对 <audio> 和 <video> 的 6 个readonly 属性绑定 :
duration (readonly) :视频的总时长,以秒为单位。
buffered (readonly) :数组{start, end} 的对象。
seekable (readonly) :同上。
played (readonly) :同上。
seeking (readonly) :布尔值。
ended (readonly) :布尔值。
...以及 4 个双向 绑定:
currentTime :视频中的当前点,以秒为单位。
playbackRate :播放视频的倍速, 1 为 '正常'。
paused :暂停。
volume :音量,0到1之间的值。
<video> 还有多出了具有readonly 属性videoWidth和videoHeight 属性的绑定。
6.6 尺寸
每个块级标签都可以对 clientWidth
、clientHeight
、offsetWidth
以及 offsetHeight
属性进行绑定。
PS:使用display: inline
的标签无法获得尺寸,当然包含有其他有尺寸的标签 (例如<canvas>
)也不会得到正常显示。在这种情况下建议对该标签嵌套一层标签或者直接绑定它的父级。
let w, h, size = 42, text = 'edit me';
<div bind:clientWidth={w} bind:clientHeight={h}>
<span style="font-size: {size}px">{text}</span>
</div>
6.7 This 和组件
this
可以绑定到任何标签 (或组件) 并允许你获取对渲染标签的引用。
let canvas, pin;
<canvas bind:this={canvas} width={32} height={32} ></canvas>
<Keypad bind:value={pin} on:submit={handleSubmit}/>
7 生命周期
7.1 onMount / onDestroy / beforeUpdate / afterUpdate
beforeUpdate
函数实现在DOM渲染完成前执行。需要在组件挂载前运行。
afterUpdate
函数会运行在异步数据加载完成后。
<script>
import { onMount } from 'svelte';
let photos = [];
onMount(async () => {
const res = await fetch(`https://ddd.com/photos?_limit=20`);
photos = await res.json();
});
</script>
<script>
import { onDestroy } from 'svelte';
let seconds = 0;
const interval = setInterval(() => seconds += 1, 1000);
onDestroy(() => clearInterval(interval));
</script>
<script>
let div, autoscroll;
beforeUpdate(() => {
autoscroll = div && (div.offsetHeight + div.scrollTop) >
(div.scrollHeight - 20);
});
afterUpdate(() => {
if (autoscroll) div.scrollTo(0, div.scrollHeight);
});
</script>
7.2 tick
tick
函数随时调用。它返回一个带有resolve方法的 Promise,每当组件pending状态
变化便会立即体现到DOM中 (除非没有pending状态
变化)。
如示例中,若不加await tick();
则选择部分文件按"Tab"键后,文本改变的同时光标会显示在文本的尾部。
<script>
import { tick } from 'svelte';
let text = `Select some text and hit the tab key to toggle uppercase`;
async function handleKeydown(event) {
if (event.which !== 9) return;
event.preventDefault();
const { selectionStart, selectionEnd, value } = this;
const selection = value.slice(selectionStart, selectionEnd);
const replacement = /[a-z]/.test(selection)
? selection.toUpperCase()
: selection.toLowerCase();
text = (
value.slice(0, selectionStart) +
replacement +
value.slice(selectionEnd)
);
await tick();
this.selectionStart = selectionStart;
this.selectionEnd = selectionEnd;
}
</script>
<style>
textarea {
width: 100%;
height: 200px;
}
</style>
<textarea value={text} on:keydown={handleKeydown}></textarea>
8 Stores
Svelte框架自带的状态管理。
8.1 Writable stores
示例如下:
App里面通过别名赋值展示了stores里面定义的变量,并整合了其他三个组件里面对stores定义的变量的操作功能包括增加,减少,重置。
由于此示例中的组件一直被实例化,并未有销毁的操作,容易导致内存溢出。
| App.svelte | decre.svelte | incre.svelte | reset.svelte | stores.js |
| :-----:| :----: | :----: | :----: | :----: |
| <script>
import { count } from './stores.js';
import Incrementer from './incre.svelte';
import Decrementer from './decre.svelte';
import Resetter from './reset.svelte';
let count_value;
const unsubscribe = count.subscribe(value => { count_value = value;});
</script>
<h1>The count is {count_value}</h1>
<Incrementer/> <Decrementer/> <Resetter/> |
<script>
import { count } from './stores.js';
function decrement() { count.update(n => n - 1); };
</script>
<button on:click={decrement}> - </button> |
<script>
import { count } from './stores.js';
function increment() { count.update(n => n + 1); };
</script>
<button on:click={increment}> + </button> |
<script>
import { count } from './stores.js';
function reset() { count.set(0); }
</script>
<button on:click={reset}> reset </button> |
import { writable } from 'svelte/store';
export const count = writable(0);|
8.2 Auto-subscriptions
自动订阅仅适用于在组件的顶级范围中声明(或导入)的存储变量。
任何以$开头的名称都被认为是指一个存储值。
在8.1的示例中,App.svelte增加销毁动作,使用onDestroy周期。更改script的内容
<script>
import { onDestroy } from 'svelte';
import { count } from './stores.js';
import Incrementer from './Incrementer.svelte';
import Decrementer from './Decrementer.svelte';
import Resetter from './Resetter.svelte';
let count_value;
const unsubscribe = count.subscribe(value => { count_value = value; });
onDestroy(unsubscribe);
</script>
自动订阅
<script>
import { count } from './stores.js';
import Incrementer from './incre.svelte';
import Decrementer from './decre.svelte';
import Resetter from './reset.svelte';
</script>
<h1>The count is {$count}</h1>
8.3 只读stores
import { readable } from 'svelte/store'
。
import { readable } from 'svelte/store';
export const time = readable(new Date(), function start(set) {
const interval = setInterval(() => {
set(new Date());
}, 1000);
return function stop() {
clearInterval(interval);
};
});
8.4 stores派生derived
import { readable, derived } from 'svelte/store';
export const elapsed = derived();
8.5 自定义stores
只要一个对象正确的使用 subscribe
,它就是可以称之为store
。
<script>
import { count } from './stores.js';
</script>
<h1>The count is {$count}</h1>
<button on:click={count.increment}>+</button>
<button on:click={count.decrement}>-</button>
<button on:click={count.reset}>reset</button>
// === stores.js
import { writable } from 'svelte/store';
function createCount() {
const { subscribe, set, update } = writable(0);
return {
subscribe,
increment: () => update(n => n + 1),
decrement: () => update(n => n - 1),
reset: () => set(0)
};
}
export const count = createCount();
8.6 绑定Store
store可写入的变量(即具有set
方法),则可以绑定其值,就像可以绑定局部组件状态一样。
绑定值:bind:变量=值
<script>
import { name, greeting } from './stores.js';
</script>
<h1>{$greeting}</h1>
<input bind:value={$name}>
<button on:click="{() => $name += '!'}">
Add exclamation mark!
</button>
// === stores.js
import { writable, derived } from 'svelte/store';
export const name = writable('world');
export const greeting = derived(
name,
$name => `Hello ${$name}!`
);
9 运动
9.1 Tweened (动画)
不加tweened效果的进度效果是段式的,只做数据的更改。而加了tweened的进度效果在数据连接处增加了平滑的效果。
// 不加tweened
import { writable } from 'svelte/store';
const progress = writable(0);
<script>
import { tweened } from 'svelte/motion';
import { cubicOut } from 'svelte/easing';
const progress = tweened(0, { duration: 400, easing: cubicOut });
</script>
<style> progress { display: block; width: 100%; } </style>
<progress value={$progress}></progress>
<button on:click="{() => progress.set(0)}"> 0% </button>
<button on:click="{() => progress.set(0.25)}"> 25% </button>
<button on:click="{() => progress.set(0.5)}"> 50% </button>
<button on:click="{() => progress.set(0.75)}"> 75% </button>
<button on:click="{() => progress.set(1)}"> 100% </button>
9.2 Spring (弹性)
默认属性:stiffness and damping values(刚度和阻尼值)
<script>
import { spring } from 'svelte/motion';
let coords = spring({ x: 50, y: 50 }, { stiffness: 0.1, damping: 0.25});
let size = spring(10);
</script>
<style>
svg { width: 100%; height: 100% }
circle { fill: #ff3e00 }
</style>
<div style="position: absolute; right: 1em;">
<label>
<h3>stiffness ({coords.stiffness})</h3>
<input bind:value={coords.stiffness} type="range" min="0" max="1" step="0.01">
</label>
<label>
<h3>damping ({coords.damping})</h3>
<input bind:value={coords.damping} type="range" min="0" max="1" step="0.01">
</label>
</div>
<svg
on:mousemove="{e => coords.set({ x: e.clientX, y: e.clientY })}"
on:mousedown="{() => size.set(30)}"
on:mouseup="{() => size.set(10)}"
>
<circle cx={$coords.x} cy={$coords.y} r={$size}/>
</svg>
10 过渡
10.1 The transition directive.
<script>
import { fade } from 'svelte/transition';
let visible = true;
</script>
<label> <input type="checkbox" bind:checked={visible}> visible </label>
{#if visible} <p transition:fade> Fades in and out </p> {/if}
10.2 Adding parameters
Note that the transition is reversible — if you toggle the checkbox while the transition is ongoing, it transitions from the current point, rather than the beginning or the end.[转换是可逆的——如果在转换进行时切换复选框,它将从当前点转换,而不是从开始或结束。]
<script>
import { fly } from 'svelte/transition';
let visible = true;
</script>
<label> <input type="checkbox" bind:checked={visible}> visible </label>
{#if visible}
<p transition:fly="{{ y: 200, duration: 2000 }}">Flies in and out</p>
{/if}
10.2 出入
transition
属性可以替换为 in
或out
属性,分别对应过渡效果的入和出,可以指定其中一个,或者指定两个。
<script>
import { fade, fly } from 'svelte/transition';
let visible = true;
</script>
<label> <input type="checkbox" bind:checked={visible}> visible </label>
{#if visible}
<p in:fly="{{ y: 200, duration: 2000 }}" out:fade>
Flies in, fades out
</p>
{/if}
10.3 自定义CSS过渡
<script>
import { fade } from 'svelte/transition';
function fade1(node, {
delay = 0,
duration = 400
}) {
const o = +getComputedStyle(node).opacity;
return {
delay,
duration,
css: t => `opacity: ${t * o}`
};
}
</script>
<label> <input type="checkbox" bind:checked={visible}> visible </label>
{#if visible}
<div class="centered" in:fade1="{{duration: 8000}}" out:fade>
<span>transitions!</span>
</div>
{/if}
10.4 自定义JS过渡
“逐字打印”效果
<script>
let visible = false;
function typewriter(node, { speed = 50 }) {
const valid = (
node.childNodes.length === 1 &&
node.childNodes[0].nodeType === 3
);
if (!valid) {
throw new Error(`This transition only works on elements with a single text node child`);
}
const text = node.textContent;
const duration = text.length * speed;
return {
duration,
tick: t => {
const i = ~~(text.length * t);
node.textContent = text.slice(0, i);
}
};
}
</script>
<label> <input type="checkbox" bind:checked={visible}> visible </label>
{#if visible}
<p in:typewriter>
The quick brown fox jumps over the lazy dog
</p>
{/if}
10.5 过渡事件
Svelte调度监听事件,像监听其他任何DOM事件一样:
<script>
import { fly } from 'svelte/transition';
let visible = true;
let status = 'waiting...';
</script>
<p>status: {status}</p>
<label>
<input type="checkbox" bind:checked={visible}>
visible
</label>
{#if visible}
<p
transition:fly="{{ y: 200, duration: 2000 }}"
on:introstart="{() => status = 'intro started'}"
on:outrostart="{() => status = 'outro started'}"
on:introend="{() => status = 'intro ended'}"
on:outroend="{() => status = 'outro ended'}"
>
Flies in and out
</p>
{/if}
10.6 局部过渡
未完,待续……