写给 React 或者 Vue 同学的 Svelte 尝鲜和踩坑

缘起

去年因为某个博文了解到 Svelte,但是一直不敢丢大项目尝试,最近手头上有个小项目,然后就尝试了一下,会 React 或者 Vue 的上手会特别快。
官方文档
官方教程
API文档
本文章阅读,默认有 Vue 或者 React 的基础

初始化

Vite 2 已将全面支持 SvelteSvelte 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 ,同样的也支持预处理语言,例如模板模板引擎 pugscript 方面支持 typescript coffeescript 等,同样的,style 支持 scssless 等。
详细的预处理器支持可以在 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 就是不行。
除去遇到的这个问题,总的来说,开发体验挺棒,也有可能是我用到特性比较少的原因

© 版权声明
THE END
喜欢就支持一下吧
点赞0 分享