Svelte 组件规范(一)

510 阅读3分钟

组件规范

组件是Svelte应用的构建块。它们被写在.svelte文件,使用一个HTML超集。

脚本、样式和标识这三个部分都是可选的。

<script>
	// logic goes here
</script>

<style>
	/* styles go here */
</style>

<!-- markup (zero or more items) goes here -->

<script>

当一个组件创建后,script块包含着运行的javascript代码,在顶层声明(或导入)的变量在组件的标识中是“可见”的,

另外还有四条规则:

1、export创造一个组件道具

Svelte使用export关键字将变量声明标记为属性或道具,这意味着组件的用户可以访问它。

<script>
	export let foo;

	// Values that are passed in as props
	// are immediately available
	console.log({ foo });
</script>

可以为道具指定默认初始值。如果组件的使用者在实例化组件时未指定组件上的属性(或其初始值未定义),则将使用该属性。

请注意,每当使用者移除道具时,道具的值将设置为未定义,而不是初始值。

<script>
	export let bar = 'optional default initial value';
	export let baz = undefined;
</script>

在开发模式下,如果未提供默认初始值,并且使用者未指定值,则将打印警告。要消除此警告,请确保指定了默认初始值,即使未定义该值。

如果导出常量、类或函数,则它是从组件外部只读的。但是,函数表达式是有效的道具。

<script>
	// these are readonly
	export const thisIs = 'readonly';

	export function greet(name) {
		alert(`hello ${name}!`);
	}

	// this is a prop
	export let format = n => n.toFixed(2);
</script>

您可以使用保留字作为道具名称。

<script>
	let className;

	// creates a `class` property, even
	// though it is a reserved word
	export { className as class };
</script>

2、任务是反应式的

要更改组件状态并触发重新呈现,只需分配给本地声明的变量。

更新表达式(count+=1)和属性赋值(obj.x=y)具有相同的效果。

因为Svelte的反应性是基于赋值的,所以使用.push()和.splice()这样的数组方法不会自动触发更新。

可以在tutorial中找到解决此问题的选项。

<script>
	let count = 0;

	function handleClick () {
		// calling this function will trigger an
		// update if the markup references `count`
		count = count + 1;
	}
</script>

3、$:将语句标记为反应语句

任何顶级语句(即不在块或函数内)都可以通过在其前面加上$:JS标签语法来进行响应。响应语句在组件更新之前立即运行,只要它们所依赖的值发生更改。

<script>
	export let title;

	// this will update `document.title` whenever
	// the `title` prop changes
	$: document.title = title;

	$: {
		console.log(`multiple statements can be combined`);
		console.log(`the current title is ${title}`);
	}
</script>

如果语句完全由对未声明变量的赋值组成,Svelte将代表您插入let声明。

<script>
	export let num;
	
	// we don't need to declare `squared` and `cubed`
	// — Svelte does it for us
	$: squared = num * num;
	$: cubed = squared * num;
</script>

4、使用$前缀存储以访问其值

存储是一个对象,它允许通过一个简单的存储契约对一个值进行被动访问。svelte/store模块包含满足此契约的最小存储实现。

任何时候,只要有对存储的引用,就可以通过在组件中以$字符作为前缀来访问它的值。这将导致Svelte声明前缀变量,并设置将在适当时取消订阅的存储订阅。

对$前缀变量的赋值要求变量是可写存储,并将导致调用存储的.set方法。

请注意,必须在组件的顶层声明存储,例如,不能在if块或函数内部声明。

局部变量(不代表存储值)不能有$前缀。

<script>
	import { writable } from 'svelte/store';

	const count = writable(0);
	console.log($count); // logs 0

	count.set(1);
	console.log($count); // logs 1

	$count = 2;
	console.log($count); // logs 2
</script>

存储协议

store = {subscribe: (subscription: (value: any) => void) => () => void, set?: (value: any) => void }

您可以创建自己的存储区,而不依赖于svelte/store,通过执行存储协议:

1、存储区必须包含```.subscribe```方法,该方法必须接受订阅函数作为其参数。
调用```.subscribe```时,必须立即同步调用此订阅函数和存储的当前值。
每当存储的值更改时,必须稍后同步调用存储的所有活动订阅函数。

2、```.subscribe```方法必须返回unsubscribe函数。
调用unsubscribe函数必须停止其订阅,
并且存储区不得再次调用其相应的订阅函数。

3、存储可以选择性地包含```.set```方法,该方法必须接受存储的新值作为其参数,
并同步调用存储的所有活动订阅函数。这样的存储称为可写存储。

对于与RxJS observates的互操作性,还允许.subscribe方法返回带有.unsubscribe方法的对象,而不是直接返回unsubscribe函数。不过,请注意,除非.subscribe同步调用订阅(这不是observate规范所要求的),否则在调用之前,Svelte会将存储的值视为未定义。