Svelte文档走读(一)

Sun 06 October 2019 / In categories Notes

Svelte

svelte api docs走读笔记。

svelte的组件是一个以.svelte结尾的文件,其语法是HTML的超集,骨架大致如下:

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

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

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

其中,<script>包含的是组件实例化时执行的代码,其中的变量范围在组件范围内有效。如果在变量声明前面加上export关键字,则表示这个变量是一个prop,也就是组件实例化时需要从外部传入的参数。(个人认为使用extern作为关键字或许含义更明确)。可以在export前面加上const代表这个prop是只读的。函数也可以作为一个prop。保留字可以作为prop,比如:export { className as class };

Svelte的反应性是构建在赋值表达式的基础上的,count += 1或者obj.x = y可以触发DOM的更新。而非赋值语句的表达式则不行。在范围顶层,也就是<scripe>直接治下的范围,可以在表达式前面加上$:来让表达式变得具有反应性(能够根据表达式成员的变化而重新计算表达式结果),比如:$: document.title = title;在title发生改变时会重新计算document.title的值。$:之后可以直接赋值一个新的变量,而不需要使用let声明此变量。算是一种简略形式把。

Svelte里面的全局权属(property)叫做store(有点像XAML中的dependencyproperty)。store可以被subscribe,从而获得更新通知。subscribe返回unsubscribe,在组件消解的时候调用。为了简略起见,使用$来饮用store,可以省略手动subscribe和unsubscribe,比如:console.log($count);,其中count是一个store。使用store需要svelte/store这个运行时库的支持。

如果像<script context="module">这样指明了context为module,那么标签里面的内容只会在这个jsmodule被加载的时候执行一次。此外,标签中export的变量会变成jsmodule的export(不具有反应性)。这些变量的export不属于默认的export,因为默认的export是组件类型本身。

<style>标签中的样式默认局部有效。要想全局有效,可以使用:global(...)

	:global(body) {
		/* this will apply to <body> */
		margin: 0;
	}

对于元素的属性,大部分跟HTML一致,但是有一些附加功能。比如可以将JS表达式添加到属性内容:<a href="page/{p}">page {p}</a><button disabled="{number !== 42}">...</button>。花括号中的内容是JS表达式。这里有一种简略形式,当属性名与花括号内的变量名重名时,可以省略属性名以及等号:name={name}简略成{name}。你也可以把一个对象的属性释放元素中:<Widget {...things}/>。还有一种不常用的形式:<Widget {...$$props}/>

svelte-ignore可以用来屏蔽下一个元素标签有可能产生的告警:<!-- svelte-ignore a11y-autofocus -->

条件控制语句有如下变种:

  • {#if expression}...{/if}
  • {#if expression}...{:else if expression}...{/if}
  • {#if expression}...{:else}...{/if}

循环控制语句有如下变种:

  • {#each expression as name}...{/each}
  • {#each expression as name, index}...{/each}
  • {#each expression as name, index (key)}...{/each},使用key可以帮助svelte在更新的时候选中必须需要更新的部分
  • {#each expression as name}...{:else}...{/each}{:else}在列表为空的时候会被调用

示例:

{#each items as { id, name, qty }, i (id)}
	<li>{i + 1}: {name} x {qty}</li>
{/each}

{#each objects as { id, ...rest }}
	<li><span>{id}</span><MyComponent {...rest}/></li>
{/each}

{#each items as [id, ...rest]}
	<li><span>{id}</span><MyComponent values={rest}/></li>
{/each}

异步语句:

  • {#await expression}...{:then name}...{:catch name}...{/await}
  • {#await expression}...{:then name}...{/await},忽略catch,假设promise一定成功
  • {#await expression then name}...{/await},忽略中间等待过程,直接期待结果

可以使用{@html expression},插入HTML代码(<>不被转义)。注意:expression必须包含合乎语法的HTML代码(比如单独的</div>就不合法)。

可以使用{@debug ...}插入调试语句并插入断点,示例:{@debug var1, var2, ..., varN}

元素指令(Element directives)

指令用来控制元素的行为。

事件指令:

  • on:eventname={handler}
  • on:eventname|modifiers={handler}

示例:

<form on:submit|preventDefault={handleSubmit}>
	<!-- the `submit` event's default is prevented,
		 so the page won't reload -->
</form>

修饰符可以是:

  • preventDefault — calls event.preventDefault() before running the handler
  • stopPropagation — calls event.stopPropagation(), preventing the event reaching the next element
  • passive — improves scrolling performance on touch/wheel events (Svelte will add it automatically where it’s safe to do so)
  • capture — fires the handler during the capture phase instead of the bubbling phase
  • once — remove the handler after the first time it runs

修饰符可以串联:on:click|once|capture={...}

如果指定了事件指令,却没有指定处理器,那么事件会被转发给组件的消费者(上一级组件);同时,对相同的事件,可以使用多个指令来指定多个处理器。

对于数据绑定,其指令形式是:bind:property={variable},示例如下:

<!-- These are equivalent -->
<input bind:value={value}>
<input bind:value> <!-- 上面的元素的简略形式 -->

需要注意的是,不同元素的可以绑定的权属(property)是不一样的,需要时查询文档。一个比较特别的例子是:bind:this={dom_node},这个例子把组件本身的示例绑定一个变量上了。

class指令可以用来指定样式:

  • class:name={value}
  • class:nameclass:name={name}的简略形式

通过use:action或者use:action={parameters}可以指定一个动作,在组件加载时调用。这个动作可以返回对象,然后这个对象可以带一个destory方法,让组件卸载的时候调用。

动作返回的对象也可以带有update方法:

action = (node: HTMLElement, parameters: any) => {
	update?: (parameters: any) => void,
	destroy?: () => void
}

如果动作的parameter发生变化,update方法会被调用。

转场效应可以通过transition指令指定:

  • transition:fn
  • transition:fn={params}
  • transition:fn|local
  • transition:fn|local={params}
transition = (node: HTMLElement, params: any) => {
	delay?: number,
	duration?: number,
	easing?: (t: number) => number,
	css?: (t: number, u: number) => string,
	tick?: (t: number, u: number) => void
}

转场出局的DOM元素,如果transition没有执行完,还是会保留在DOM中。transition可以被逆向撤销。

By default intro transitions will not play on first render. You can modify this behaviour by setting intro: true when you .

转场可以有局部性,如果指定了local修饰符:<p transition:fade|local>,那么这个转场效果只有在直接的父元素状态发生变化的时候才会改变。

转场的时候,Svelte还会派发下面四个合成事件:

  • introstart
  • introend
  • outrostart
  • outroend

使用transition指令来转场,效果是双向的。如果只是想单向转场,可以使用in或者out指令:

  • in:fn
  • in:fn={params}
  • in:fn|local
  • in:fn|local={params}
  • out:fn
  • out:fn={params}
  • out:fn|local
  • out:fn|local={params}

由于out转场是单向的,当被打断时不会发生逆转,只会从头开始。

通过animate指令可以指定键控列表重新排序时候的动态特效,其形式如下:

  • animate:name
  • animate:name={params}
animation = (node: HTMLElement, { from: DOMRect, to: DOMRect } , params: any) => {
	delay?: number,
	duration?: number,
	easing?: (t: number) => number,
	css?: (t: number, u: number) => string,
	tick?: (t: number, u: number) => void
}

DOMRect {
	bottom: number,
	height: number,
	​​left: number,
	right: number,
	top: number,
	width: number,
	x: number,
	y:number
}

示例如下:

<!-- When `list` is reordered the animation will run-->
{#each list as item, index (item)}
	<li animate:flip>{item}</li>
{/each}

(本篇完)

Load Disqus Comments