从0-1Vite + Svelte
1.前言
node版本:v20.11.1
编辑器:trae
最终实现一个管理后台项目
https://gitee.com/tcyyyy/vite---svelte 后台项目仓库
2.学习目录:
a.创建 vite + svelte 应用
b.认识 svelte
c.学习svelte语法
2.创建 vite + svelte 应用
npx create-vite@latest . --template svelte --yes
命令简单解析 .:路径参数在当前目录初始化项目 --template svelte:模板选择 --yes:自动应答 跳过所有交互式问答

出现上图就是执行成功了
咱们按照提示的 命令执行完毕 先把项目跑起来

上图 就是代表项目能正常跑起来了

这个时候咱们看代码是没有着色的
可以在插件市场安装
Svelte for VS Code

以上就是安装 Svelte for VS Code 之后的代码着色
以上就是搭建的全部过程了
3.代码学习
3.1 从 hello svelte! 入门😁

上图就是 修改过后的 app.svelte 文件

上图就是页面展示 字段
<script> </script> <h1>hello svelte!</h1> <style> </style>
script 标签里面 是我们写js代码的地方
style 是我们写样式的
html 代码 写在两个标签中间即可
3.2 声明变量添加数据
<script> let name = 'svelte' </script> <h1>hello {name}!</h1> <style> </style>

页面还是 咱们刚才所见
3.3动态属性
<script> let name = 'svelte' let src = '/src/assets/image/svelte.png'; </script> <div> <img {src} alt="{name} dances." /> <h1>hello {name}!</h1> </div> <style> </style>

以上代码 页面展示
3.4声明组件
创建一个 svelte 文件 写入描述

上图就是新建的一个组件
<script> import ONE from './component/one.svelte' let name = 'svelte' let src = '/src/assets/image/svelte.png'; </script> <div> <ONE /> <img {src} alt="{name} logo." /> <h1>hello {name}!</h1> </div> <style> </style>
以上代码描述主要是如何 引入组件 组件名称要大写用来区分html标签
3.5解析html标签


<script> import ONE from './component/one.svelte' let name = 'svelte' let src = '/src/assets/image/svelte.png'; let htmlText = `<img src="/src/assets/image/svelte.png" alt="{name} logo." />` </script> <div> {@html htmlText} <ONE /> <img {src} alt="{name} logo." /> <h1>hello {name}!</h1> </div> <style> </style>
3.6响应事件 深度反应性

以上代码可以实现上图功能
3.7 $derived使用
<script> let numbers = $state([1, 2, 3, 4]); let total = $derived(numbers.reduce((t, n) => t + n, 0)); function addNumber() { numbers.push(numbers.length + 1); } </script> <p>{numbers.join(' + ')} = {total}</p> <button onclick={addNumber}> 添加数字得出总数 </button>
以上代码 即可实现下方逻辑

$derived 作用
·自动响应依赖变化
·高效 - 只在依赖变化时重新计算
·可以在组件中多次使用
·替代了 Svelte 之前版本中的 $: 语法(虽然 $: 仍然可用)
3.8 $inspect使用
<script> let numbers = $state([1, 2, 3, 4]); let total = $derived(numbers.reduce((t, n) => t + n, 0)); function addNumber() { numbers.push(numbers.length + 1); } $inspect(numbers).with(console.trace); </script> <p>{numbers.join(' + ')} = {total}</p> <button onclick={addNumber}> Add a number </button>
$inspect作用
·监听 numbers 这个响应式变量的所有变化 (所示代码:$inspect(numbers))
·每当 numbers 被修改时,都会触发回调(所示代码:$inspect(numbers))
·将变化信息通过 console.trace 输出到控制台(所示代码:.with(console.trace))
·会显示完整的调用堆栈(trace),让你知道是代码中的哪一部分导致了 numbers 的变化(所示代码:.with(console.trace))

3.9$effect使用
<script> let elapsed = $state(0); let interval = $state(1000); $effect(() => { const id = setInterval(() => { elapsed += 1; }, interval); return () => { clearInterval(id); }; }); </script> <button onclick={() => interval /= 2}>加速</button> <button onclick={() => interval *= 2}>减速</button> <p>elapsed: {elapsed}</p>
以上代码 即可实现一下页面展示
$effect 说明
·$effect 是一个运行时声明 类似于 React 的 useEffect ,但语法更简洁
·Svelte 会自动检测 effect 内部使用的响应式变量(如 interval )
·当这些变量变化时,effect 会重新运行
注意:$effect 主要用于处理副作用(如定时器、事件监听、API 调用等),常规的状态计算应该使用 $derived

3.10父组件向子组件单值传递
父组件:
<script> import NESTED from './component/Nested.svelte'; </script> <NESTED answer={100} /> <NESTED/>
子组件 使用$props接收 传递值
<script> let { answer } = $props(); </script> <p>answer: {answer}</p>
3.11父组件向子组件多值传递
父组件 传递使用...拓展符进行传递
子组件 接收还是通过$props <script> let { one, two } = $props(); </script> <p> 1: {one} </p> <p> 2: {two} </p>
以上代码即可实现下方逻辑

3.12html表达逻辑 if
<script> let count = $state(0); function increment() { count += 1; } </script> <button onclick={increment}> count:{count} </button> {#if count > 10} <p>count:{count} count大于10了</p> {/if}
以上代码即可实现以下逻辑

3.13html表达逻辑 if else
以上代码即可实现下方逻辑

3.14循环渲染模板
<script> const colors = ['red', 'orange', 'yellow', 'green', 'blue', 'indigo', 'violet']; let selected = $state(colors[0]); </script> <h1 style="color: {selected}">点击下方按钮修改字体颜色</h1> <div> {#each colors as color, i} <button style="background: {color}" aria-label={color} aria-current={selected === color} onclick={() => selected = color} >{i + 1}</button> {/each} </div> <style> h1 { transition: color 0.2s; font-size: 2rem; font-weight: 700; } div { display: grid; grid-template-columns: repeat(7, 1fr); grid-gap: 5px; max-width: 400px; } button { aspect-ratio: 1; border-radius: 50%; background: var(--color, #fff); transform: translate(-2px,-2px); filter: drop-shadow(2px 2px 3px rgba(0,0,0,0.2)); transition: all 0.1s; color: black; font-weight: 700; font-size: 2rem; } button[aria-current="true"] { transform: none; filter: none; box-shadow: inset 3px 3px 4px rgba(0,0,0,0.2); } </style>

主要是用 #each 来循环dom colors 数组 as color 数组项, i 下标
·简洁直观的语法
·自动响应式更新
·作用域隔离
3.15给每个块设置唯一键
父项目
<script> import Nested from './component/Nested.svelte'; let things = $state([ { id: 1, name: 'apple' }, { id: 2, name: 'banana' }, { id: 3, name: 'carrot' }, { id: 4, name: 'doughnut' }, { id: 5, name: 'egg' } ]); </script> <button onclick={() => things.shift()}> 删除第一个 </button> {#each things as thing (thing.id)} <Nested name={thing.name} /> {/each}
子项目
以上代码即可实现一下效果

3.16标记promis等待中值
<script> import { roll } from './utils.js'; let promise = $state(roll()); </script> <button onclick={() => promise = roll()}> 掷骰子 </button> {#await promise} <p>...加载</p> {:then number} <p>你掷出了{number}!</p> {:catch error} <p style="color: red">{error.message}</p> {/await}
utils.js 文件 export async function roll() { return new Promise((fulfil, reject) => { setTimeout(() => { if (Math.random() < 0.3) { reject(new Error('Request failed')); return; } fulfil(Math.ceil(Math.random() * 6)); }, 1000); }); }
以上代码即可实现已选展示逻辑

3.17DOM events
<script> let m = $state({ x: 0, y: 0 }); function onpointermove(event) { m.x = event.clientX; m.y = event.clientY; } </script> <div onpointermove={onpointermove}> 指针位于{Math.round(m.x)} x {Math.round(m.y)}处 </div> <style> div { position: fixed; left: 0; top: 0; width: 100%; height: 100%; padding: 1rem; } </style>
onpointermove事件可以简写为 {onpointermove}
以下是内联事件处理
以上代码可以实现以下逻辑

3.18捕获Capturing
<div onkeydowncapture={(e) => alert(`<div> ${e.key}`)} role="presentation">
<input onkeydowncapture={(e) => alert(`<input> ${e.key}`)} />
</div>
3.19组件事件
父组件 <script> import Stepper from './component/Stepper.svelte'; let value = $state(0); </script> <p>当前值为 {value}</p> <Stepper increment={() => value += 1} decrement={() => value -= 1} /> 子组件 <script> let { increment, decrement } = $props(); </script> <button onclick={decrement}>-1</button> <button onclick={increment}>+1</button>
以上代码实现以下逻辑

3.20text input
<script> let name = $state('world'); </script> <input bind:value={name} /> <h1>Hello {name}!</h1>
以上代码实现以下效果

3.21复选框
<script> let yes = $state(false); </script> <label> <input type="checkbox" bind:checked={yes} /> 是否订阅 </label> {#if yes} <p> 订阅 </p> {:else} <p> 不订阅 </p> {/if} <button disabled={!yes}>订阅</button>
以上代码即可实现以下逻辑

3.22反转卡片实列
<script> let flipped = $state(false); </script> <div class="container"> 翻转卡片 <button class={["card", { flipped }]} onclick={() => flipped = !flipped} > <div class="front"> <span class="symbol">♠</span> </div> <div class="back"> <div class="pattern"></div> </div> </button> </div> <style> .container { display: flex; flex-direction: column; gap: 1em; height: 100%; align-items: center; justify-content: center; perspective: 100vh; } .card { position: relative; aspect-ratio: 2.5 / 3.5; font-size: min(1vh, 0.25rem); height: 80em; border-radius: 2em; transform: rotateY(180deg); transition: transform 0.4s; transform-style: preserve-3d; padding: 0; user-select: none; cursor: pointer; } .card.flipped { transform: rotateY(0); } .front, .back { display: flex; align-items: center; justify-content: center; position: absolute; width: 100%; height: 100%; left: 0; top: 0; backface-visibility: hidden; border-radius: 2em; border: 1px solid var(hsl(206, 20%, 90%)); box-sizing: border-box; padding: 2em; } .front { background-size: 8em 8em, 8em 8em; } .back { transform: rotateY(180deg); } .symbol { font-size: 30em; } .pattern { width: 100%; height: 100%; background-color: hsl(206, 20%, 90%); /* pattern from https://projects.verou.me/css3patterns/#marrakesh */ background-image: radial-gradient(hsl(206, 20%, 80%) 0.9em, transparent 1em), repeating-radial-gradient(hsl(206, 20%, 80%) 0, hsl(206, 20%, 80%) 0.4em, transparent 0.5em, transparent 2em, hsl(206, 20%, 80%) 2.1em, hsl(206, 20%, 80%) 2.5em, transparent 2.6em, transparent 5em); background-size: 3em 3em, 9em 9em; background-position: 0 0; border-radius: 1em; } </style>
以上代码即可实现以下逻辑

3.23组件样式
父组件 <script> import Box from './component/box.svelte'; </script> <div class="boxes"> <Box --color="red" /> <Box --color="green" /> <Box --color="blue" /> </div> 子组件 <div class="box"></div> <style> .box { width: 5em; height: 5em; border-radius: 0.5em; margin: 0 0 1em 0; background-color: var(--color, #ddd); } </style>
以上代码可实现以下效果

3.24动画交互
<script> import kitten from './kitten.png'; let hereKitty = $state(false); </script> <svelte:body onmouseenter={() => hereKitty = true} onmouseleave={() => hereKitty = false} /> <img class={{ curious: hereKitty }} alt="Kitten wants to know what's going on" src={kitten} /> <style> img { position: absolute; left: 0; bottom: -60px; transform: translate(-80%, 0) rotate(-15deg); transform-origin: 100% 100%; transition: transform 0.4s; } .curious { transform: translate(-15%, 0) rotate(0deg); } :global(body) { overflow: hidden; } </style>
以上代码可实现以下逻辑

猫的图放在这里了

https://gitee.com/tcyyyy/vite---svelte 后台项目仓库
本文来自博客园,作者:樱桃树下的约定,转载请注明原文链接:https://www.cnblogs.com/tcyweb/p/18838238

浙公网安备 33010602011771号