svelte 上手初体验

开发前准备工作

安装插件:Svelte for VS Code
安装 demo 项目 npm create vite@latest my-app -- --template svelte
或者使用 svelteKit 来安装项目 npx create svelte@latest my-app

svelte 的特点

  • 不使用虚拟DOM
  • 重编译 轻运行时
  • 更少的code
  • 无障碍友好(对于一些不规范的标签写法,会有提示)
  • 可作为单独的组件开发,嵌入其他的技术栈的项目中。

svelte 生命周期

声明周期对于每个应用/组件来说都十分重要,各个框架总体来说也大同小异。

onMount

组件初始化的生命周期,在此处进行异步数据的获取。此外,如果 onMount 函数返回一个函数,这个函数会在组件销毁时调用。

<script>
	import { onMount } from 'svelte';

	let photos = [];

	onMount(async () => {
		const res = await fetch(`/tutorial/api/album`);
		photos = await res.json();
	});
</script>

onDestroy

顾名思义,用来组件销毁时进行逻辑处理,如清除定时器,解除监听事件之类的。

<script>
	import { onDestroy } from 'svelte';

	let counter = 0;
	const interval = setInterval(() => counter += 1, 1000);

	onDestroy(() => clearInterval(interval));
</script>

beforeUpdate & afterUpdate

DOM 更新前后分别触发,值得注意的是,初始化的时候,beforeUpdate 会先于 onMount 执行。

beforeUpdate(() => {
	autoscroll = div && (div.offsetHeight + div.scrollTop) > (div.scrollHeight - 20);
});

afterUpdate(() => {
	if (autoscroll) div.scrollTo(0, div.scrollHeight);
});

上手开发

基础语法:

  • 数据绑定/属性绑定:使用 {} 符号包裹。
  • 样式:在.svelte文件里面声明 style 标签。这种方式与 vue 类似,不同的是它是只作用于组件,相当于 scoped
  • 渲染html: {@html }
  • 事件绑定:on:click={}
  • 双向绑定:<input bind:value={inputValue} bind:checked={isChecked}/>, 对于单选和多选框的双向绑定,使用 bind:group={selectValue} 来实现。
  • 计算属性:$: 。 不知道该怎么表达,就用了 vue 里面的相等概念。
  • 组件传值 props:export let childProps = 'inital value'; 。这样就表示声明了一个 childProps 的值,在引用组件的时候可以通过 childProps={} 来给组件传值。其中默认赋值不是必须的。
  • 事件装饰器:内置的用来约束 DOM 绑定事件的装饰器,用法与 vue 类似,写法有点区别 - <div on:click|once={handleClick}></div>。框架提供的的装饰器有:preventDefault stopPropagation passive capture nonpassive once self trusted

入口文件

入口文件引入主组件,和公共样式。

import App from './App.svelte'

const app = new App({
  target: document.getElementById('app')
})

export default app

.svelte文件

这个文件整体和 .vue 差不多,都有 style 标签和 script 标签,不同的是不需要 template 标签来包裹。

模板语法

条件判断

条件判断的写法还算中规中矩,如果有用过模板语法或者PHP之类的,应该不陌生,很好上手。

{#if user.loggedIn}
<button on:click={toggle}>
Log out
</button>
{:else}
	<button on:click={toggle}>
		Log in
	</button>
{/if}

循环

循环的写法就略微有些怪异了,用了一个 as 关键字,我第一次写的时候就搞错了,习惯性就打出来一个 in - 。-

<script>
	let cats = [
		{ id: 'J---aiyznGQ', name: 'Keyboard Cat' },
		{ id: 'z_AbfPXTKms', name: 'Maru' },
		{ id: 'OUtn3pvWmpg', name: 'Henri The Existential Cat' }
	];
	let name = 'caaaaaat'
</script>
<ul>
	{#each cats as cat}
		<li><a target="_blank" href="https://www.youtube.com/watch?v={cat.id}">
			{cat.name}
		</a></li>
	{/each}
</ul>

除此之外,也可以用解构的方式,将数组的对象属性拍平。不过需要注意的是,如果数组内对象的属性和组件的其他响应式值重名时,在循环内部是获取不到这个重名的响应式值的。所以尽量不要重名哦,不然会造成使用上的困扰。

<ul>
  <script>
  	let cats = [
  		{ id: 'J---aiyznGQ', name: 'Keyboard Cat' },
  		{ id: 'z_AbfPXTKms', name: 'Maru' },
  		{ id: 'OUtn3pvWmpg', name: 'Henri The Existential Cat' }
  	];
  	let name = 'caaaaaat'
  </script>
	<!-- open each block -->
	{name}
	{#each cats as {name, id}}
		<li><a target="_blank" href="https://www.youtube.com/watch?v={id}">
			{name}
		</a></li>
	<!-- close each block -->
	{/each}
</ul>

还有一点值得注意的是,使用数组方法操作数组时,为了保证正确的响应,需要加上key。声明的方式是 for things as thing (thing.id), 括号内的就是 key。

异步模块

这个模块很方便很好用,对于异步方法获取到的 data ,可以实现在模板中对 pending 状态和 resolve/ reject 状态区分展示。而在 vue 的写法中,我们通常的做法是:定义一个 loading 的数据,再进行 if/else 的判断。而在 svelte 里面就可以不需要单独的定义冗余字段。

<script>
	async function getRandomNumber() {
		const res = await fetch(`/tutorial/random-number`);
		const text = await res.text();

		if (res.ok) {
			return text;
		} else {
			throw new Error(text);
		}
	}

	let promise = getRandomNumber();

	function handleClick() {
		promise = getRandomNumber();
	}
</script>

<button on:click={handleClick}>
	generate random number
</button>

{#await promise}
<p>loading。。。</p>
{:then number}
<p>{number}</p>
{:catch error}
<p>{error.message}</p>
{/await}

响应式

虽然说 Svelte 是普通的变量声明来实现响应式,但是对于对象和数组的响应式,相对来说比较怪异哈,具体表现为:

  • 通过改变数组的方法响应式不会触发响应式。
  • 直接修改对象的某个属性值也不会触发响应式。
  • 总之:需要响应式的值必须要出现在等式的左边,才会触发更新。

组件

组件写法

组件为一个单个的 .svelte 文件,通过 export 可以导出 props

// Counter.svelte
<script lang="ts">
  let count: number = 0
  const increment = () => {
    count += 1
  }
  export let childProps;
</script>

<button on:click={increment}>
  count is {count}
</button>
<p>{childProps}</p>

组件引入

引入组件,需要注意的是组件必须为大写开头,不然会被编译为普通的 html 标签。

// app.svelte
<script lang="ts">
  import svelteLogo from './assets/svelte.svg'
  import Child from './lib/Child.svelte'
</script>

<main>
  <div class="card">
    <Counter childProps={2333}/>
  </div>
</main>

组件事件

组件的事件通过 dispatch 触发,父组件通过 on:eventName 来接收事件。

<script>
	import {createEventDispatcher} from 'svelte'
	const dispatch = createEventDispatcher();
	function sayHello() {
		dispatch('message', {
			text: 'hello world!'
		})
	}
</script>

<button on:click={sayHello}>
	Click to say hello
</button>

如果不指定监听的回调函数,则事件会被透传到上一级组件,可以用来做对下下级组件的事件监听。


posted @ 2022-08-05 17:40  下小朋友  阅读(442)  评论(0编辑  收藏  举报