{"id":16183927,"url":"https://github.com/crazymryan/study-svelte","last_synced_at":"2026-01-20T19:32:20.955Z","repository":{"id":117841092,"uuid":"318729328","full_name":"CrazyMrYan/study-svelte","owner":"CrazyMrYan","description":null,"archived":false,"fork":false,"pushed_at":"2020-12-05T07:33:24.000Z","size":2259,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-07-06T13:02:14.254Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"HTML","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/CrazyMrYan.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2020-12-05T07:29:49.000Z","updated_at":"2020-12-05T07:33:26.000Z","dependencies_parsed_at":"2024-08-08T11:03:45.542Z","dependency_job_id":null,"html_url":"https://github.com/CrazyMrYan/study-svelte","commit_stats":{"total_commits":2,"total_committers":1,"mean_commits":2.0,"dds":0.0,"last_synced_commit":"bcf1f059dcad72ca0941cb36778a4a8597a0b644"},"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/CrazyMrYan/study-svelte","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/CrazyMrYan%2Fstudy-svelte","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/CrazyMrYan%2Fstudy-svelte/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/CrazyMrYan%2Fstudy-svelte/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/CrazyMrYan%2Fstudy-svelte/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/CrazyMrYan","download_url":"https://codeload.github.com/CrazyMrYan/study-svelte/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/CrazyMrYan%2Fstudy-svelte/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":28610608,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-01-20T18:56:40.769Z","status":"ssl_error","status_checked_at":"2026-01-20T18:54:26.653Z","response_time":117,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.5:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-10-10T07:08:20.020Z","updated_at":"2026-01-20T19:32:20.939Z","avatar_url":"https://github.com/CrazyMrYan.png","language":"HTML","readme":"### 说在前面\n\n`svelte` 不知道大家有没有了解过，最近一次偶然刷文章，看到一篇[《都快2020年，你还没听说过SvelteJS?》](https://zhuanlan.zhihu.com/p/97825481) [0] 的文章，看了svelte与其他框架的对比\n\n[svelte 中文 doc](https://www.firecat.run/) [1]\n\n对比各框架开发的项目的尺寸\n\n![对比各框架开发的项目的尺寸](./1.jpg)\n\n\n\n对比各项目的 Lighthouse 性能评分\n\n![对比各项目的 Lighthouse 性能评分](./640.jpg)\n\n\n\n说实话属实有点惊讶到我。 ** 真的假的？\n\n于是我抱着试试就试试的心态来做个评测人\n\n\n\n### 关于虚拟DOM\n\nsvelte 的作者 Rich Harris 在一篇名为[《虚拟DOM纯粹是开销》](https://svelte.dev/blog/virtual-dom-is-pure-overhead) [2] 的文章中指出，为什么不使用虚拟dom\n\n虚拟dom的三个步骤\n\n1. 两个快照都包含一个元素。在两种情况下都是`\u003cdiv\u003e`，这意味着我们可以保留相同的DOM节点\n2. 我们列举了新旧属性上的所有属性，`\u003cdiv\u003e`以查看是否需要更改，添加或删除任何属性。在这两种情况下，我们都有一个属性-a`className`的值为`\"greeting\"`\n3. 下降到元素中，我们看到文本已更改，因此我们需要更新真实的DOM\n\n而 svelte 直接跳过前面两步，直接执行第三步\n\n\n\n```javascript\nif (changed.name) {\n  text.data = name;\n}\n```\n\n这几乎就是Svelte生成的更新代码。与传统的UI框架不同，Svelte是一种编译器，它在*构建时*就知道应用程序中的*情况*如何变化，而不必等着在*运行时*进行工作。\n\n\n\n### 业内大牛如何看待 svelte\n\nvue 的作者尤雨溪，在知乎回答了个 [《如何看待 svelte 这个前端框架？》](https://www.zhihu.com/question/53150351) [3] 问题\n\n![](./image-20201130170959194.png)\n\n“svelte 的核心思想在于 **通过静态编译来减少框架运行时的代码**”\n\n\n\n### 关于 UI\n\n我觉着这两个ui还是比较不错的\n\n**Material UI**\n\nhttps://sveltematerialui.com/\n\nhttps://github.com/hperrin/svelte-material-ui\n\n\n\n**SVELTESTRAP**\n\nhttps://sveltestrap.js.org/\n\nhttps://github.com/bestguy/sveltestrap\n\n\n\n### svelte 与其他框架\n\n老严闲来的时候找到了 一个叫做 `Realworld` 存储库中有24种conduit实现As ，也就是用来对比性能的以及大小的；\n\n今天一起来对比一下 vue/react/svelte 这三个框架的 \n\n- 项目打包后压缩包大小\n- 项目网页性能分析对比\n\n\n\nvue：https://github.com/gothinkster/vue-realworld-example-app\n\nreact：https://github.com/gothinkster/react-redux-realworld-example-app\n\nsvelte：https://github.com/sveltejs/realworld\n\n感兴趣的同学也可以看看其他框架 https://github.com/gothinkster/realworld\n\n![](./image-20201201175253834.png)\n\n#### 开始打包\n\n这三个项目，打包顺序基本上在同一时间执行 `npm run build`，svelte 直接在我我眨眼的一瞬间打完包 ，啪 很快啊 （有点夸张~几秒钟）\n\n静静的等待vue和react同时打包完之后，我开始进行统一压缩静态文件，压缩格式为zip\n\n\n\n#### 对比大小\n\n排名如下\n\n1. svelte   —  89.9 KB\n2. vue       —  483 KB\n3. react     —  490 KB\n\n果然差距还是确实如传说一样恐怖\n\n\n\n#### 性能考核\n\n严老湿本次使用 Chrome 的 Lighthouse （谷歌网页性能分析工具） 来对比性能评分 \n\n全局安装 `lighthouse`\n\n```shell\nnpm install -g lighthouse\n```\n\n执行 （直接使用的对应的线上地址）\n\n```shell\nlighthouse https://realworld.svelte.dev/\n```\n\n这是我在下面所测试的截屏\n\nvue \n\n![](./image-20201203171006602.png)\n\nreact\n\n![](./image-20201203171137276.png)\n\nsvelte\n\n![](./image-20201203171339234.png)\n\n#### 对比性能\n\n性能得分排名如下：\n\n1. svelte   —  83\n2. react    —  52\n3. vue      —  32\n\n`svelte` 也是不负众望 稳居第一\n\n\n\n### 使用 svelte 模板\n\n看到上面，天天被逼着做性能优化的同学，激动起来了 ~ 那我们一起来简单学习一下这个性能强悍的 svelte 吧\n\nsvelte 模板 [4] ，我们直接使用一个模板来开工\n\n```shell\ngit clone https://github.com/sveltejs/template\n\u0026\ncd template-master\n```\n\n\n\n### 下载依赖\n\n```shell\nyarn install \nor \nnpm install\n```\n\n下载完成之后，我们看看目录。老严的评价就是 `简洁`\n\n![](./image-20201130113835071.png)\n\n### 启动项目\n\n```shell\nyarn dev\nor\nnpm run dev\n```\n\n启动完成之后\n\n```shell\n  Your application is ready~! �\n\n  - Local:      http://localhost:5000\n  - Network:    Add `--host` to expose\n```\n\n\n\n### 打开页面\n\n地址栏输入 `http://localhost:5000`\n\n![image-20201130113222571](./image-20201130113222571.png)\n\n我们可以看到这样的一个页面 hello world\n\n### 安装ui\n\n这里我们使用 sveltestrap\n\n```javascript\nnpm install --save sveltestrap \nnpm install --save bootstrap\n```\n\n在 main.js 中引入\n\n```javascript\nimport 'bootstrap/dist/css/bootstrap.min.css';\n```\n\n在页面中引入组件\n\n```js\n\u003cscript\u003e\n\timport { Button } from \"sveltestrap\";\n\tconst handleClick = () =\u003e alert(\"I warned you!\");\n\u003c/script\u003e\n\n\u003cButton color=\"danger\" on:click={handleClick}\u003eDo Not Press\u003c/Button\u003e\n```\n\n![](./image-20201205104807542.png)\n\n\n\n### 简单了解语法\n\n在学习之前我觉得有必要简单了解一下其语法\n\n#### 绑定数据\n\n在 vue 中我们的变量需要写在 `data` 中 ，而 `svelte` 语法更加贴合原生\n\n``` html\n\u003c!-- vue --\u003e\ndata() {\n\treturn {\n\t\tname: 'hhh',\n\t};\n}\n\n\u003cdiv\u003e{{name}}\u003c/div\u003e\n```\n\n\n\nsvelte 绑定数据 ，svelte 动态绑定需要加上 {}\n\n```html\n\u003cscript\u003e\n\timport { Button } from \"sveltestrap\";\n\t// 定义数据\n\tlet name = \"hhh\";\n\tlet src = 'http://crazy-x-lovemysoul-x-vip.img.abc188.com/images/logo.png';\n\u003c/script\u003e\n\u003c!-- 绑定数据 --\u003e\n\u003c!-- 如果kv一致只用写一个 --\u003e\n\u003cimg {src} alt=\"\"\u003e\n\u003cButton\u003e{name}\u003c/Button\u003e\n```\n\n![](./image-20201205114940929.png)\n\n#### 条件渲染\n\nvue 中有条件渲染 `v-if`  `v-else-if` `v-else` ,svelte 也有\n\n```html\n\u003cscript\u003e\n\tlet condition = 1;\n\u003c/script\u003e\n{#if condition == 2}\n\t\u003cp\u003e悲\u003c/p\u003e\n{:else if condition == 1}\n\t\u003cp\u003e伤 \u003c/p\u003e\n{:else if condition == 0}\n\t\u003cp\u003e日\u003c/p\u003e\n{:else}\n\t\u003cp\u003e记\u003c/p\u003e\n{/if}\n```\n\n![](./image-20201205133217424.png)\n\n#### 循环渲染\n\n循环渲染列表\n\n```html\n\u003cscript\u003e\n    // 定义变量\n\tlet news = [\n        { id: 1, title: '拜登呼吁必须停止把对手当敌人' },\n        { id: 2, title: '江苏响水致78死爆炸案一审宣判' },\n        { id: 3, title: '嫦娥五号将择机实施月面软着陆' }\n    ];\n\u003c/script\u003e\n\n\n\u003cul\u003e\n    \u003c!-- 有没有点 ejs的感觉 --\u003e\n\t{#each news as {title}}\n\t\t\u003cli\u003e\n\t\t\t\u003ca href=\"https://www.baidu.com/s?rsv_idx=1\u0026wd={title}\"\u003e\n\t\t\t\t{title}\n\t\t\t\u003c/a\u003e\n\t\t\u003c/li\u003e\n\t{/each}\n\u003c/ul\u003e\n\n\n\u003cstyle\u003e\n\tul,li{\n\t\tlist-style: none;\n\t}\n\ta{\n\t\tcolor: #ff3e00;\n\t}\n\u003c/style\u003e\n```\n\n![](./image-20201205133722710.png)\n\n咋感觉有点像 `ejs` 循环渲染呢  [5]呢?\n\n\n\n#### 事件绑定\n\n在 `svelte` 中方法直接写函数定义函数即可使用\n\n```html\n\u003cscript\u003e\n\timport { Button } from \"sveltestrap\";\n\t// 定义数据\n\tlet name = \"hhh\",title = '标题';\n\t// 定义方法\n\tconst handleClick = () =\u003e {\n\t\tname = \"严老湿\"\n\t\ttitle = \"老严带你入坑 svelte\"\n\t};\n\u003c/script\u003e\n\u003c!-- on:click 绑定方法  {绑定动态值}--\u003e\n\u003cButton color=\"danger\" on:click={handleClick}\u003e{name}\u003c/Button\u003e\n\u003ch1\u003e{title}\u003c/h1\u003e\n```\n\n![](./方法.gif)\n\n\n\n#### 组件\n\n组件是框架必不可少的一个功能\n\n来看看 svelte 中如何创建一个组件吧\n\napp.svelte \n\n```html\n\u003cscript\u003e\n    // 直接引入组件即可使用 无需注册\n\timport Child from './components/child.svelte'\n\tlet name = '我是你爹'\n\u003c/script\u003e\n\n\u003cdiv\u003e\n\t{name}\n\t\u003cChild\u003e\u003c/Child\u003e\n\u003c/div\u003e\n```\n\n创建一个 child.svelte 页面\n\n```html\n\u003cscript\u003e\n    let title = '我是你儿子'\n\u003c/script\u003e\n\n\u003cdiv\u003e{title}\u003c/div\u003e\n```\n\n\n\n![image-20201205140934477](./image-20201205140934477.png)\n\n那么组件有了，我们来看看组件传值吧！\n\n##### 传值\n\napp.svelte \n\n```html\n\u003cscript\u003e\n\timport Child from './components/child.svelte'\n\tlet name = '我是你爹'\n\tlet childName = \"狗剩\"\n\u003c/script\u003e\n\n\u003cdiv\u003e\n\t{name}\n\t\u003cChild {childName}\u003e\u003c/Child\u003e\n\u003c/div\u003e\n```\n\n\n\nchild.svelte \n\n```html\n\u003cscript\u003e\n    export let childName;\n\u003c/script\u003e\n\n\u003cdiv\u003e爹给我取的名字是 {childName}\u003c/div\u003e\n```\n\n![](./image-20201205141812363.png)\n\n刚刚我们是简单的单一传值\n\n接下来我们传一个对象试试\n\napp.svelte \n\n```html\n\u003cscript\u003e\n\timport Child from './components/child.svelte'\n\tlet name = '我是你爹'\n\tlet aboutMe = {\n\t\tname:'狗剩',\n\t\tage:18,\n\t\tgender:'man'\n\t}\n\u003c/script\u003e\n\n\u003cdiv\u003e\n\t{name}\n    \u003c!-- 通过... 展开 aboutMe --\u003e\n\t\u003cChild {...aboutMe}\u003e\u003c/Child\u003e\n\u003c/div\u003e\n```\n\nchild.svelte \n\n``` html\n\u003cscript\u003e\n    export let name,gender,age;\n\u003c/script\u003e\n\n\u003cdiv\u003e我取的名字是 {name}\u003c/div\u003e\n\u003cdiv\u003e我取的年龄是 {age}\u003c/div\u003e\n\u003cdiv\u003e我取的性别是 {gender}\u003c/div\u003e\n```\n\n![](./image-20201205142824450.png)\n\n那这多费劲呐？还需要一个个接收。有一话叫存在即合理\n\n\n\n#### 动画\n\n在官方 api 中提到 svelte 提供了一些动画效果出来给大家使用\n\n![](./image-20201205140449260.png)\n\n我们直接使用官方示例 淡入淡出动画\n\n```html\n\u003cscript\u003e\n\timport { fade } from 'svelte/transition';\n\tlet visible = true;\n\u003c/script\u003e\n\n\u003clabel\u003e\n\t\u003cinput type=\"checkbox\" bind:checked={visible}\u003e\n\tvisible\n\u003c/label\u003e\n\n{#if visible}\n\t\u003cp transition:fade\u003e\n\t\tFades in and out\n\t\u003c/p\u003e\n{/if}\n```\n\n![](./动画.gif)\n\n#### 生命周期\n\n在 svelte 中的生命周期有onMount 、beforeUpdate 、afterUpdate 、afterUpdate 下面老严依次给大家伙列出来\n\n- onMount （挂载后）\n\n  该`onMount`函数作为将component挂载到DOM后立即执行的回调。它必须在component初始化期间被调用（但不必位于component内部；可以从外部模块调用它）。\n\n  ```html\n  \u003cscript\u003e\n      import { onMount } from 'svelte';\n  \n      onMount(() =\u003e {\n          console.log('the component has mounted');\n      });\n  \u003c/script\u003e\n  ```\n\n  如果需要`onMount`返回一个函数，则在卸载 component 时调用该函数。\n\n  ```html\n  \u003cscript\u003e\n  \timport { onMount } from 'svelte';\n  \n  \tonMount(() =\u003e {\n  \t\tconst interval = setInterval(() =\u003e {\n  \t\t\tconsole.log('beep');\n  \t\t}, 1000);\n  \n  \t\treturn () =\u003e clearInterval(interval);\n  \t});\n  \u003c/script\u003e\n  ```\n\n  \n\n- beforeUpdate （更新前）\n\n  `beforeUpdate`任何状态更改后组件更新之前，回调函数会立即运行。第一次回调运行将在初始onMount之前.\n\n  ```html\n  \u003cscript\u003e\n      import { beforeUpdate } from 'svelte';\n  \n      beforeUpdate(() =\u003e {\n          console.log('the component is about to update');\n      });\n  \u003c/script\u003e\n  ```\n\n\n\n- afterUpdate （更新后)\n\n  `afterUpdate`在组件更新后立即运行回调\n\n  ```html\n  \u003cscript\u003e\n      import { afterUpdate } from 'svelte';\n  \n      afterUpdate(() =\u003e {\n          console.log('the component just updated');\n      });\n  \u003c/script\u003e\n  ```\n\n\n\n- onDestroy（销毁后）\n\n  在组件卸载后运行回调。在onMount、beforeUpdate、afterUpdate和onDestroy中，这是唯一一个在服务器端组件中运行的组件。\n\n  ```html\n  \u003cscript\u003e\n      import { onDestroy } from 'svelte';\n  \n      onDestroy(() =\u003e {\n          console.log('the component is being destroyed');\n      });\n  \u003c/script\u003e\n  ```\n\n\n\n\n\n### 案例\n\n老严逛着逛着 正好看到一个 官方示例的 `to do list` 本来还想着说带大家做，那既然有现成的，将就一下\n\n没有什么框架是写一个 todolist 还学不会的 ，老严在代码里面也加了一些代码注释\n\n因为样式代码 太多,我们先上效果图再看代码\n\n![](./todolist.gif)\n\n```html\n\u003cscript\u003e\n\timport { quintOut } from 'svelte/easing';\n\timport { crossfade } from 'svelte/transition';\n\timport { flip } from 'svelte/animate';\n\t// 动画\n\tconst [send, receive] = crossfade({\n\t\tduration: d =\u003e Math.sqrt(d * 200),\n\n\t\tfallback(node, params) {\n\t\t\tconst style = getComputedStyle(node);\n\t\t\tconst transform = style.transform === 'none' ? '' : style.transform;\n\t\t\treturn {\n\t\t\t\tduration: 600,\n\t\t\t\teasing: quintOut,\n\t\t\t\tcss: t =\u003e `\n\t\t\t\t\ttransform: ${transform} scale(${t});\n\t\t\t\t\topacity: ${t}\n\t\t\t\t`\n\t\t\t};\n\t\t}\n\t});\n\n\tlet uid = 1;\n\t// 默认数据\n\tlet todos = [\n\t\t{ id: uid++, done: false, description: 'write some docs' },\n\t\t{ id: uid++, done: false, description: 'start writing blog post' },\n\t\t{ id: uid++, done: true,  description: 'buy some milk' },\n\t\t{ id: uid++, done: false, description: 'mow the lawn' },\n\t\t{ id: uid++, done: false, description: 'feed the turtle' },\n\t\t{ id: uid++, done: false, description: 'fix some bugs' },\n\t];\n\t// 新增待办\n\tfunction add(input) {\n\t\tconst todo = {\n\t\t\tid: uid++,\n\t\t\tdone: false,\n\t\t\tdescription: input.value\n\t\t};\n\n\t\ttodos = [todo, ...todos];\n\t\tinput.value = '';\n\t}\n\t// 删除方法\n\tfunction remove(todo) {\n\t\ttodos = todos.filter(t =\u003e t !== todo);\n\t}\n\t// 选中方法\n\tfunction mark(todo, done) {\n\t\ttodo.done = done;\n\t\tremove(todo);\n\t\ttodos = todos.concat(todo);\n\t}\n\u003c/script\u003e\n\n\u003cdiv class='board'\u003e\n    \u003c!-- 点击回车执行add  --\u003e\n\t\u003cinput\n\t\tplaceholder=\"what needs to be done?\"\n\t\ton:keydown={e =\u003e e.which === 13 \u0026\u0026 add(e.target)}\n\t\u003e\n\t\u003c!-- 代办 --\u003e\n\t\u003cdiv class='left'\u003e\n\t\t\u003ch2\u003etodo\u003c/h2\u003e\n\t\t{#each todos.filter(t =\u003e !t.done) as todo (todo.id)}\n\t\t\t\u003clabel\n\t\t\t\tin:receive=\"{{key: todo.id}}\"\n\t\t\t\tout:send=\"{{key: todo.id}}\"\n\t\t\t\tanimate:flip\n\t\t\t\u003e\n\t\t\t\t\u003c!-- 选中代表已做完 --\u003e\n\t\t\t\t\u003cinput type=checkbox on:change={() =\u003e mark(todo, true)}\u003e\n\t\t\t\t{todo.description}\n\t\t\t\t\u003c!-- 删除 --\u003e\n\t\t\t\t\u003cbutton on:click=\"{() =\u003e remove(todo)}\"\u003eremove\u003c/button\u003e\n\t\t\t\u003c/label\u003e\n\t\t{/each}\n\t\u003c/div\u003e\n\t\u003c!-- 已完成 --\u003e\n\t\u003cdiv class='right'\u003e\n\t\t\u003ch2\u003edone\u003c/h2\u003e\n\t\t{#each todos.filter(t =\u003e t.done) as todo (todo.id)}\n\t\t\t\u003clabel\n\t\t\t\tclass=\"done\"\n\t\t\t\tin:receive=\"{{key: todo.id}}\"\n\t\t\t\tout:send=\"{{key: todo.id}}\"\n\t\t\t\tanimate:flip\n\t\t\t\u003e\n\t\t\t\t\u003c!-- 修改状态为代办 --\u003e\n\t\t\t\t\u003cinput type=checkbox checked on:change={() =\u003e mark(todo, false)}\u003e\n\t\t\t\t{todo.description}\n\t\t\t\t\u003c!-- 删除 --\u003e\n\t\t\t\t\u003cbutton on:click=\"{() =\u003e remove(todo)}\"\u003eremove\u003c/button\u003e\n\t\t\t\u003c/label\u003e\n\t\t{/each}\n\t\u003c/div\u003e\n\u003c/div\u003e\n\n\u003cstyle\u003e\n\t.board {\n\t\tdisplay: grid;\n\t\tgrid-template-columns: 1fr 1fr;\n\t\tgrid-gap: 1em;\n\t\tmax-width: 36em;\n\t\tmargin: 0 auto;\n\t}\n\n\t.board \u003e input {\n\t\tfont-size: 1.4em;\n\t\tgrid-column: 1/3;\n\t}\n\n\th2 {\n\t\tfont-size: 2em;\n\t\tfont-weight: 200;\n\t\tuser-select: none;\n\t\tmargin: 0 0 0.5em 0;\n\t}\n\n\tlabel {\n\t\tposition: relative;\n\t\tline-height: 1.2;\n\t\tpadding: 0.5em 2.5em 0.5em 2em;\n\t\tmargin: 0 0 0.5em 0;\n\t\tborder-radius: 2px;\n\t\tuser-select: none;\n\t\tborder: 1px solid hsl(240, 8%, 70%);\n\t\tbackground-color:hsl(240, 8%, 93%);\n\t\tcolor: #333;\n\t}\n\n\tinput[type=\"checkbox\"] {\n\t\tposition: absolute;\n\t\tleft: 0.5em;\n\t\ttop: 0.6em;\n\t\tmargin: 0;\n\t}\n\n\t.done {\n\t\tborder: 1px solid hsl(240, 8%, 90%);\n\t\tbackground-color:hsl(240, 8%, 98%);\n\t}\n\n\tbutton {\n\t\tposition: absolute;\n\t\ttop: 0;\n\t\tright: 0.2em;\n\t\twidth: 2em;\n\t\theight: 100%;\n\t\tbackground: no-repeat 50% 50% url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath fill='%23676778' d='M12,2C17.53,2 22,6.47 22,12C22,17.53 17.53,22 12,22C6.47,22 2,17.53 2,12C2,6.47 6.47,2 12,2M17,7H14.5L13.5,6H10.5L9.5,7H7V9H17V7M9,18H15A1,1 0 0,0 16,17V10H8V17A1,1 0 0,0 9,18Z'%3E%3C/path%3E%3C/svg%3E\");\n\t\tbackground-size: 1.4em 1.4em;\n\t\tborder: none;\n\t\topacity: 0;\n\t\ttransition: opacity 0.2s;\n\t\ttext-indent: -9999px;\n\t\tcursor: pointer;\n\t}\n\n\tlabel:hover button {\n\t\topacity: 1;\n\t}\n\u003c/style\u003e\n```\n\n\n\n当你可以手动写出这个todolist的时候，你就已经出师了，因为老严也就这点能耐 哈哈\n\n最后代码，我提交到了git 有需要的同学可以去下载噢\n\n### 注解\n\n[0] https://zhuanlan.zhihu.com/p/97825481\n\n[1] https://www.firecat.run/\n\n[2] https://svelte.dev/blog/virtual-dom-is-pure-overhead\n\n[3] https://www.zhihu.com/question/53150351\n\n[4] https://github.com/sveltejs/template\n\n[5] https://ejs.bootcss.com/#docs\n\n\n\n### 参考文献\n\n- https://www.firecat.run/docs\n- https://zhuanlan.zhihu.com/p/97825481\n- https://iiong.com/sveltejs-study-notes/","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcrazymryan%2Fstudy-svelte","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fcrazymryan%2Fstudy-svelte","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcrazymryan%2Fstudy-svelte/lists"}