svelte框架的学习
什么是Svelte?
Svelte.js是一个开源的JavaScript框架,通过将Svelte代码转换为流畅的UI界面,简化了Web应用程序的创建。该框架的一个关键区别是:它在编译阶段加载框架而不是用户运行时加载,因此其比 React 或 Vue 更快。
Svelte由它的架构决定运行速度。该框架将代码编译成独立的小型JavaScript模块,确保浏览器尽可能少地完成工作,从而加快加载速度。
Svelte 超快的速度背后有三个主要原因:
- 无虚拟DOM: Svelte在没有虚拟DOM的情况下实现了与 React 和 Vue 相同的功能。这意味着您可以在不依赖虚拟元素的情况下使用它,并获得更好的性能优势。换句话说,Svelte 在没有 DOM 的情况下直接处理代码,并将大部分代码的处理放在编译阶段去完成。
- **减少代码量:**Svelte 将你的代码编译成体积小、不依赖框架的普通 JS 代码,让你的应用程序无论启动还是运行都变得迅速。
- **响应式能力:**Svelte和 React一样,对数据变化做出自己的反应,它不需要浏览器做额外的工作来将组件转换为DOM操作,将数据更改呈现为JavaScript代码。
如果你掌握了JS、HTML、CSS,则学习Svelte的时候,无任何明显的学习曲线。它允许 Web 开发人员构建各种规模的 Web 应用程序,同时为访客提供可靠的用户体验和超高的性能。
Svelte与其它框架的区别:Svelte、React、Vue 的对比
Svelte与 React、Vue等等的框架对比,Svelte构建的应用程序是事先编译的,因此不必将整个框架提供给每个网站访问者。因此,用户的体验更流畅,消耗更少的带宽,这一切都感觉更快,更轻量级。
这是一个对照的图表,您可以一目了然地查看这三个框架之间的差异。
| Svelte.js | React.js | Vue.js | |
|---|---|---|---|
| 应用性能 | 比React和Vue更快 | 比Svelte慢,比Vue略慢 | 比Svelte慢,但比React略快 |
| 构建 | 脚本编译器 | DOM | Virtual DOM |
| 平均应用大小 | 15 Kb | 193 Kb | 71 Kb |
| 学习曲线 | 简单易学 | 相对容易学习 | 相对容易学习 |
简单来说,Svelte可以让您提高效率。通过让您使用您熟悉的语言和符号(HTML、CSS、JavaScript),即使是初学者也可以快速入门。另一方面,React 和 Vue 需要类型脚本和 JSX 技能。
除此之外,Svelte 不依赖于在运行时加载的复杂库。相反,它会编译你的代码,并加载一个比 React更小的软件包。这种体积的差异换来的是访客更快的加载时间。
与 Vue 和 React 不同,Svelte几乎不需要初始化的脚手架,因为它是使用基本的 HTML、CSS 和 JavaScript 编写的。所以,Svelte的脚本看起来类似于普通的JS。
使用Svelte.js的好处
现在我们上面表格的对比研究了Svelte与其替代方案,让我们来谈谈Svelte能成为最受欢迎的框架的原因:
- 更好的开发体验:Svelte是最受欢迎的框架,因为它设置更加简单,让开发人员可以更专注写的业务代码。
- 模块化 CSS:默认情况下,Svelte样式的有自己的作用域,这意味着当您将Svelte文件编译时,编译器将为每个元素生成唯一的类名。这确保了不同页面展示出来的效果是独立的。
- 内置动画: 在Svelte 中使用动画是一种很好的体验。它内置了强大而令人愉悦的交互功能,无需额外的软件包。
- 更小的体积: 编译完成后的代码,拥有更小的体积,更快的加载速度。
什么时候应该使用Svelte.js?
坦率地说,这一切都归结为你打算用它来构建具体的项目。仅仅因为它提供了快速的性能,并不能使它成为解决您所有问题。通常,我建议在以下情况下使用 Svelte:
- 构建快速、响应迅速的网站:Svelte 的小捆绑包尺寸确保您创建的任何内容都能快速运行。这使得它非常适合那些想要快速,SEO驱动的网站和卓越的网络体验的客户。
- 为连接性较差的设备创建 Web 应用程序:由于 Svelte 使用的代码更少,这意味着要下载和执行的 字节数 更少,因此非常适合构建适用于 网络 或 设备性能 较差的 应用程序。
- 设计交互式页面:动画和过渡内置于 Svelte 中。开发人员可以使用svelte/animate模块创建交互式内容,这是让访问者与网站保持互动的好方法,而且并不会影响加载速度和SEO。
1.创建一个Svelte的程序
npm create vite@latest
使用vite创建项目有着更好的启动速度及更小的编译文件
1.数据渲染
<script>
let name = "小明";
let src = "./vite.svg";
</script>
<div>
//将变量放进一对花括号内,即可进行渲染,花括号内可以放表达式,即
hello
{name.replace(/([\W])(\W)/, "$1_$2")}
//甚至还可以对标签的属性进行简写,例如对img标签src属性进行简写
<img {src} alt="" />
</div>
2、双向绑定
双向绑定只需要通过 bind:value 即可完成。若单选框组、复选框组:还需要添加bind:group属性和value值。
<script>
let name = 'world';
</script>
<input bind:value={name}>
<h1>Hello {name}!</h1>
checkbox双向绑定:
<script>
let yes = false;
</script>
<label>
<input type="checkbox" checked={yes}>
</label>
复选框组:
<input type=checkbox bind:group={books} name="books" value={‘钢铁‘}>
<input type=checkbox bind:group={books} name="books" value={‘卖火柴‘}>
<input type=checkbox bind:group={books} name="books" value={‘唐诗300首‘}>
单选组:
<input type=radio bind:group={books} name="books" value={‘钢铁‘}>
<input type=radio bind:group={books} name="books" value={‘卖火柴‘}>
<input type=radio bind:group={books} name="books" value={‘唐诗300首‘}>
select:
<select value={selected} on:change="{() => answer = ''}">
{#each questions as question}
<option value={question}>
{question.text}
</option>
{/each}
</select>
3、样式渲染
<script>
import "./mystyle.css";
</script>
<div style="color: red">字符串</div>
<div class="myclass">蓝色文字</div>
<div class="yellowclass">黄色文字</div>
<div class="myclass2">大文字</div>
<!-- <style>
.myclass {
color: blue;
}
</style> -->
<style lang="scss" type="text/scss">
.myclass2 {
font-size: 40px;
}
</style>
按条件应用类名:
<button class:selected="{current === 'foo'}">clickme</button>
简写:
<div class:big>
big类名
</div>
使得项目支持scss语法。
想要使得项目支持scss,样式预处理语言。
需要先安装预处理器:svelte-preprocess, 由于需要支持scss,那sass当然也需要进行安装。
npm install svelte-preprocess node-sass --save-dev
安装好预处理器后,还需要对脚手架配置文件vite.config.js进行修改:
最终修改如下:
import { defineConfig } from "vite";
import { svelte } from "@sveltejs/vite-plugin-svelte";
import sveltePreprocess from "svelte-preprocess";
// https://vitejs.dev/config/
export default defineConfig({
plugins: [
svelte({
preprocess: sveltePreprocess(),
}),
],
});
将scss写在style即可。不要忘记,将lang和type属性写上。
<div class="bluetext">
蓝色字符串,
<span class="violettext">紫色字符串</span>
</div>
<style lang="scss" type="text/scss">
.bluetext {
color: blue;
.violettext {
color: violet;
}
}
</style>
4.创建组件
在svelte项目中,每一个svelte为后缀的文件都是一个组件。(和react十分像)
匿名插槽
父组件:
<script>
import Box from './Box.svelte';
</script>
<Box>
<h2>Hello!</h2>
<p>This is a box. It can contain anything.</p>
</Box>
子组件:
<div class="box">
<slot></slot>
</div>
<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>
具名插槽
父组件:
<ContactCard>
<span slot="name">
P. Sherman
</span>
<span slot="address">
42 Wallaby Way<br>
Sydney
</span>
</ContactCard>
子组件:
<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>
作用域插槽:
<Hoverable let:hovering={active}>
{active}
</Hoverable>
<script>
let hovering;
</script>
<div on:mouseenter={() => hovering = true} on:mouseleave={() => hovering = false}>
<slot hovering={hovering}></slot>
</div>
5、父传子
父传子的过程需要子组件暴露属性,父组件才能进行参数的传递。
如何暴露属性? 子组件可以在定义响应式变量的过程中,在前面加上export关键词,即可定义参数属性。
父组件:
<script>
import Child from "./Child.svelte";
</script>
<div class="c-parent">
我是父组件
<Child text="子组件" />
</div>
<style lang="scss" type="text/scss">
.c-parent {
width: 500px;
height: 500px;
background-color: rgb(29, 210, 255);
}
</style>
子组件:
<script>
export let text = ""; // 此处暴露出去的值,可以赋值默认值。
</script>
<div class="c-child">
子组件
<br />
父组件:{text}
</div>
<style lang="scss" type="text/scss">
.c-child {
width: 300px;
height: 300px;
background-color: rgb(166, 39, 245);
}
</style>
子组件定义多个属性,父组件还可以通过解构的方式去传递参数:
子组件:
<script>
export let name;
export let age;
</script>
父组件:
<script>
let userinfo = {
name: "小明",
age: 18
}
</script>
<Child {...userinfo} />
6、子传父
在svelte中提供了一个创建事件调度器的方法createEventDispatcher来创建事件调度方法,开发者可以利用该事件调度方法来调度事件。从而达到子传父的目的。
父组件:在父组件中监听自定义方法on:hello,当子组件调度hello事件的时候,父组件能接收到传递过来的参数。
<script>
import Child from "./Child.svelte";
</script>
<div class="c-parent">
我是父组件
<Child
text="子组件"
on:hello={(e) => {
console.log("父组件收到的:", e.detail);
}}
/>
</div>
<style lang="scss" type="text/scss">
.c-parent {
width: 500px;
height: 500px;
background-color: rgb(29, 210, 255);
}
</style>
子组件:
<script>
import { createEventDispatcher } from "svelte";
const dispatch = createEventDispatcher();
const sendToParent = () => {
dispatch("hello", "this is message");
};
export let text = "";
</script>
<div class="c-child">
子组件
<br />
父组件:{text}
<br />
<button on:click={sendToParent}>父组件</button>
</div>
<style lang="scss" type="text/scss">
.c-child {
width: 300px;
height: 300px;
background-color: rgb(166, 39, 245);
}
</style>
父子组件传递与vue、react雷同
7、关于渲染html字符串
在svelte中提供一个特殊的标记 @html,使用该标记可以为我们渲染html字符串。
<script>
let h5 = `我的名字叫:<span style="color: blue">小明</span>`;
</script>
{@html h5}
8、svelte事件
在svelte中定义事件也十分简单,与原生类似,不同的是,需要在on后面加上冒号。
格式如:on:事件名={方法引用}
修饰符:
preventDefault — 停止默认事件修饰符
stopPropagation—停止冒泡修饰符
passive— 提高滚动性能
nonpassive—的设置passive: false
capture—捕获阶段处理事件
once— 只执行一次,完了后移除事件,使得下次不能被执行。
self— 仅在事件对象event.target为元素本身时执行事件。
trusted — 只有 event.isTrusted是 rue才进行触发。
例子:
<button on:click|once={事件函数}>点击我</button>
例子:
<script>
let count = 0;
const reduce = () => {
count--;
};
const add = () => {
count++;
};
</script>
<div>
数量:
<button on:click={reduce}>-</button>
{count}
<button on:click={add}>+</button>
</div>
9、svelte中的反应性
从第一小节可得知,开发者只需要定义一个变量,则该变量就是响应式。
在svelte中,提供一个反应性的语法,在script标签中用$:符合进行定义。先来理解什么是反应性,当被依赖的响应式变量发生改变的时候,会自动同步更新反应性语法里面的表达式。
例子:
<script>
let count = 0;
const reduce = () => {
count--;
};
const add = () => {
count++;
};
$: console.log("count变成:%d", count);
</script>
<div>
数量:
<button on:click={reduce}>-</button>
{count}
<button on:click={add}>+</button>
</div>
价格:{price} 合计:{total}
10、修改数组或对象
在开发过程中经常会遇到一个问题,就是虽然修改了数组,但是不会产生效果的情况。是由于数组和对象变量的指向地址并无发生变化,使得sevelte不能识别是否发生的变量,无法进一步的触发渲染事件。可以通过浅拷贝或深拷贝的形式,使得变量所指向的地址发生改变即可。
<script>
let arr = [1, 2, 3];
$: total = arr.reduce((total, val) => (total += val));
</script>
<div>
{arr.join(" + ")} = {total}
<br />
<button
on:click={() => {
arr.push(arr.length + 1);
arr = [...arr];
}}>add item</button
>
</div>
11、条件渲染
svelte有着自己的一套模板语法,使用起来结构更加清晰.
可以看到如下代码,条件渲染的条件是放在标签语法{#if }里面,而分支用{:else}分开,最终再以{/if}结束。
<script>
let flag = true;
</script>
{#if flag}
<div>真的</div>
{:else}
<div>假的</div>
{/if}。
<script>
let flag = true;
let flag2 = false;
</script>
{#if flag}
<div>真的</div>
{#if flag2}
<div>真的</div>
{:else}
<div>假的</div>
{/if}
{:else}
<div>假的</div>
{/if}
12、列表渲染
svelte有对于循环也是有响应的模板语法。
{#each 数组 as 数组项目, 数组下标 (唯一的键值)}
<div>{数组项目.属性}</div>
{/each}
<script>
import { each } from "svelte/internal";
let arr = [
{ name: "小明", age: 20 },
{ name: "小红", age: 19 },
{ name: "小蓝", age: 20 },
{ name: "小天", age: 15 },
];
</script>
{#each arr as item, index}
<div>
{index}、姓名:{item.name} 年龄:{item.age}
</div>
{/each}
可以通过each后面的圆括号来指定唯一的键(key)
<script>
import { each } from "svelte/internal";
let arr = [
{ id: 1, name: "小明", age: 20 },
{ id: 2, name: "小红", age: 19 },
{ id: 3, name: "小蓝", age: 20 },
{ id: 4, name: "小天", age: 15 },
];
</script>
{#each arr as item, index (item.id)}
<div>
{index}、姓名:{item.name} 年龄:{item.age}
</div>
{/each}
10、Await模板标签
svelte有个与promise配合使用的模板标签有等待、成功、失败状态(较为常用)
{#await Promise}
等待状态
{:then 成功值}
成功状态
{/await}
不含失败和等待状态
{#await Promise then 成功值}
成功状态
{/await}
<script>
let timer = new Promise((resolve) => {
setTimeout(() => {
resolve("倒计时完成");
}, 3000);
});
</script>
{#await timer}
loading...
{:then r}
{r}
{/await}
<script>
let timer = new Promise((resolve) => {
setTimeout(() => {
resolve("倒计时完成");
}, 3000);
});
</script>
{#await timer then r}
{r}
{/await}
13、绑定元素
可以通过bind:this,将元素绑定到具体的变量中去。
<script>
let input;
export function focus() {
input.focus();
}
</script>
<input bind:this={input} />