Svelte教程笔记
这是我在学习Svelte 教程时记下的笔记。
或许对某些人有用,但首先,这是写给自己的笔记 :)
1. 引言
创建一个新的 Svelte 项目
https://svelte.dev/blog/svelte-for-new-developers
npx degit sveltejs/template new-project-name
VS Code
安装以下扩展程序
2. 反应活性
a. 作业
https://svelte.dev/tutorial/reactive-assignments
on:click on看起来像一个指令,它click是事件名称。
状态是响应式的,script标签下的闭包会在状态值改变时重新渲染。
<script>
let count = 0;
function handleClick() {
count++;
}
</script>
<button on:click={handleClick}>
Clicked {count} {count === 1 ? 'time' : 'times'}
</button>
b. 声明
https://svelte.dev/tutorial/reactive-declarations
计算/派生状态需要使用特殊语法进行声明$:。
let count = 0;
$: doubled = count * 2;
当需要多次访问时非常有用。您可以改用其他方式,
而不是到处都用。{count * 2}{doubled}
c. 声明
https://svelte.dev/tutorial/reactive-statements
$:不仅限于表达式(响应式值),也包括语句。
<script>
let count = 0;
$: console.log(`the count is {count}`);
$: if (count >= 10) {
alert(`count is too high!`)
count = 9;
}
function handleClick() {
count += 1;
}
</script>
<button on:click={handleClick}>
Clicked {count} {count === 1 ? 'time' : 'times'}
</button>
d. 更新数组和对象
https://svelte.dev/tutorial/updating-arrays-and-objects
一个简单的经验法则:更新后的变量名必须出现在赋值语句的左侧。
或者像在 React 中那样,赋予一个新的引用。
// Instead of this
function addNumber() {
numbers.push(numbers.length + 1);
numbers = numbers
}
// Do this
function addNumber() {
numbers = [...numbers, numbers.length + 1]
}
3.道具
a. 声明属性
https://svelte.dev/tutorial/declaring-props
用于将数据传递给其他组件。这与 React 中的概念相同。
在 React 中,组件接收数据props,但在 Svelte 中,你需要导出变量。
Nested.svelte
<script>
export let answer;
</script>
<p>The answer is {answer}</p>
App.svelte导入Nested组件并按如下方式传递答案。
<script>
import Nested from './Nested.svelte'
</script>
<Nested answer={42}>
b. 默认值
https://svelte.dev/tutorial/default-values
您可以在声明期间设置默认属性值。
Nested.svelte
<script>
export let answer = 'is unknown!';
</script>
<p>The answer is {answer}</p>
如果没有向Nestedlike传递 props <Nested>,则使用默认值。
c. 展开道具
https://svelte.dev/tutorial/spread-props
就像在 React 中一样,你可以使用对象展开运算符传递多个 props。
<Info {...pkg}>
4. 逻辑
a. 如果块
https://svelte.dev/tutorial/if-blocks
该标记仅在 Svelte 中可用,在 HTML 中不可用。
{#if user.loggedIn}
<button on:click={toggle}>Log Out</button>
{/if}
{#if !user.loggedIn}
<button on:click={toggle}>Log In</button>
{/if}
b. 否则会阻塞
https://svelte.dev/tutorial/else-blocks
互斥条件可以使用{:else}块
{#if user.loggedIn}
<button on:click={toggle}>Log Out</button>
{:else}
<button on:click={toggle}>Log In</button>
{/if}
c. 否则语句块
https://svelte.dev/tutorial/else-if-blocks
可以通过以下方式检查其他条件{:else if condition}
{#if x > 10}
<p>{x} is greater than 10!</p>
{:else if x < 5 }
<p>{x} is less than 5
{:else}
<p>{x} is 'teween 5 and 10</p>
{/if}
d. 每个方块
https://svelte.dev/tutorial/each-blocks
你可以使用以下方式迭代可迭代对象{#each iterable as alias, index}
<ul>
{#each cats as cat, index}
<li>{index + 1}th cat is {cat.name}</li>
{/each}
</ul>
别名可以像这样解构:
{#each cats as {name, id, age}, index}
<li>{index + 1}th cat is {name} and is {age} years old</li>
{/each}
e. 为每个块添加键
https://svelte.dev/tutorial/keyed-each-blocks
在 React 中,创建可迭代元素需要key为每个元素创建一个迭代器。
例如)
{things.map(thing => <li key={thing.id}>{thing.color}</li>)}
在 Svelte 中,您需要在标记中指定键。
{#each things as thing (thing.id)}
<li>{thing.color}</li>
{/each}
或者你可以进行解构thing
{#each things as {id, color} (id)}
<Thing current={color}/>
{/each}
f. 等待块
https://svelte.dev/tutorial/await-blocks
awaitSvelte 标记语言提供了一种处理Promise的方法。
由于 Svelte 只会获取最新的 Promise,因此可以自动处理竞态条件。
{#await promise}
<p>Loading...</p>
{:then number}
<p>The value is {number}<p>
{:catch error}
<p class="error">{error.message}</p>
{/await}
您可以选择不显示中间的“加载中”消息,并等待 Promise 解析完成。
{#await promise then number}
<p>The value is {number}<p>
{/await}
这比 React 中的抽象要清晰得多,在 React 中,需要使用useEffect异步方法解析 Promise 并设置状态。
5. 事件
a. DOM 事件
https://svelte.dev/tutorial/dom-events
使用on:指令,后跟 DOM 事件名称。
例如)鼠标移动
<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>
b. 内联处理程序
https://svelte.dev/tutorial/inline-handlers
⚠ 与 React 不同,内联事件处理程序不会导致任何性能问题,因为 Svelte 知道如何进行优化。
相反,
<div on:mousemove={handleMousemove}>
The mouse position is {m.x} x {m.y}
</div>
您可以handleMousemove像下面这样内联插入。
<div on:mousemove={e => m = {x: e.clientX, y: e.clientY}}>
The mouse position is {m.x} x {m.y}
</div>
或者,在某些编辑器中,为了实现语法高亮显示,可以将内联方法用引号括起来。
<div on:mousemove="{e => m = {x: e.clientX, y: e.clientY}}">
The mouse position is {m.x} x {m.y}
</div>
c. 事件修饰符
https://svelte.dev/tutorial/event-modifiers
你可以使用修饰符来“装饰”(我的理解)事件,例如:
once运行一次处理程序prevetnDefault:event.preventDefault()在调用处理程序之前stopPropagation停止event.stopPropagation()事件气泡/捕获passive:用于触控/滚轮滚动性能(谷歌将其添加为非标准,但得到了广泛支持)capture默认情况下,DOM 事件会向上冒泡。此操作会将其反转capture(请参阅 MDN Event.eventPhase)。self:event.target === current element。
例如)用于once仅在按钮上运行一次事件处理程序
<button on:click|once={handleClick}>Click me</button>
修饰符可以串联使用。on:click|once|capture|preventDefault
handleClick无论你按多少次按钮,都只会调用一次。
⚠ 空格很重要!下面的代码无效,因为句点之间有空格|。
<button on:click | once={handleClick}>Click me</button>
d. 组件事件
https://svelte.dev/tutorial/component-events
与原生JS中的自定义事件分发(需要将自定义数据作为detail属性传递)不同,
// add an appropriate event listener
obj.addEventListener("cat", function(e) { process(e.detail) });
// create and dispatch the event
let event = new CustomEvent("cat", {
👇
detail: {
hazcheeseburger: true
}
});
obj.dispatchEvent(event);
你发送一个包含数据的事件,它将event.detail自动作为一部分提供。
Inner.svelte
<script>
import {createEventDispatcher} from 'svelte'
const dispatch = createEventDispatcher()
function sayHello() {
// NOT THIS!
// dispatch('message', {detail: {text: 'hi!'}})
// But pass the data as it is
dispatch('message', { text: 'Hello!' });
}
</script>
<button on:click={sayHello}>
Click to say hello
</button>
然后,您可以像这样使用该组件并订阅事件message。
App.svelte
<script>
import Inner from './Inner.svelte';
function handleMessage(event) {
// Access "text" via 👇 event.detail
alert(event.detail.text);
}
</script>
<Inner on:message={handleMessage}/>
这种模式与 React 不同,React 中内部组件接收一个“事件处理程序”作为函数并调用它,而不是声明一个事件。
const App = () => <Inner onMessage={handleMessage}>
const Inner = ({onMessage}) => <button onClick={onMessage}>Click</button>
看来在 Svelte 中,事件处理程序是使用原生 JavaScript 的CustomEvent接口声明的。
e. 事件转发
https://svelte.dev/tutorial/event-forwarding
DOM 事件会向上冒泡,而 Svelte 事件则不会。可以通过在每一层创建事件分发器来实现显式的事件转发。
Svelte 可以通过快捷方式转发事件,只需指定on:eventname指令而不指定值即可。
<Inner on:message>
然后所有on:message事件处理程序都将被转发并提供给调用组件。
注意:这有点难理解,需要稍后再来研究。
f. DOM 事件转发
https://svelte.dev/tutorial/dom-event-forwarding
Svelte 要求你明确决定是否公开某个事件。
当内部组件中有多个元素暴露同一个事件时,例如两个按钮on:click,
CustomButton.svelte
<button id="b1" on:click>
Click me
</button>
<button id="b2" on:click>
Click me2
</button>
然后你可以通过检查来判断是哪颗子弹射出的。event.target
App.svelte
<script>
import CustomButton from './CustomButton.svelte'
function handleClick(event) {
console.log(`e =>`, event.target)
}
</script>
<CustomButton on:click={handleClick}> />
点击自定义按钮#b1,#b2结果如下:
e => <button id="b1">Click me</button>
e => <button id="b2">Click me2</button>
6. 装订
a. 文本输入
https://svelte.dev/tutorial/text-inputs
有点像双向绑定,元素的变化会更新状态和当前状态。
<script>
let name = 'world!'
</script>
<input bind:value={name}>
<h1>Hello {name}!</h1>
更新值input会同时更新name状态和输入值。
b. 数值输入
https://svelte.dev/tutorial/numeric-inputs
电池已包含
Svelte 会自动将类型为number& 的输入转换range为数值。
而 React 则需要显式转换,因为它基于底层技术。
c. 复选框输入
https://svelte.dev/tutorial/checkbox-inputs
复选框输入类型值绑定到bind:checked而不是bind:value。
<script>
let isChecked = false
</script>
<input type="checkbox" bind:checked={isChecked}>
d. 小组输入
https://svelte.dev/tutorial/group-inputs
在原生 JavaScript 中,您可以使用 ` name<select>` 来对相关的复选框和单选按钮进行分组。MDN
参考:<input type="radio">
<form>
👇
<input type="radio" name="scoops" value="1">
<input type="radio" name="scoops" value="2">
<input type="radio" name="scoops" value="3">
</form>
但在 Svelte 中,您可以使用指令绑定组bind:group。
<form>
👇
<input type="radio" bind:group="scoops" value="1">
<input type="radio" bind:group="scoops" value="2">
<input type="radio" bind:group="scoops" value="3">
</form>
当绑定到单选按钮组时,绑定的值是一个值;但对于复选框,绑定的值是一个数组。
<script>
let scoops = 1;
let flavours = [];
</script>
<!-- Radio `scopes` bound to a single value -->
<label>
<input type=radio bind:group={scoops} value={1}>
One scoop
</label>
<label>
<input type=radio bind:group={scoops} value={2}>
Two scoops
</label>
<label>
<input type=radio bind:group={scoops} value={3}>
Three scoops
</label>
<!-- Checkbox group value, `favlours` is an array -->
<label>
<input type=checkbox bind:group={flavours} value="Cookies and cream">
Cookies and cream
</label>
<label>
<input type=checkbox bind:group={flavours} value="Mint choc chip">
Mint choc chip
</label>
<label>
<input type=checkbox bind:group={flavours} value="Raspberry ripple">
Raspberry ripple
</label>
e. 文本区域输入
https://svelte.dev/tutorial/textarea-inputs
与此相同<input type="text">。您可以使用绑定值bind:value={value}。如果值变量名匹配value,则可以省略赋值语句,例如:
<textarea bind:value></textarea>
f. 选择绑定
https://svelte.dev/tutorial/select-bindings
与 Textarea 类似,如果变量名为. ,则可以使用bind:value={value}它并省略赋值。bind:valuevalue
<script>
let value;
let answer = ""
const questions = [
{id: 1, 'question #1'},
{id: 2, 'question #2'},
{id: 3, 'question #3'},
]
</script>
<!-- this works too 👇 -->
<!-- <select bind:value={value} on:change="{() => answer = ""}"> -->
<select bind:value on:change="{() => answer = ""}">
{#each questions as question}
<option value={question}>{question.text}</option>
{/each}
</select>
<input bind:value={answer}>
g. 选择多个
https://svelte.dev/tutorial/multiple-select-bindings
我之前已经在https://svelte.dev/tutorial/group-inputsd. Group inputs中提到过这一点了。
使用指令绑定到 select 元素multiple会将值设置为数组。
flavours是一个数组。
<select multiple bind:value={flavours}>
{#each menu as flavour}
<option value={flavour}>
{flavour}
</option>
{/each}
</select>
h. 可编辑内容绑定
https://svelte.dev/tutorial/contenteditable-bindings
你可以绑定到其中任何一个textContent。innerHTML
<div
contenteditable="true"
bind:innerHTML={html}
></div>
<!-- or -->
<div
contenteditable="true"
bind:textContent={html}
></div>
了解一下&和之间的区别
textContentinnerHTML
,以及为什么应该考虑使用textContent而不是innerHTML。
i. 每个块绑定
https://svelte.dev/tutorial/each-block-bindings
如果你打算使用不可变数据(React 风格),就不要用这个。
熟悉命令式编程风格?那就用这个。
j. 中间元素
https://svelte.dev/tutorial/media-elements
使用.video/audiorequestAnimationFrame
k. 尺寸
https://svelte.dev/tutorial/dimensions
每个块级元素,例如div,,等section,都有以下属性的绑定。article
一、这
https://svelte.dev/tutorial/bind-this
bind:this={variable}返回对已渲染元素的引用。该引用在组件挂载之前variable一直有效。 请使用onMount生命周期方法来引用该变量。undefined
注意:这看起来像是ref在 React 中。
m. 组件绑定
https://svelte.dev/tutorial/component-bindings
如前所述,您可以bind:value为自定义组件提供双向绑定。
子组件的更改将在父元素中生效。
Keypad.svelte
<script>
export let value;
</script>
...
假设在App.svelte,
<script>
import Keypad from './Keypad.svelte'
let pin;
const handleSubmit = () => console.log(`pin => ${pin}`)
</script>
<input bind:value={pin} />
<Keypad bind:value={pin} on:submit={handleSubmit}>
你可以绑定到Keypad它bind:value={pin}。它既可以作为组件的输入,也可以作为输出Keypad。
可以通过更改其中的值来演示它的功能<input bind:value={pin} />。
太棒了!非常方便。但是要小心,因为你可能会搞不清状态流向。
在 React 中,需要传递一个回调函数,以便在子元素值发生变化时调用该函数,父元素将通过回调函数更新状态。
App.jsx
function App() {
const [pin, setPin] = React.useState(null)
return <Keypad onChange={setPin} />
}
7. 生命周期
a. onMount
https://svelte.dev/tutorial/onmount
它类似于componentDidMount和useEffect的混合,因为它在组件挂载时调用,并通过从中返回的回调函数进行清理(这就是useEffect 进行清理的方式)。
此外,componentDidMount它既可以调用异步方法async,也不useEffect可以调用异步方法。
这是fetchReact 中推荐的调用方式,onMount通常情况下,人们应该在这里发出网络请求。
<script>
import { onMount } from 'svelte';
onMount(async () => {
const response = await fetch('https://www...');
photos = await response.json();
return () => {
// clean up resources here
};
});
</script>
b. onDestroy
https://svelte.dev/tutorial/ondestroy
onDestroy类似于 React 的componentWillUnmount。使用它在组件卸载阶段清理资源。
<script>
import { onDestroy } from 'svelte'
let seconds = 1;
const id = setInterval(() => seconds++, 1000)
onDestroy(() => void clearInterval(id))
</script>
c. 更新前和更新后
https://svelte.dev/tutorial/update
流动方式如下:
beforeUpdate-> onMount-> beforeUpdate-> 状态变化 -> afterUpdate->onDestroy
由于beforeUpdate运行在之前onMount,因此需要检查元素是否存在。
d. 蜱虫
https://svelte.dev/tutorial/tick
为了绕过批量处理(状态更新、DOM 更新等)
<script>
import { tick } from 'svelte'
</script>
8. 商店
a. 可写存储
https://svelte.dev/tutorial/writable-stores
Svelte 内置电池,并附带全局状态管理库。
svelte/store具有writable创建全局状态的方法。
store.js
import { writable } from 'svelte/store'
export const count = writable(0)
然后就可以导入count,store.js用于读取、更新或设置值。
- 通过订阅读取数据
writable会返回一个状态,你可以subscribe()查看该状态的值是否发生变化。这是一个高阶函数(HoF),它会返回一个取消订阅的函数。这与Redux store 的 subscribe 方法返回 unsubscribe 方法的方式相同。我猜测你需要正常调用unsubscribeunsubscribe方法onDestroy来清理数据。
<script>
import { onDestroy } from 'svelte'
import { count } from './store'
let countValue;
const unsubscribe = count.subscribe(value => { countValue = value });
// Clean up after your business!
onDestroy(unsubscribe);
</script>
- 更新状态 -
writable返回一个状态,您可以update为其赋值 - 它需要一个回调函数,该回调函数会接收要更新的当前值。
<script>
import { count } from './store.js'
const incrementCount = () => count.update(currentValue => currentValue + 1)
</script>
<button on:click={incrementCount}>Increment Count by One/button>
- 设置状态(便捷的更新方法)——
set该方法看起来像是一个便捷方法update,因为您可以直接设置一个值而无需回调函数。
<script>
import { count } from './store.js'
const reset = () => count.set(0)
</script>
<button on:click={reset}>Reset Count</button>
b. 自动订阅
https://svelte.dev/tutorial/auto-subscriptions
Svelte 还提供了另一种便捷的方式来订阅全局状态变化。
通过$在变量前加上前缀,Svelte 会自动处理订阅和取消订阅的操作。
与其使用冗长的取消/订阅命令count,
<script>
import { onDestroy } from 'svelte'
import { count } from './store'
let countValue;
const unsubscribe = count.subscribe(value => { countValue = value });
// Clean up after your business!
onDestroy(unsubscribe);
</script>
<p>Count value is {countValue}</p>
你可以简单地count加上$前缀$count。
<script>
import { onDestroy } from 'svelte'
import { count } from './store'
</script>
<p>Count value is {$count}</p>
请务必阅读链接页面中的注释。
c. 可读商店
https://svelte.dev/tutorial/readable-stores
可读存储提供的是只读存储,可以初始化但不能更新。
这看起来类似于useEffect“当最后一个订阅者取消订阅时”调用返回函数。
store.js
import { readable } from 'svelte';
const initialValue = new Date();
const valueUpdator = set => {
const id = setInterval(() => set(new Date()), 1000);
// called when the last subscriber unsubscribes.
return () => clearInterval(id);
}
export const time = readable(initialValue, valueUpdator);
与 store 一样,你可以像在另一个文件中一样,通过前缀wriable来引用它。$$time
d. 衍生商店
教程中回调函数time使用了$类似前缀。$time
自动订阅教程指出:
任何以 $ 开头的名称都被视为指向存储值。它实际上是一个保留字符——Svelte 会阻止你声明带有 $ 前缀的变量。
但我尝试去掉$前缀,如下所示,仍然有效。
export const elapsed = derived(
time,
t => Math.round((t - start) / 1000)
);
不确定是否$需要。我在 Reddit 上提问了。https
://www.reddit.com/r/sveltejs/comments/hblmxa/question_derived_callback_in_tutorial_uses_a/
e. 定制商店
https://svelte.dev/tutorial/custom-stores
可以通过实现方法来创建自定义存储subscribe。
本教程使用wriable`s`subscribe来暴露接口,但并未展示如何自行实现。
f. 商店绑定
https://svelte.dev/tutorial/store-bindings
以前缀引用的存储值$可以像本地状态一样进行绑定。
<script>
import { name } from './store.js';
</script>
<input bind:value={$name}>
输入内容后,系统将更新$name自身及其所有依赖项。
9. 运动
a. 过渡动画
https://svelte.dev/tutorial/tweened
Svelte 内置了运动库,无需安装第三方库。
而在 React 中,你需要使用 ` react-springMotion`、`MotionById`react-motion等。
b. 春季
https://svelte.dev/tutorial/spring
tweened对于经常更改的值,请使用此方法代替。
10. 过渡
a. 过渡指令
https://svelte.dev/tutorial/transition
另一种在 JavaScript 中实现过渡效果的便捷方法。
根据 Chrome 开发者工具显示,<p transition:fade>它会注入一个内联样式来实现淡入/淡出效果。
<script>
import { fade } from 'svelte/transition';
let visible = true;
</script>
{#if visible}
<p transition:fade>Fade in and out</p>
{/if}
b. 添加参数
https://svelte.dev/tutorial/adding-parameters-to-transitions
您还可以将内联参数传递给标记中的过渡函数。
<script>
import { fly } from 'svelte/transition';
let visible = true;
</script>
<input type=checkbox bind:checked={visible}>
{#if visible}
<p transition:fly="{{ y: 200, duration: 2000 }}">Flies in and out</p>
{/if}
过渡效果是“可逆的”。
切换可见性不会突然从开始或结束状态开始过渡,
而是会从上次停止的地方反向播放。
请参阅链接的教程页面,了解实际效果!很棒。
c. 进出
https://svelte.dev/tutorial/in-and-out
您可以使用in&out指令而不是transition.来精细地控制过渡效果。
d. 自定义 CSS 过渡
https://svelte.dev/tutorial/custom-css-transitions
只要你了解CSS的过渡和动画等技术,看起来很简单。但
我对这两方面都不太了解,所以很难。
首先要学习:MDN 上的CSS 过渡使用方法。
e. 自定义 JS 过渡
https://svelte.dev/tutorial/custom-js-transitions
使用tick回调函数来实现 CSS 过渡无法实现的 JS 过渡效果。
f. 过渡事件
https://svelte.dev/tutorial/transition-events
transition使用以下指令监控指令事件
on:introstarton:outrostarton:introendon:outroend
g. 局部转变
https://svelte.dev/tutorial/local-transitions
local转换操作使转换发生在单个元素上,而不是一组元素上。
说实话,我真的没发现它有什么用。
h. 延迟过渡
https://svelte.dev/tutorial/deferred-transitions
更高级的过渡概念我以后再学。
11. 动画
a. 有生命指令
https://svelte.dev/tutorial/animate
哎呀,过会儿再来吧……
12. 行动
a. 使用指令
https://svelte.dev/tutorial/actions
使用use:指令来指定操作。
<script>
import { pannable } from './pannable.js';
</script>
<div use:pannable></div>
pannable是一个函数,它接受一个 DOM 节点。
// Fires following custom events
// 1. panstart
// 2. panmove
// 3. panend
export function pannable(node) {}
当组件pannable分发自定义事件时,父组件可以在标记中订阅该事件。
<script>
import { pannable } from './pannable.js';
// These functions have access to `event` dispatched from `pannable`
const handlePanStart = event => {}
const handlePanMove = event => {}
const handlePanEnd = event => {}
</script>
<div
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>
可以通过暴露来清理行动痕迹onDestroy。
export function pannable(node) {
return {
onDesotry() {
// clean up the mess
}
}
}
b. 添加参数
https://svelte.dev/tutorial/adding-parameters-to-actions
就像过渡一样,动作也可以接受参数。
<script>
import { longpress } from './longpress.js';
</script>
<div use:longpress={duration}></div>
当持续时间发生变化时,longpress.js不会知道它duration已经发生了变化。
要订阅此duration变化,请update在操作中实现函数。
longpress.js
export function longpress(node, duration) {
return {
update(newDuration) {
duration = newDuration
}
}
}
可以将多个参数作为对象传递给操作。
<script>
import { longpress } from './longpress.js';
</script>
<div use:longpress={{duration, spiciness}}></div>
并在动作中接受对象。
longpress.js
export function longpress(node, { duration, spiciness }) {}
13. 课程
a. 类指令
https://svelte.dev/tutorial/classes
Svelt 提供了一个用于切换类的快捷方式。
class只是在 Svelte 中是这样className,不像在 React 中那样。
<script>let current = 'foo';</script>
<style>
.someActiveClass {
background-color: red;
color: white
}
</style>
<button
class:someActiveClass="{current='foo'}"
on:click="{() => current = 'foo'}">
>foo</button>
<button
class:someActiveClass="{current='bar'}"
on:click="{() => current = 'bar'}">
>bar</button>
<button
class:someActiveClass="{current='baz'}"
on:click="{() => current = 'baz'}">
>baz</button>
只要条件匹配,就会在后面添加自定义类class:。
b. 简写类指令
https://svelte.dev/tutorial/class-shorthand
快捷方式的简写(呼,真绕口)是,如果要切换的类与变量名匹配,则可以省略指令赋值。
<div class:big={big}></div>
可以缩写为
<div class:big></div>
14. 成分组成
a. 老虎机
https://svelte.dev/tutorial/slots
这与 React 的实现方式类似children,用于指定将子组件放置在当前组件中的哪个位置。
Svelte 组件不是函数,而更像是带有脚本和样式的标记。
因此,要访问子组件,需要指定 ` <script> <slot></slot>` 或 `<style> <slot />`。
您可以指定多个<slot />,这将多次显示子项。
box.svelte
<style>
.box {}
</style>
<div class="box">
<slot></slot>
<!-- or -->
<slot />
</div>
并将子组件传递给 box 组件。
<script>
import Box from './box.svelte';
</script>
<Box>
<h1>Here is the child header</h1>
<p> this is the content <p>
</Box>
个人说明:这更符合 React 应有的风格,因为 React 本来就应该是声明式的。Svelte
正确地使用了子元素的标记声明,而 React 则是命令式的children。(更不用说,`<div>`children可以是任何东西,比如一个用于实现渲染属性的函数)。
b. 槽位回退
https://svelte.dev/tutorial/slot-fallbacks
如果没有指定任何备用方案,可以使用 ` <slot />but`,但要提供备用方案(当用户没有指定子项时),则可以使用更长的 ` <slot>fallback content</slot>.`
box.svelte
<style>
.box {}
</style>
<div class="box">
<slot>Fallback content!!!</slot>
</div>
Box下面展示了传递无子节点的示例。
<script>
import Box from './Box.svelte';
</script>
<Box>
<h2>Hello!</h2>
<p>This is a box. It can contain anything.</p>
</Box>
<Box></Box>
<Box />
c. 命名槽
https://svelte.dev/tutorial/named-slots
在 React 中,可以像这样公开单独的组件或静态子组件。
function App() {
return (
<ContactCard>
<ContactCard.Name>Sung Kim</ContactCard.Name>
<ContactCard.Address />
</ContactCard>
)
}
// or
function App() {
return (
<ContactCard>
<ContactCardName>Sung Kim</ContactCardName>
<ContactCardAddress />
</ContactCard>
)
}
ContactCardName它需要为`or`创建单独的组件ContactCardAddress,每个组件都接受自己的children函数。
接下来就更有意思了。
您可以指定要将子内容插入到哪个“槽位”中!
ContactCard.svelte
<style>
.missing {}
</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>
如上一节所示,每个命名槽位都包含备用槽位。
调用组件指定子组件中的插槽。
App.svelte
<script>
import ContactCard from './ContactCard.svelte';
</script>
<ContactCard>
<span slot="name">Sung</span>
<span slot="email">Sung@sung.com</span>
</ContactCard>
c. 老虎机道具
https://svelte.dev/tutorial/slot-props
要将数据从子组件传递slot到父组件,需要在声明子组件时声明暴露的状态(通过插槽)。
你不需要在父组件中声明变量,而是像使用“绑定”一样使用let。
Hovering.svelte:包含插槽的组件。
<script>
let hovering;
const enter = () => hovering = true;
const leave = () => hovering = false;
</script>
<div on:mouseenter={enter} on:mouseleave={leave}>
<slot hovering={hovering}></slot>
<!-- or use the hsort hand -->
<!-- <slot hovering></slot> -->
</div>
hovering要在父组件中访问,请使用let前面提到的方法。
Parent.svelte
<script>
import Hoverable from './Hoverable.svelte';
</script>
<Hoverable let:hovering={hovering}>
<div class:active={hovering}>
{#if hovering}
<p>I am being hovered upon.</p>
{:else}
<p>Hover over me!</p>
{/if}
</div>
</Hoverable>
请注意,该hovering变量未在声明中声明script,但可以在内部使用Hovering。
15. 上下文 API
a. setContext 和 getContext
https://svelte.dev/tutorial/context-api
Svelte 的 Context API 与 React 的类似;只有子组件才能通过父组件中暴露的
Context API 访问上下文数据。getContextsetContext
store更像是Zustand,其中状态在组件层次结构中的任何位置都可用。
React 和 Svelte Context API 的区别在于,React 的 API 是声明式的,使用标记语言;而 Svelte 的 API 是命令式的,setContext在组件初始化期间使用。
React
function App() {
return (
<Context.Provider value={value}>
children can access context value here
</Context.Provider>
)
}
16. 特殊元素
a. svelte:self
https://svelte.dev/tutorial/svelte-self
递归引用当前组件。
文档中存在拼写错误,因此提交了一个 issue:https://github.com/sveltejs/svelte/issues/5044
更新:“一个文件”指的是当前文件,而不是File组件。因此文档已更正。已关闭该 issue。
b. svelte:component
https://svelte.dev/tutorial/svelte-component
用于<svelte:component this={component}>动态加载组件。
要传递 props,请将其传递给<svelte:component>.
<svelte:component text="custom text" this={selected.component}/>
text然后传递给selected.component(教程中没有记录,只是偶然发现的)。
确保动态组件接受该属性。
例如)RedThing.svelte
<style>
strong { color: red; }
</style>
<script>
export let text = "red thing";
</script>
<strong>{text}</strong>
c. svelte:window
https://svelte.dev/tutorial/svelte-window
这是一种以声明式方式向window对象添加事件的方法。
d. svelte:window绑定
https://svelte.dev/tutorial/svelte-window-bindings
原来,你window不仅可以绑定事件,还可以绑定到某些属性。
e.苗条:身体
https://svelte.dev/tutorial/svelte-body
这样就可以在document.body.
f.苗条:头
https://svelte.dev/tutorial/svelte-head
直接在代码中注入内容<html><head>,
无需react-helmet第三方库。
g. svelte:选项
https://svelte.dev/tutorial/svelte-options
Svelte 编译器的高级选项。
最值得注意的是,您可以指定不可变性来优化列表中的组件渲染。
17. 模块上下文
a. 代码共享
https://svelte.dev/tutorial/sharing-code
这看起来像是一个在组件的所有实例中都可用的“静态”变量。
可能是原型值。
b. 出口
https://svelte.dev/tutorial/module-exports
模块级脚本中的导出内容可以从另一个 Svelte 组件导入。
18. 调试
a. @debug 标签
https://svelte.dev/tutorial/debug
更好的“console.log” :p
照片由William Krause拍摄,来自Unsplash
文章来源:https://dev.to/dance2die/svelte-tutorial-note-cap