缘起
去年因为某个博文了解到 Svelte
,但是一直不敢丢大项目尝试,最近手头上有个小项目,然后就尝试了一下,会 React
或者 Vue
的上手会特别快。
官方文档
官方教程
API文档
本文章阅读,默认有 Vue
或者 React
的基础
初始化
Vite 2
已将全面支持 Svelte
和 Svelte ts
了,可以通过 Vite
初始化项目
# npm 6.x svelte | svelte-ts
npm init @vitejs/app my-vue-app --template svelte-ts
# npm 7+, 需要额外的双横线:
npm init @vitejs/app my-vue-app -- --template svelte-ts
# yarn
yarn create @vitejs/app my-vue-app --template svelte-ts
复制代码
Svelte组件
Svelte
的组件文件类型是 .svelte
,特别长,类似于 Vue
的单文件组件,Svelte
组件也氛围三个区块,html
script
style
,同样的也支持预处理语言,例如模板模板引擎 pug
,script
方面支持 typescript
coffeescript
等,同样的,style
支持 scss
,less
等。
详细的预处理器支持可以在 svelte-preprocess
这个包里面看到
export { default as pug } from './processors/pug';
export { default as coffeescript } from './processors/coffeescript';
export { default as typescript } from './processors/typescript';
export { default as less } from './processors/less';
export { default as scss, default as sass } from './processors/scss';
export { default as stylus } from './processors/stylus';
export { default as postcss } from './processors/postcss';
export { default as globalStyle } from './processors/globalStyle';
export { default as babel } from './processors/babel';
export { default as replace } from './processors/replace';
复制代码
使用方式比较简单,和 Vue
一致,在标签里面加入 lang=""
的属性
<script lang="ts"></script>
<style lang="less"></style>
复制代码
不过由于 svelte
也是通过调用现成的包来实现预编译的,所以在使用预处理语言的时候,需要引入对应的预处理器,比如 scss
需要引入 sass
或者 node-sass
,不然会有报错,其他语言同理,如下
Cannot find any of modules: sass,node-sass
Error: Cannot find module 'node-sass'
Require stack:
- /Users/fengqinglingyu/sevlte/node_modules/_svelte-preprocess@4.7.2@svelte-preprocess/dist/modules/utils.js
- /Users/fengqinglingyu/sevlte/node_modules/_svelte-preprocess@4.7.2@svelte-preprocess/dist/autoProcess.js
- /Users/fengqinglingyu/sevlte/node_modules/_svelte-preprocess@4.7.2@svelte-preprocess/dist/index.js
- /Users/fengqinglingyu/sevlte/svelte.config.cjs
复制代码
Svelte模板
Svelte
的模板和 jsx
写法差不多,还有一部分类似 nunjuck
这种模板引擎的写法,上手非常简单,而且组件允许多个根元素
<!-- 类似 JSX type={type} 可以缩写成 {type},同样也可以用展开运算符 -->
<button {type} {...spreadProps}>
Clicked {count} {count === 1 ? 'time' : 'times'}
</button>
<p>{count} doubled is {doubled}</p>
<h1>Hello {name}!</h1>
<p>{a} + {b} = {a + b}.</p>
<!-- 条件渲染 -->
{#if x > 10}
<p>{x} is greater than 10</p>
{:else if 5 > x}
<p>{x} is less than 5</p>
{:else}
<p>{x} is between 5 and 10</p>
{/if}
<!-- 列表渲染 -->
<!-- cats 是原始数组, as 后面第一个参数是数组的项,第二个参数是数组项目的索引,括号内的是类似 `React` 列表渲染的 `key` 属性 -->
{#each cats as cat, i (i)}
<li><a target="_blank" href="">
{i + 1}: {cat.name}
</a></li>
{/each}
<!-- 异步渲染,比较类似 Flutter 的 FutureBuilder -->
{#await promise}
<p>...waiting</p>
{:then number}
<p>The number is {number}</p>
{:catch error}
<p style="color: red">{error.message}</p>
{/await}
复制代码
组件状态
组件内定义的变量就是组件的状态,如果状态发生改变,那么组件会重新渲染
<script>
let count = 0;
function handleClick() {
count += 1;
}
</script>
<button on:click={handleClick}>
Clicked {count} times
</button>
复制代码
组件反应式声明
当页面的某些状态改变,依赖别的状态或者属性的时候,可以用函数,也可以用反应式声明,和 Vue
的计算属性类似
<script>
let count = 0;
$: doubled = count * 2;
</script>
<div>{count}</div>
<div>{doubled}</div>
复制代码
组件外部属性
组件的某些状态需要依赖父组件传递,这种称之为组件的属性
Svelte
使用 export
关键字将变量声明标记为属性,export
并不是传统 ES6
的那个导出,是一种语法糖写法,注意只要 export let
是声明属性,export const
export function
export class
这些写法为组件的只读属性,不会接受外面的传值
Svelte
<!-- Child.svelte -->
<script>
// 不带默认值的属性
export let answer;
// 带默认值的属性,在父组件没有传这个属性的时候,会用默认值 0
export let count = 0;
// 千万不要写 const ,写了不报错,但是这样写组件不会接受外部的传进来的值,一个大坑
export const sum = 0;
// 这里即使父组件传了 10000,这里的值依旧是 0
</script>
<p>The answer is {answer}</p>
<!-- Parent.svelte -->
<script>
import Child from './Child.svelte';
</script>
<Child answer={42} count={1000} sum={10000} />
复制代码
事件绑定
事件绑定用的是 on:eventName
,和 Vue
一样,支持修饰符
<div on:click={increment}>test</div>
<!-- 阻止默认事件 -->
<div on:click|preventDefault={increment}>test</div>
<!-- 阻止事件冒泡 -->
<div on:click|stopPropagation={increment}>test</div>
<!-- 多修饰器组合 -->
<div on:click|once|preventDefault|stopPropagation={increment}>test</div>
复制代码
组件生命周期
Svelte
组件的生命周期有不少,主要用到的还是 onMount
onDestoy
beforeUpdate
afterUpdate
onMount
的设计也和 useEffect
的设计差不多,如果返回一个函数,返回的函数将会在组件销毁后执行,和 onDestoy
一样
<script>
onMount(() => {
// 在组件挂载到 DOM 后立即执行的回调
return () => {
// 在组件被销毁的后执行的回调,和 onDestroy 周期一致
}
})
onDestoy(() => {
// 在组件被销毁的后执行的回调
})
</script>
复制代码
使用感受
这次因为是个小项目,没有太多去尝试 Svelte
的一些比较复杂的功能,有 Vue
或者 React
基础的话,上手特别快,就有些语法糖要适应, export const
还是卡了不少时间,按正常思维,属性是不可变的,但是使用 export const
就是不行。
除去遇到的这个问题,总的来说,开发体验挺棒,也有可能是我用到特性比较少的原因