svelte使用总结
概念
什么是Svelte?
Svelte由它的架构决定运行速度。该框架将代码编译成独立的小型JavaScript模块,确保浏览器尽可能少地完成工作,从而加快加载速度。
Svelte 速度快的主要原因:
-
无虚拟DOM
-
代码量少
-
响应式
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 不依赖于在运行时加载的复杂库。相反,它会编译你的代码,并加载一个比 React更小的软件包。这种体积的差异换来的是访客更快的加载时间。
与 Vue 和 React 不同,Svelte几乎不需要初始化的脚手架,因为它是使用基本的 HTML、CSS 和 JavaScript 编写的。所以,Svelte的脚本看起来类似于普通的JS。
使用Svelte.js的优点
-
更好的开发体验
-
模块化 CSS
-
内置动画
-
项目体积小
语法
渲染
响应式数据
-
使用响应式数据时需要在
script
中声明当前变量 -
{ }
内可以使用 表达式
<script>
let name = "张三";
</script>
<main>
<p >我的名字叫{name}</p>
</main>
图片引入
-
图片也是类型响应式数据的需要声明一个变量才能使用
-
svelte支持自动编译简写 ,所以
src=
可以写成{src}
<script>
let src = "./下载.png";
</script>
<main>
<img {src} alt="" />
</main>
双向绑定
双向绑定最重要的语法 : bind
-
双向绑定只需要通过
bind:value
即可完成。 -
单选框组、复选框组:需要添加
bind:group
属性和value值。 -
但需要区分 单个选框时则是需要使用
bind:checked
<script>
let name = '法外狂徒';
</script>
<input bind:value={name}>
<h1>Hello {name}!</h1>
单选框双向数据绑定:
<script>
let choice = false;
</script>
<label>
<input type="checkbox" bind:checked={choice}>
</label>
单选框组 复选框组 :
<!-- 单选框组 -->
<input type="radio" bind:group={books} name="books" value="单选1" />
<input type="radio" bind:group={books} name="books" value="单选2" />
<input type="radio" bind:group={books} name="books" value="单选3" />
<br />
<!-- 复选框组 -->
<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首" />
下拉选项框
<select
value={selected}
on:change={(event) => {
selected = event.target.value;
}}
>
<option value="1">下拉选项1</option>
<option value="2">下拉选项2</option>
<option value="3">下拉选项3</option>
</select>
-
下拉选项框的操作直接使用 value与change事件配合完成
-
change事件:当下拉选定新值时就更改选择项
样式渲染
行内式:
<div style="color:red">字符串</div>
外链式:
<script>
import "./mystylea1.css";
</script>
<main>
<div class="bluetext">蓝色文字</div>
</main>
当前页面使用样式:
<div class="myclass2">大头字</div>
<!-- vite.config.js文件中还需要进行定义预先编译器的设置 -->
<style lang="scss" type="text/scss">
.myclass2 {
font-size: 24px;
}
</style>
svelte中想要使用scss语法需要先安装预处理器:svelte-preprocess, 由于需要支持scss,那sass当然也需要进行安装。
npm install svelte-preprocess sass 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(),
}),
],});
插槽传值
匿名插槽
父组件:
<script>
import Box from './Box.svelte';
</script>
<div>
<Box>
这是一个子组件
</Box>
</div>
子组件:
<div class="box">
<slot></slot>
</div>
-
此时子组件通过匿名函数获取到父级参数传递而来的值
具名插槽
父组件:
<script>
import Box from './Box.svelte';
</script>
<div>
<Box>
<div slot="block1">插槽1</div>
<div slot="block2">插槽2</div>
</Box>
</div>
子组件:
<div class="box">
<slot name="block1"></slot>
<slot name="block2"></slot>
</div>
-
具名插槽需要绑定父级中定义的插槽名称
父传子
父传子的过程需要子组件暴露属性,父组件才能进行参数的传递。
<script>
import Child from "./Child.svelte";
</script>
<main>
<div class="box1">
<!--通过子组件属性进行传参-->
<Child msg="hello wold">
</Child>
</div>
</main>
-
定义一个对象来接收子组件传递参数
子组件:
<script>
export let msg = ""; // 此处暴露出去的值,可以赋值默认值。
</script>
<div class="child">
父组件信息:{msg}
</div>
子传父
子组件
-
子组件 通过使用自带函数方法 向父组件传递数据的方法
-
并且需要定义一个事件来进行参数的传递
import { createEventDispatcher } from "svelte";
const dipatch = createEventDispatcher();
const sendMSG = () => {
dipatch("sendMSGtoParent", "你好父组件");
//dipatch("父组件声明接收参数的名函数名称","需要传递的数据");
};
触发事件
<button on:click={sendMSG}>点击传递数据</button>
父组件
-
定义一个对象来接收子组件传递参数
let smsg = "接收子组件参数有";
-
通过 父组件声明接收参数的名函数名称 来进行事件的关联 并且使用 e.detail 获取到传递的数据
<main>
<div class="box1">
<Child on:sendMSGtoParent={(e) => {
smsg = e.detail; }} >
</Child>
{smsg}
</div>
</main>
渲染html字符串
在svelte中提供一个特殊的标记 @html,使用该标记可以为我们渲染html字符串。
<script>
let A1 = "我叫:<span style='color:blue'>张三</span>";
</script>
<div>
<!-- 使用{@html "对象名"} 来使用html文本 -->
{@html A1}
</div>
svelte事件
在svelte中定义事件也十分简单,与原生类似,不同的是,需要在on后面加上冒号。
格式如:on:事件名={方法引用}
修饰符:
-
preventDefault
— 停止默认事件修饰符 -
stopPropagation
—停止冒泡修饰符 -
passive
— 提高滚动性能 -
nonpassive
— 显式的设置passive: false
-
capture
—捕获阶段处理事件 -
once
— 只执行一次,完了后移除事件,使得下次不能被执行。 -
self
— 仅在事件对象event.target为元素本身时执行事件。 -
trusted
— 只有event.isTrusted
是true
才进行触发。
例子:
<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>
svelte的监听
当一个属性会被别的属性所影响而发生改变时就需要使用到 反应性
$: "需要依赖别的属性" = "被依赖的属性"
在svelte中,提供一个反应性的语法,在script标签中用$:符合进行定义。先来理解什么是反应性,当被依赖的响应式变量发生改变的时候,会自动同步更新反应性语法里面的表达式。
<script>
let count = 0;
const reduce = () => {
count--;
};
const add = () => {
count++;
};
$: total = price * count;
</script>
<div>
数量:
<button on:click={reduce}>-</button>
{count}
<button on:click={add}>+</button>
{total}
</div>
-
当
count
被改变时total
就会产生改变
修改数组或对象时没反应
-
问:虽然修改了数组,但是不会产生效果是什么情况?
-
答:数组和对象变量的指向地址并无发生变化,使得sevelte不能识别是否发生的变量,无法进一步的触发渲染事件
解决方法:
对象:
1、对象合并: Object.assign({}, obj1, obj2)
2、解构: {...obj1, ...obj2}
3、 json转化: JSON.parse(JSON.stringify(obj1))
数组:
1、解构: [...arr1, ...arr2]
2、 json转化: JSON.parse(JSON.stringify(arr1))
例子:
<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>
-
通过
arr = [...arr]
达到重新加载了数组 -
total 依赖数组的变化而更新值
条件渲染
svelte有着自己的一套模板语法,使用起来结构更加清晰.
条件渲染的条件是放在标签语法{#if }里面,而分支用{:else}分开,最终再以{/if}结束。
<script>
let flag = true;
</script>
{#if flag}
<div>A</div>
{:else}
<div>B</div>
{/if}
-
条件渲染也支持嵌套。
<script>
let flag = true;
let flag2 = false;
</script>
{#if flag}
<div>1</div>
{#if flag2}
<div>2</div>
{:else}
<div>3</div>
{/if}
{:else}
<div>4</div>
{/if}
列表渲染
同样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}
Await模板标签
svelte有个与promise配合使用的模板标签,以提高用户的体验感。
语法1:含等待、成功、失败状态(较为常用)
{#await Promise}
等待状态
{:then 成功值}
成功状态 //接收 resolve(成功的参数)
{/await}
语法2:不含失败和等待状态
{#await Promise then 成功值}
成功状态
{/await}
例子1、
<script>
let timer = new Promise((resolve) => {
setTimeout(() => {
resolve("倒计时完成");
}, 3000);
});
</script>
{#await timer}
loading...
{:then res}
{res}
{/await}
例子2、
<script>
let timer = new Promise((resolve) => {
setTimeout(() => {
resolve("倒计时完成");
}, 3000);
});
</script>
{#await timer then res}
{res}
{/await}
绑定Dom元素
可以通过bind:this,将元素绑定到具体的变量中去。
作用类似于 $ref
<script>
let input;
export function focus() {
input.focus();
}
</script>
<input bind:this={input} />
生命周期
svelte中的生命周期:
-
onMount
-
onDestroy
-
beforeUpdate
-
afterUpdate
<script>
import { onMount, onDestroy, beforeUpdate, afterUpdate } from 'svelte';
// 挂载期
onMount(async () => {
// 一般可以通过挂载来进行网络请求。
});
// dom节点更新前
beforeUpdate(() => {
// 用于记录dom节点更新前的状态
})
// dom节点更新后
afterUpdate(() => {
// 在dom接口更新后所需事件
})
// 卸载期
onDestroy(() => {
// 卸载工作
// 例如释放变量、删除时钟。
});
</script>
tick的用法
tick函数返回一个Promise, 你可以在任意地方使用tick。它的作用是:有了await tick()后,它不会里面刷新dom,而去等待下一次微任务就绪的时候(包括其他组件已经渲染完成)再继续往下执行。
<script>
import { tick } from "svelte";
let count = 0;
async function hello() {
count++;
new Promise((resolve) => {
setTimeout(() => {
resolve("hello");
}, 3000);
}).then((res) => {
console.log(res);
});
await tick();
console.log(count);
}
</script>
count: {count}
<button on:click={hello}>click me</button>
全局数据管理
当我们需要一个全局的数据仓库的时候,用此方法
新建 store.svelte文件:
import { writable } from 'svelte/store';
export const count = writable(0);
-
引入
writable
方法声明全局变量 -
导出一个名为
count
的变量了,并且初始值使用writable
标明了
接收全局变量值
在页面中需要先引入 全局变量
import { count } from './stores.js';
通过定义该页面的自定义变量来接收全局变量
语法:
"自定义变量名".subscribe((value)=>{"所进行的操作"})
<script>
let number;
//读取全局数据
count.subscribe((value) => {
number = value;
});
</script>
{{number}}
重置全局变量值
-
将值重置为新值
-
语法:
"全局变量名".set("具体值");
<button
on:click={() => {
count.set(1002);
}}>设置</button
>
操作全局变量值
-
通过uppdate方法来更新全局数据
-
语法
"全局变量名".update((val)=>{"所进行的操作"});
<button
on:click={() => {
count.update((val) => {
val++;
return val;
});
}}>-</button
>
只读全局仓库:只允许内部修改
export const time = readable(new Date(), function start(set) {
const interval = setInterval(() => {
set(new Date());
}, 1000);
return function stop() {
clearInterval(interval);
};
});
利用derived基于原有的仓库数据进行定义新变量
import { readable, derived } from 'svelte/store';
export const time = readable(new Date(), function start(set) {
const interval = setInterval(() => {
set(new Date());
}, 1000);
return function stop() {
clearInterval(interval);
};
});
const start = new Date();
export const elapsed = derived(
time,
$time => Math.round(($time - start) / 1000)
);
Axios的封装
安装axios:
npm install axios
fetch文件
export function fetch(uri, data, method = "POST", responseType = "json") {
return new Promise((resolve, reject) => {
axios({
url: BASEURL + uri,
method: method,
params: method === "GET" ? data : null,
data: method === "POST" ? data : null,
// headers: {
// "Content-Type": "application/json",
// },
responseType: responseType,
})
.then(function (response) {
resolve(response.data);
})
.catch(err => {
reject(err);
});
});
}
通过ajax请求数据
创建api.js文件,导入fetch文件。
在api.js写请求接口。
配置路由
路由配置
安装路由依赖:
npm install svelte-spa-router
定义路由:
import Home from './routes/Home.svelte'
import Author from './routes/Author.svelte'
import Book from './routes/Book.svelte'
import NotFound from './routes/NotFound.svelte'
const routes = {
// Exact path
'/': Home,
// Using named parameters, with last being optional
'/author/:first/:last?': Author,
// Wildcard parameter
'/book/*': Book,
// Catch-all
// This is optional, but if present it must be the last
'*': NotFound,
}
使用路由:
<body>
<Router {routes}/>
</body>
接收路由参数:
<script>
import {location, querystring} from 'svelte-spa-router'
</script>
<p>The current page is: {$location}</p>
<p>The querystring is: {$querystring}</p>
路由跳转:
声明式:
<script>
import {link} from 'svelte-spa-router'
let myLink = "/book/456"
</script>
<a use:link={myLink}>The Biggest Princess</a>
导航式:
import {push, pop, replace} from 'svelte-spa-router'
// The push(url) method navigates to another page, just like clicking on a link
push('/book/42')
// The pop() method is equivalent to hitting the back button in the browser
pop()
// The replace(url) method navigates to a new page, but without adding a new entry in the browser's history stack
// So, clicking on the back button in the browser would not lead to the page users were visiting before the call to replace()
replace('/book/3')
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 清华大学推出第四讲使用 DeepSeek + DeepResearch 让科研像聊天一样简单!
· 推荐几款开源且免费的 .NET MAUI 组件库
· 实操Deepseek接入个人知识库
· 易语言 —— 开山篇
· 【全网最全教程】使用最强DeepSeekR1+联网的火山引擎,没有生成长度限制,DeepSeek本体