上一次看Svelte是2019年,已经是两年前了。
如果需要写一些前端程序,所以又调研了以下这些前端框架,发现基本上还是那些老的框架的天下,比如reactjs,vuejs,angularjs等等。
不过Svelte发展的也不错,在github/svelte上也已经有5万多关注了。作为Rich Harris的个人作品,实在是不易。
Rich Harris在The truth about Svelte这篇博文中阐述了他对Svelte的原旨的一些理解。很多框架(Elm、Imba、Idyll、Marko)采用的方式跟Svelte差不多,但是Svelte能成功,是因为它对传统基于JavaScript的前端作成方式具有较小的侵入,易于被大众接受。
Svelte不基于Virtual DOM,所以性能较好。另一款不基于Virtual DOM的JS框架是solidjs,在各种性能测评中超过了Svelte,如今也超过了1万关注了。这篇是solidjs作者2019年些的solidjs与svelte的对比:JavaScript UI Compilers: Comparing Svelte and Solid。
尤大亲自评测 Vue3 和 Svelte(19个组件后Vue更好!)是一篇Vue和Svelte的对比,观点是组件多了的时候Svelte生成代码的尺寸缩放性可能有所不足。
Svelte学习
Tutorial
又把官方教程过了一遍。不得不说Svelte的文档工作做的很不错。
- Svelte用于创建组件,一个组件通常含有脚本标签,样式标签,以及其他页面元素标签构成。方便起见,写组件的时候将这些混合在一个文件中。
- 样式具有局部性,甚至不会应用于嵌套的子组件
- 为了将脚本中定义的变量应用到页面部分,采用的是模板变量,也就是形如
{name}
的方式。模板变量可以用于标签的内容以及属性的值之上。- 属性值不一定需要使用引号括起来
- 若变量与属性同名,则可以省略属性名和等号部分,例如
<img {src}>
‘
- 粘贴html字符串需要使用
{@html string}
,所以花括号并不是简单的变量替换,还可以指定一些开关- 还支持
{count === 1 ? 'time' : 'times'}
,可能花括号里面的是一个表达式
- 还支持
- 对属性名可以继续做文章,比如
on:click={incrementCount}
挂载事件处理器
- 反应性
$: doubled = count * 2
,这里的美元符号用于告诉svelte这个表达式需要再count变化的时候重新执行- 除了单个表达式,$还支持花括号括起来的表达式块,以及if语句等等
- 值得注意的是,$会延后执行所标记的表达式
- svelte只会检测=号来判断数据是否跟新,这一点千万别忘了,
+=
之类的也算 - 也可以触发对于标的辖属的反应式更i性能:
obj.foo += 1
,array[i] = x
- 一条规则,
const foo = obj.foo; foo.bar = 'baz';
不能触发对obj.foo.bar
的更新
- props辖属
- props用于声明组件的形式参数:
export let answer;
,实际参量通过标签的属性传递:<Nested answer={42}/>
- 参数可以指定默认值
- 参量可以从标的辖属中获取:
<Info {...pkg}/>
- props用于声明组件的形式参数:
- DOM事件
- 通过改写元素属性来描述事件的处理,比如:
<div on:mousemove={handleMousemove}>
- 也可以直接插入函数体,比如:
on:mousemove="{e => m = { x: e.clientX, y: e.clientY }}
- 可以加入额外的修饰符作为控制开关,比如:
<button on:click|once={handleClick}>
, - 可以串连操作符,比如:
on:click|once|capture={...}
- 其他控制符
- preventDefault
- stopPropagation
- passive (提高滚动性能,sevelte会自动添加)
- nonpassive
- capture 在下探阶段,而不是回弹阶段处理事件
- once 让事件只触发一次
- self 只在event.target是元素自身的时候触发
- trusted 只在event.isTrusted为真的时候触发
- 组件可以通过createEventDispatcher来派发事件
- createEventDispatcher 必须在组件初始化的时候调用
- 组件事件通过
on:message={handleMessage}
来处理,其中message
为自定义的事件名 - 组件事件不会回弹,需要显示上递,svelte提供了方便语法:
<Inner on:message/>
- 组件上递语法也可以用于DOM事件:
<button on:click>
- 通过改写元素属性来描述事件的处理,比如:
- 映照(bindings),也就是将DOM中的值对照到svelte中,或者反之映射到DOM中
- 简单的语法
<input bind:value={name}>
,用于将DOM中的值同步到svelte - 由于DOM中的值都是字符串,所以svelte提供了转化机制:
<input type=number bind:value={a} min=0 max=10>
- 对于复选框(checkbox),需绑定的是其checked属性:
<input type=checkbox bind:checked={yes}>
- 复选框如果指定了多个,需要绑定到一个数组:
<input type=checkbox bind:group={flavours} name="flavours" value={flavour}>
, - 单选框(radiobox)只能多选一,可以将多个绑定到同一个对照:
<input type=radio bind:group={scoops} name="scoops" value={1}>
- 文本区域与文本输入框差不多:
<textarea bind:value={value}>
,可以简写为<textarea bind:value>
- 单选列表的各项内容是对象,比如
<select bind:value={selected} on:change="{() => answer = ''}">
的selected是一个对象,可能只是使用其中的selected.value - 多选列表需要指定multiple,比如
<select multiple bind:value={flavours}>
- 也可以绑定可编辑内容,比如
<div contenteditable="true" bind:innerHTML={html}></div>
- 可以在
{#each todos as todo}
循环中对照到todo的某些辖属,注意这样会修改todos的内容 <audio>
以及<video>
等媒体元素可以有若干辖属可供绑定- 每个部块元素都有clientWidth, clientHeight, offsetWidth, offsetHeight四个辖属可以对照
- 每个DOM元素或组件标的上都有this可以对照,但是只在组件标的的生命周期里有效
- 组件定义的派入项(props)也可以用来对照
- 简单的语法
- 存续周期(lifecycle)
- 存续周期的各通告函数,在SSR时不会触发,且必须在组件初始化的时候设置
- onMount在组件挂载到DOM时触发
- onMount可以返回一个函数,在组件销毁时调用
- onDestroy在组件销毁时调用
- beforeUpdate和afterUpdate用于在DOM更新当前或者随后执行一些代码
- tick可以将代码的执行延迟到下一个间隙(svelte是以microtask为间隔更新DOM的
- store
- 组件的状态是局部的,这时候就需要全局的状态协调,store就是干这事的
- store提供只读或者读写的存储标的,一般定义在额外的js文件中,供其他组件引用。
- 存储标的可以有set和update等操作,set接受的是值,update接受的是一个更新函数。
- 可以订阅存储标的的更新,值得注意的是,订阅之后要注意退订,若组件消解的时候没有退订,则会导致内存泄漏
- svelte提供了
{$count}
这种语法帮助自动订阅和退订 - 存储标的之间还可以组合
- 只要一个标的正确实现了subscribe,那么就是一个合格的存储标的,可以用于
{$count}
这种语法 - 只要一个存储标的实现了set,就可以将其作为对照使用,比如
<input bind:value={$name}>
- 也可以直接对其进行赋值:
<button on:click="{() => $name += '!'}">
,相当于name.set($name + '!')
- motion(行动特效)
- tweened由svelte/motion提供,可以用来控制渐进性
- svelte/easing则提供一些渐进性函数,比如cubicOut
- spring则是由svelte/motion提供的另一个动作方式,可以对快速的变换做一些迟滞
- transition(过场特效)
- svelte/transition提供预设的过场函数,比如fade:
<p transition:fade>Fades in and out</p>
- 有的过场支持参数:
<p transition:fly="{{ y: 200, duration: 2000 }}">
- 入场和出场都可以设置不同的特效:
<p in:fly="{{ y: 200, duration: 2000 }}" out:fade>
- 可以自定义基于CSS以及JS的过场
- 通过订阅on:introstart、on:outrostart、on:introend、on:outroend等事件可以探知过场的开始和结束
- 默认情况下,过场会在任意的上级元素变更时触发,为了防止这一点,可以开启过场的局部性:
<div transition:slide|local>
- 过场可以推后执行,并与其他元素协调
- 可以用
{#key }
模块来强制更新某元素子树,从而使之可以适配过场动画
- svelte/transition提供预设的过场函数,比如fade:
- Animations(动画特效)
- 略
- 动作(action)
- 动作是元素级别的代谢周期函数,
<div class="box" use:pannable ...>
将pannable
动作挂载到此元素上- 动作可以接收额外的参数,比如
<button use:longpress={duration}
- 槽位(slot)
- 如何让一个组件从外接收另一个组件作为其子元素
- 办法是在组件内部预留槽位,可以预设默认值
- 办法是某个组件的时候,必须在其包含区域指定要接收的其他组件
- 如果想要多个槽位,必须给每个槽位命名,然后被接收的标的上必须指定目标槽位的名字
$$slots
这个特殊变量用于提供传入的嵌套组件- 给槽位传派入值:
<slot hovering={hovering}></slot>
- 那嵌套组件如何知道有这个派入值存在呢,需要使用这种形式
<Hoverable let:hovering={active}>
来主动告知
- 上下文(context)
- 上下文和存储标的不同,前者只能用在某组件及其下属组件上,且不具有反应性;后者则可以用于全局,且有反应性
- 特定元素
<svelte:self>
可以让组件重复自身,但是使用时别忘了设置终止条件哦<svelte:component>
用于在运行时绘制组件<svelte:window>
用于在window范围侦听事件,用于破除组件的局部性- 还可以对照window的innerWidth、innerHeight、outerWidth、outerHeight、scrollX、scrollY,online (window.navigator.onLine)
- 以上除了scrollX 和scrollY以外皆只读
<svelte:body>
用于在body上侦听事件,用于破除组件的局部性<svelte:head>
用于在head上侦听事件,用于破除组件的局部性<svelte:options>
用于指定编译选项immutable={true}
可以简化编译器检查,默认不开accessors={true}
为组件的派入提供读写器,默认不开namespace="..."
组件的命名空间,使用时的常见值时"svg“tag="..."
将组件编译成web自定义元素时用的名字
<svelte:fragment>
作为一个虚拟容器,用于组织落放到槽位的内容
- 模块上下文(module context)
<script context="module">
- 声明的代码只会在模块加载的时候运行一次
- 其中export的是js意义上的export
- 模块的默认导出是组件自身
- 调试
- 可以用
{(console.log(user), '')}
打印错误信息 - 也可以用
{@debug user}
来激活调试器,@debug
后面跟的是逗号分隔列表
- 可以用
examples
比教程里面的例子多一些。
其他
- Major new addition to Svelte: global state management (think Redux/MobX/Vuex, but for Svelte) via
svelte/store
- https://www.freecodecamp.org/news/the-svelte-handbook/
- Svelte tutorials
- Building a simple Svelte JS app
- Svelte for Sites, React for Apps
- How to test Svelte components
Web Component
- https://javascript.plainenglish.io/can-you-build-web-components-with-svelte-3c8bc3c1cfd8
- https://css-tricks.com/using-custom-elements-in-svelte/
- https://dev.to/silvio/how-to-create-a-web-components-in-svelte-2g4j
javascript相关
- Event loop: microtasks and macrotasks
- Microtasks
- Using microtasks in JavaScript with queueMicrotask
- In depth: Microtasks and the JavaScript runtime environment
- What was the motivation for introducing a separate microtask queue which the event loop prioritises over the task queue?
- Tasks, microtasks, queues and schedules
老问题
其他框架
- https://github.com/ionic-team/stencil Stencil: A Compiler for Web Components and PWAs
- https://lit-element.polymer-project.org/guide 用于创建组件,是polymer的遗留物
- 看了Elm的https://guide.elm-lang.org/architecture/,感觉理念跟erlang接近,当然Elm的类型推导比erlang的丰富
- What are the best alternatives to Svelte?
其他
- 作者加入Vercel了:Vercel welcomes Rich Harris, creator of Svelte
- 受Svelte启发的https://github.com/malinajs/malinajs
(完)
2022-03-22更新
可以从https://svelte.dev/blog/the-easiest-way-to-get-started开始你的Svelte之旅。
(更新完)
2022-03-24更新:Svelte搭配Vite
在Svelte工程中使用vite。
从Getting Started 看,只要
yarn create vite my-svelte-app --template svelte
# 或
yarn create vite my-svelte-ts-app --template svelte
具体的工程模板在仓库vite/packages/create-vite/中。
通过yarn create -h
查看到的帮助信息是Creates new projects from any create-* starter kits.
,应该使用的是create-vite这个包。
yarn应该会自动去下载create-vite料包,放置在全局处。
此处有vite的社区模板https://github.com/vitejs/awesome-vite#templates
具体使用方法(以npm为例):
npx degit user/project my-project
cd my-project
npm install
npm run dev
Creating a Svelte, Vite, and TailwindCSS 3 Template
作者已经写了一篇针对SvelteKit的文章SvelteKit/Vite/Tailwind,所以这篇是针对Svelte的。
SvelteKit默认使用Vite作为打合器。
命令行如下:
# for TypeScript use --template svelte-ts
npm init vite@latest my-svelte-app -- --template svelte
cd my-svelte-app
npm install
# 添加tailwindcss
npx svelte-add@latest tailwindcss
npm install
此处的npx svelte-add@latest
用法有点新奇。
另外npm init -h
给出的帮助信息是Create a package.json file
。
其他参考
- How to configure Svelte project with Vite so that the static files are not copied during the build?
- How to Set up Svelte using Vite, TypeScript and Tailwind CSS
- Is Vite currently the best bundler for Svelte?
- 2020年的文章,列举它是因为例子中使用了pnpm。
- Making a simple note app using Svelte and Vite
- Tailwind CSS and Svelte
- vite-plugin-svelte/Frequently Asked Questions
SvelteKit相关
- When to use Svelte vs SvelteKit vs Sapper?
- [What’s the deal with SvelteKit?](What’s the deal with SvelteKit?)
(更新完)
2022-03-24更新:Svelte Routing
Svelte Society Day 2020: Rich Harris: Frequently Asked Questions 380s讲了为啥Svelte没有Vue那样默认的router。简单地说,因为可选的太多了,各有优劣。
Harris的口音不像是美国的。
- What routing library with Svelte?
- 列举了router
- https://routify.dev/
- https://github.com/EmilTholin/svelte-routing (server side)
- https://github.com/jorgegorka/svelte-router (SPA, i tested, I had an issue: https://github.com/jorgegorka/svelte-router/issues/63, seems not active project)
- https://github.com/ItalyPaleAle/svelte-spa-router (SPA. I tested. Works well. There is no beforeeach function. But i found a workaround : https://github.com/ItalyPaleAle/svelte-spa-router/issues/112)
- http://visionmedia.github.io/page.js/
- https://github.com/lukeed/navaid
- https://github.com/TehShrike/abstract-state-router/
- 同时提到i8n的一些内容
- 列举了router
(更新完)
2022-03-24更新:Svelte UI框架
8 Popular Svelte UI Components列举了
- https://github.com/shinokada/flowbite-svelte
- https://github.com/hperrin/svelte-material-ui
- https://github.com/carbon-design-system/carbon-components-svelte
- https://github.com/matyunya/smelte
- https://github.com/bestguy/sveltestrap
- https://github.com/c0bra/svelma
- https://github.com/illright/attractions
- https://github.com/vikignt/svelte-mui
- https://github.com/AlexxNB/svelte-chota
- Framework7 Svelte
- Svelte-flow
Overview of Svelte UI Libraries and Components 列举了
- Svelte Material UI
- Smelte
- Carbon Components Svelte
- Svelte Materialify
- Sveltestrap
- Attractions
- SvelteChota
- Notus Svelte
- Svelthree
- Felte
- Svelte Mapbox
- Svelte Calendar
- Svelte-Grid
其他清单
其他参考
(更新完)