Svelte初学
Svelte(发音:[svelt])是一个类似于 React 和 Vue 的前端框架,作者是 Rich Harris,同时也是 Rollup 的作者。
编译器而非框架(无运行时)
Svelte 是一种全新的构建用户界面的方法。传统框架如 React 和 Vue 在浏览器中需要做大量的工作,而 Svelte 将这些工作放到构建应用程序的编译阶段来处理。 与使用虚拟(virtual)DOM 差异对比不同。Svelte 编写的代码在应用程序的状态更改时就能像做外科手术一样更新 DOM。 我们知道 React 和 Vue ,都是基于运行时(runtime)的框架,应用都必须引入框架本身 —— 也就是运行时代码,这些运行时代码被用于构建虚拟 DOM、处理 diff 算法等等。并且,这些工作都是在浏览器中完成的,当用户在页面上进行各种操作改变组件的状态时,框架的 runtime 会根据新的组件状态(state)计算(diff)出哪些 DOM 节点需要被更新,从而更新视图。 而 Svelte 不同,它会将我们所写的 Svelte 组件(Svelte 也是组件化的思想)编译成与 DOM 直接交互的原生 JavaScript 代码,这是在构建过程中完成的,代码在运行时不需要再多加一个中间层,也就是说不需要额外引入一个所谓的框架运行时。所以说 Svelte 是编译器而非框架。
优势
- 减少代码量
- 无虚拟 DOM
- 真正的反应能力
- 打包体积更小
声明式添加数据
在组件<script>
标签声明一个 name 变量,然后在标签中应用name变量:
<script>
let name = 'world';
</script>
<h1>Hello {name}!</h1>
动态属性
跟上面控制文本一样,也可以使用花括号控制元素属性。
<script>
let imageSrc = 'image.jpg';
</script>
<img src={imageSrc} alt="Super Man">
如果变量名与属性名相同,可以省去属性名,否则会报错
<script>
let src = 'image.jpg';
</script>
// <img src={src} alt="Super Man"> //A11y: <img> element should have an alt attribute
<img {src} alt="Super Man">
同样属性内部也可以添加变量
<script>
let src = 'image.jpg';
let name = 'You';
</script>
<img {src} alt="Super Man is { name }">
css样式
组件的css样式规则的作用域会被限定在当前组件中,其原理是往标签添加一个class类,类似css scoped。
<style>
#header{
color: green;
}
.main {
width: 50px;
height: 50px;
background: yellow;
}
p{
color: red
}
</style>
<span id="header">Header</span>
<div class="main"></div>
<p>This is a paragraph.</p>
最终css转化成:
#header.svelte-1vottuu{color:green}
.main.svelte-1vottuu{width:50px;height:50px;background:yellow}
p.svelte-1vottuu{color:red}
Reactivity 数据响应
赋值 Svelete 内核是一个强大的 (反应性)reactivity 系统,能够让 DOM 与你的应用程序状态保持同步。
<script>
let count = 0;
function handleClick() {
count +=1
}
</script>
<button on:click={handleClick}>
Clicked {count} {count === 1 ? 'time' : 'times'}
</button>
响应式声明 - 值
类似Vue的computed,需要通过其他组件状态计算得到。
<script>
let count = 0;
$: doubled = count * 2;
</script>
<p>{count} doubled is {doubled}</p>
响应式声明 - 语句
类型Vue的watch, 监听某个变量的变化
$: console.log(`the count is ${count}`);
$: {
console.log(`the count is ${count}`);
alert(`I SAID THE COUNT IS ${count}`);
}
$: if (count >= 10) {
alert(`count is dangerously high!`);
count = 9;
}
更新数组和对象
由于 Svelte 的反应性是由赋值语句触发的,因此使用数组的诸如 push 和 splice 之类的方法就不会触发自动更新。 如下操作不会触发任何变化:
function addNumber() {
numbers.push(numbers.length + 1);
}
解决该问题的一种方法是添加一个多余的赋值语句:
function addNumber() {
numbers.push(numbers.length + 1);
numbers = numbers;
}
// OR
function addNumber() {
numbers = [...numbers, numbers.length + 1];
}
属性
属性定义 组件通过export声明props, 也可直接给props赋值
// Child.svelte
<script>
export let answer;
export let name = "Tony"
</script>
// App.svelte
<script>
import Child from './Child.svelte';
</script>
<Child amswer="a mystery" name="Judy" />
如果组件中含有一个对象属性,可以利用...语法将它们传到子组件中,而不用逐一指定。
<Info {...pkg}/>
逻辑
条件逻辑
通过把html代码放到if块中来控制渲染逻辑
{#if user.loggedIn}
<button on:click={toggle}>
Log out
</button>
{/if}
{#if !user.loggedIn}
<button on:click={toggle}>
Log in
</button>
{/if}
也可以直接写成 if ... else ...
{#if user.loggedIn}
<button on:click={toggle}>
Log out
</button>
{:else}
<button on:click={toggle}>
Log in
</button>
{/if}
也可以直接写成 if ... else if ...
{#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}
循环逻辑
遍历数据列表使用each块
<ul>
{#each cats as cat}
<li><a target="_blank" href="https://www.baidu.com/s?ie=UTF-8&wd={cat.id}">
{cat.name}
</a></li>
{/each}
</ul>
表达式 cats是一个数组,遇到数组或类似于数组的对象 (即具有length 属性)。你都可以通过 each [...iterable]遍历迭代该对象。
你也可以将index 作为第二个参数(key),类似于:
{#each cats as cat, i}
<li><a target="_blank" href="https://www.baidu.com/s?ie=UTF-8&wd={cat.id}">
{i + 1}: {cat.name}
</a></li>
{/each}
如果你希望代码更加健壮,你可以使用each cats as { id, name }来解构,用cat.id 和 cat.name 来代替 id 和 name。
{#each cats as cat, i}
<li><a target="_blank" href="https://www.baidu.com/s?ie=UTF-8&wd={cat.id}">
{i + 1}: {cat.name}
</a></li>
{/each}
each块添加key值
你可以将任何对象用作 key 来使用,就像Svelte 用 Map 在内部作为key一样,换句话说,你可以用 (thing) 来代替 (thing.id)作为 key 值。但是,使用字符串或者数字作为 key 值通常更安全,因为这能确保它的唯一性。
{#each things as thing (thing.id)}
<Thing current={thing.color}/>
{/each}
事件
通过在标签添加on:event来添加事件
<div on:mousemove={handleMousemove}>
The mouse position is {m.x} x {m.y}
</div>
添加内联函数 在某些框架中,出于性能原因,您可能会看到避免内联事件处理程序的建议,特别是在循环内部。这个建议不适用于Svelte——无论您选择哪种形式,编译器都会正常运行。
<div on:mousemove="{e => m = { x: e.clientX, y: e.clientY }}">
The mouse position is {m.x} x {m.y}
</div>
Await块
很多Web应用程序都可能在某个时候有需要处理异步数据的需求。使用 Svelte 在标签中使用 await 处理数据也是十分容易:
{#await promise}
<p>...waiting</p>
{:then number}
<p>The number is {number}</p>
{:catch error}
<p style="color: red">{error.message}</p>
{/await}
如果无需知道 promise 返回错误,则可以忽略 catch 块。如果在请求完成之前不想程序执行任何操作,也可以忽略第一个块。
{#await promise then value}
<p>the value is {value}</p>
{/await}
事件修饰符
DOM 事件处理程序具有额外的 修饰符(modifiers)。例如,带 once 修饰符的事件处理程序只运用一次:
<script>
function handleClick() {
alert('no more alerts')
}
</script>
<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 是其本身时才执行。
你可以将修饰符组合在一起使用,例如:on:click|once|capture={...}。
组件事件
组件也可以调度事件,为此,组件内必须创建一个相同事件并在外部进行分配。
// Inner.svelte
<script>
// setup code goes here
import { createEventDispatcher } from 'svelte';
const dispatch = createEventDispatcher()
function sayHello() {
dispatch('message',{
text: 'Hello123!'
});
}
</script>
<button on:click={sayHello}>
Click to say hello
</button>
// App.svelte
<script>
import Inner from './Inner.svelte';
function handleMessage(event) {
alert(event.detail.text);
}
</script>
<Inner on:message={handleMessage}/>
createEventDispatcher 必须在首次实例化组件时调用它,—组件本身不支持如 setTimeout 之类的事件回调。 定义一个dispatch进行连接,进而把组件实例化。
生命周期
- onMount
- onDestroy
- beforeUpdate
- afterUpdate
- tick
Vite构建Svelte
Vite也支持Svelte,用Vite开发可以使开发效率又可以提升一倍。 项目构建目录如下:
|-- .vscode |---- extensions.json |-- node_modules |-- public |---- vite.svg |-- src |---- assets |------- svelte.svg |---- lib |------- Counter.svelte |---- app.css |---- app.svelte |---- main.js |---- vite-env.d.ts --.gitignore -- index.html -- jsconfig.json -- package-lock.json -- package.json -- README.md -- vite.config.js
可安装@sveltejs/vite-plugin-svelte包,vite.config.js配置如下:
import { defineConfig } from 'vite'
import { svelte } from '@sveltejs/vite-plugin-svelte'
// https://vitejs.dev/config/
export default defineConfig({
plugins: [svelte()]
})
本案例简单介绍Svelte一些基础知识,与详细了解,可查看其官方文档。