svelte笔记

svelte

    • 特性
    • 编译过程
    • 使用场景
    • 创建项目
      • 问题1:build报错
    • 基本语法
      • 响应式变量
      • if语句
      • for循环
      • await加载数据
      • Event
      • 组件通信
        • 父子组件
        • 跨组件通信
      • store
      • slot插槽
      • 生命周期
        • tick
        • onMount
        • onDestroy
    • SvelteKit 与 Svelte 的区别
      • 项目结构
      • 路由
      • +page
        • +page.svelte
        • +page.js/ts
      • +error
      • +layout
      • +layout.svelte
        • layout.server.ts
      • load方法的参数
      • 发起 fetch 请求

‌Svelte‌是一个 编译型框架,以其独特的编译时优化机制著称,具有轻量级、高性能和易上手等特性。Svelte通过编译器将声明式组件转换为高效的JavaScript代码,直接更新DOM,从而提供高性能的Web应用。

特性

  1. 编译时优化‌:Svelte在编译阶段处理大部分逻辑,减少运行时的工作量,生成高度优化的原生JavaScript代码‌。
    • Svelte 的响应式系统基于观察者模式,但其独特之处在于它在构建阶段就识别出哪些变量是响应式的,并生成相应的更新代码。这意味着在运行时,Svelte 只需执行必要的 DOM 更新,无需额外的运行时框架代码来维护响应性。
    • Svelte 应用在开发时可能需要稍长的构建时间,但生产环境的性能很好。
  2. 轻量级‌:Svelte组件简洁且高效,适合构建轻量级Web项目‌。
  3. 高性能‌:由于编译时处理,Svelte应用在运行时表现非常流畅,适合构建复杂的交互式应用‌。
  4. 易上手‌:Svelte使用HTML、CSS和JavaScript,开发者可以快速上手并利用已有的技能‌。

编译过程

  • 代码提取:将框架相关的代码从组件中分离出来。
  • 代码优化:消除不必要的运行时检查和绑定。
  • 代码生成:生成优化后的 JavaScript 代码,只包含必要的运行时逻辑。

使用场景

Svelte特别适合构建以下类型的Web应用:

  • 个人项目‌:由于其轻量级和易上手的特性,Svelte是个人项目和小型项目的理想选择。
  • 交互式应用‌:由于编译时优化和高效执行,Svelte能够处理复杂的用户交互和数据更新。
  • 现代Web应用‌:结合SvelteKit,可以快速构建现代Web应用,并享受其高性能和易用性。

创建项目

npx sv create myapp
cd myapp
npm install
npm run dev
  • 应用的每个页面都是一个 Svelte 组件
  • 通过在项目的 src/routes 目录中添加文件来创建页面。这些页面将被服务端渲染,以确保用户首次访问您的应用时速度尽可能快,之后客户端应用将接管

问题1:build报错

上述操作启动项目,执行 npm run build时报错,配置fallback

https://svelte.dev/docs/kit/single-page-apps#Usage

svelte笔记_第1张图片

// svelte.config.js
kit: {
    adapter: adapter({
        fallback: '200.html'
    }),
}

基本语法

响应式变量

计算属性、watch监听

<script lang="ts">
	let count = 0;
    // 计算属性
    $: doubleCount = count * 2;
    // watch监听
    $: if (count) {
        console.log('✨file:+page.svelte:11✨✨ ', count);
    }
    function handleAdd() {
        count++;
    }

    function handleSub() {
        count--;
    }
script>

<button on:click={handleSub}>button>
<span>{count}span>
<button on:click={handleAdd}>button>
<span>{doubleCount}span>

if语句

{#if count < 3}
    <p>我是count小于3的时候显示的p>
{:else if count >= 3 && count <= 6} 
    <p>我是count 大于等于 3 并且 小于等于 6的时候显示的p>
{:else}
    <p>我是不符合的时候显示的p>
{/if}

for循环

<script lang="ts">
	// for
    let cats = [
        {id: '1', name: 'Cat1'},
        {id: '2', name: 'Cat2'},
        {id: '3', name: 'Cat3'},
    ]
    const addCat = () => {
        cats.push({id: cats.length +1+'', name: 'Cat' + (cats.length +1)});
        console.log('✨file:+page.svelte:22✨addCat✨ ', cats);
        cats = [...cats]
    }
script>
<div>
    

await加载数据

<script lang="ts">
   let cats = [
        {id: '1', name: 'Cat1'},
        {id: '2', name: 'Cat2'},
        {id: '3', name: 'Cat3'},
    ]
     //  网络请求
    async function sleep() {
        return new Promise(resolve => {
            setTimeout(() => {
                resolve(cats);
            }, 2e3)
        })
    }

    let request: Promise<any> = loadData();

    function handleRequest() {
        request = loadData();
    }

    async function loadData() {
        return await sleep();
    }
script>

<div>
    <button on:click={handleRequest}>加载数据button>
    {#await request}
        <p>loading...p>
    {:then list}
        <ul>
            {#each list as cat (cat.id)}
                <li>{cat.name}li>
            {/each}
        ul>
    {/await}
div>

Event

<script lang="ts">
    let m = {x:0, y:0}
    function handleMove(event) {
        m.x = event.clientX;
        m.y = event.clientY;
    }

    const handleMoveClick = () => {
        console.log('✨file:+page.svelte:56✨handleMoveClick✨ ');
    }
script>
<div class="box" on:mousemove={handleMove} role="application">
    the mouse position is {m.x} X {m.y}
div>

<div>
    <button on:click|once={handleMoveClick}>只可点击一次button>
div>
<style>
    .box {
        width: 500px;
        height: 200px;
        border: 1px solid black;
    }
style>

组件通信

父子组件

child.svelte

<script lang="ts">
    let {addSuccess, msg} = $props();
script>
<div>
    <h1>Child {msg}h1>
    

parent.svelte

<script lang="ts">
    import Child from "./Child.svelte";
    //     子组件
    const handleSubDeflate = (e: any) => {
        console.log('✨父组件:子组件点击回调事件✨ ', e);
    }
script>


<Child msg="hello world" addSuccess={handleSubDeflate}/>
跨组件通信

child.svelte

<script lang="ts">
    import {getContext} from "svelte";

    let {addSuccess, msg} = $props();

    const pubMsg = getContext('pubMsg');

script>
<div>
    <h1>Child {msg}h1>
    <p>上下文数据:{pubMsg}p>
    

parent.svelte

<script lang="ts">
    import Child from "./Child.svelte";
    import {setContext} from "svelte";
    //     子组件
    const handleSubDeflate = (e: any) => {
        console.log('✨父组件:子组件点击回调事件✨ ', e);
    }
    // 设置数据
    setContext('pubMsg', '我是公共数据')
script>



<Child msg="hello world" addSuccess={handleSubDeflate}/>

store

store/userStore.ts

import {type Writable, writable} from 'svelte/store'

interface User {
    id: string
    userName: string
}
export const userStore: Writable<User | null> = writable(null)

页面使用store

<script lang="ts">

    import {userStore} from "../../store/userStore";

    const handleSetInfo = () => {
        userStore.set({
            userName: 'zs',
            id: '1'
        })
    }
    const updateUser = () => {
        userStore.update((user: any) => {
            user.userName = 'abc'
            return user;
        })
    }
script>
<h1>个人资料h1>
{#if $userStore}
    <p>{$userStore.userName} --- {$userStore.id}p>
{/if}
<button on:click={handleSetInfo}>设置用户信息button>
<button on:click={updateUser}>更新用户信息button>

slot插槽

child.svelte

<script lang="ts">

script>
<div class="card">
    <slot name="header">default Headerslot>
    <slot>default contentslot>
    {#if $$slots.footer}
        <slot name="footer">slot>
    {/if}
div>
<style>
    .card {
        border: 1px solid #eeeeee;
    }
style>

使用组件

<script lang="ts">
import Child from "./Child.svelte";
script>

<Child>
    <h1 slot="header">头部h1>
    <p>组件内容<br>组件内容<br>组件内容<br>组件内容p>
    <h2 slot="footer">底部h2>
Child>

生命周期

tick

tick()函数是一个重要的生命周期函数,用于处理异步操作和DOM更新‌。在Svelte中,tick()函数确保所有的DOM更新都已完成,这对于处理依赖于DOM更新的逻辑非常有用。

<script lang="ts">
    import {tick} from "svelte";

    let text = 'Select some text and hit the tab key to toggle uppercase'

    const handleKeydown = (event: any) => {
        if (event.key !== 'Tab') return;

        if (event.target) {
            const {selectionStart, selectionEnd, value} = event.target;
            const selection = value.slice(selectionStart, selectionEnd);

            const replacement = /[a-z]/.test(selection)? selection.toUpperCase() : selection.toLowerCase();
            text = value.slice(0, selectionStart) + replacement + value.slice(selectionEnd);

            tick().then(() => {
                event.target.selectionStart = selectionStart;
                event.target.selectionEnd = selectionEnd;
            })

        }
    }
script>

<textarea bind:value={text} on:keydown|preventDefault={handleKeydown}>textarea>

<style>
    textarea {
        width: 100%;
        height: 200px;
    }
style>
onMount
import {onMount} from "svelte";

onMount(() => {
    console.log("mounted");
});
onDestroy
<script>
	import { onDestroy } from 'svelte';

	onDestroy(() => {
		console.log('onDestroy');
	});
script>

SvelteKit 与 Svelte 的区别

SvelteKit 是一个使用 Svelte 快速开发稳健、高性能 Web 应用程序的框架。如果您来自 React,SvelteKit 类似于 Next。如果您来自 Vue,SvelteKit 类似于 Nuxt。

Svelte 负责渲染 UI 组件。您可以组合这些组件并仅使用 Svelte 渲染整个页面,但要构建完整的应用程序,您需要的不仅仅是 Svelte。

SvelteKit 帮助您在遵循现代最佳实践的同时构建 Web 应用,并为常见的开发挑战提供解决方案。它提供从基本功能 —— 比如在点击链接时更新 UI 的路由 —— 到更高级的功能。

它的广泛功能列表包括:仅加载最小所需代码的构建优化;离线支持;用户导航前的页面预加载;通过 SSR、浏览器客户端渲染或构建时预渲染来处理应用程序不同部分的可配置渲染;图像优化;等等。使用所有现代最佳实践构建应用程序非常复杂,但 SvelteKit 为您处理了所有繁琐的工作,这样您就可以专注于创造性的部分。

它利用带有 Svelte 插件的 Vite 来实现热模块替换 (HMR),从而在浏览器中即时反映代码更改,提供闪电般快速且功能丰富的开发体验。

项目结构

my-project/
├ src/
│ ├ lib/
│ │ ├ server/
│ │ │ └ [您的仅服务端库文件]
│ │ └ [您的库文件]
│ ├ params/
│ │ └ [您的参数匹配器]
│ ├ routes/
│ │ └ [您的路由]
│ ├ app.html
│ ├ error.html
│ ├ hooks.client.js
│ ├ hooks.server.js
│ └ service-worker.js
├ static/
│ └ [您的静态资源]
├ tests/
│ └ [您的测试]
├ package.json
├ svelte.config.js
├ tsconfig.json
└ vite.config.js

路由

SvelteKit 的核心是一个基于文件系统的路由器。

  • src/routes 是根路由
  • src/routes/about 创建一个 /about 路由
  • src/routes/blog/[slug] 创建一个带有参数 slug 的路由,当用户请求类似 /blog/hello-world 的页面时,可以用它动态加载数据

每个路由目录包含一个或多个路由文件,这些文件可以通过它们的 + 前缀识别。

简单的规则:

  • 所有文件都可以在服务端上运行
  • 除了 +server 文件外,所有文件都在客户端运行
  • +layout+error 文件不仅适用于它们所在的目录,也适用于子目录

+page

+page.svelte

+page.svelte 组件定义了您应用程序的一个页面。默认情况下,页面在初始请求时在服务端渲染(SSR),在后续导航时在浏览器中渲染(CSR)。

+page.js/ts

通常,页面在渲染之前需要加载一些数据。为此,我们添加一个 +page.js 模块,该模块导出一个 load 函数:

这个函数与 +page.svelte 一起运行,这意味着它在服器端渲染期间在服务端上运行,在客户端导航期间在浏览器中运行。有关该 API 的完整详细信息,请参见 load

除了 load+page.js 还可以导出一些值用于配置页面行为:

  • export const prerender = truefalse'auto' // 预渲染

  • export const ssr = truefalse

    • 通常,SvelteKit 会先在服务端上渲染您的页面,并将该 HTML 发送到客户端,如果您将 ssr 设置为 false,它会改为渲染一个空的“外壳”页面。这在您的页面无法在服务端上渲染时(例如使用了只在浏览器可用的全局对象 document)会有用,但在大多数情况下并不推荐这样做(请参阅附录)。
    • 如果您在根 +layout.js 中添加 export const ssr = false,那么整个应用只会在客户端被渲染——这实际上意味着您将应用变成了一个 SPA。
  • export const csr = truefalse

    • 些页面根本不需要 JavaScript —— 很多博客文章或“关于”页面就是这种情况。对于这类页面,您可以禁用 CSR:

    • 禁用 CSR 不会向客户端发送任何 JavaScript。这意味着:

      • 网页只能通过 HTML 和 CSS 来工作。
      • 所有 Svelte 组件中的

你可能感兴趣的:(web,笔记)