基础

// Text.svelte
<p>
  this is Text Component
</p>

// App.svelte
<script>
  import text from './Text.svelte'
  const name = 'google'
  const src = 'https://www.google.com/logos/doodles/2020/december-holidays-days-2-30-6753651837108830.3-law.gif'
  const htmlText = '<strong>html</strong> parsing sample'
</script>
<div>
  <h1 class="heading">
    hello {name}
  </h1>
  <div>
    <img src={src} alt="{name} logo" />
  </div>
  <p>
    {@html htmlText}
  </p>
  <Text />
</div>

<style>
  .heading{color:#ff0000}
</style>
// index.js
import App from './App.svelte';

const app = new App({
	target: document.body,
	props: {
		// we'll learn about props later
		answer: 42
	}
});

交互

<script>
	let count = 0;
  $: doubled = count * 2;
	const handleClick = () => count += 1;
</script>
<button on:click={handleClick}>
	Click
</button>
<!-- 推荐, 重复使用该组建时很友好 -->
<p>
	{count} {doubled}
</p>
<!-- 不使用也可以 -->
<p>
	{count} {count * 2}
</p>
<script>
	let count = 0;
	let count2 = 0;
  // 监听count更改时执行, 有声明就监听
	$: console.log(`the count is ${count}`);
  // 可以大括号打包
  $: {
    console.log(`the count is ${count}`);
  }
  // 也可以添加条件
  $: if(count > 10){
    console.log('count max')
    count = 9
  }

	function handleClick() {
		count += 1;
	}
	function handleClick2() {
		count2 += 1;
	}
</script>

<button on:click={handleClick}>
	Clicked {count} {count === 1 ? 'time' : 'times'}
</button>

<button on:click={handleClick2}>
	Clicked {count2} {count2 === 1 ? 'time' : 'times'}
</button>
<script>
	let numbers = [1,2,3,4];
  $: length = numbers.length;
  const addNumber = () => {
    numbers = [...numbers, numbers.length + 1]
    // 直接push 他不会导致组建更新
    // nums.push(numbers.length + 1)
  }
</script>
<button @on:click={addNumber}>
  click {length}
</button>

Props

<!-- App.svelte -->
<script>
	import People from './People.svelte';
  const p1 = {
    name: 'dao',
    age: 20,
  }
</script>
<People name="dao" age={20} />
<People {...p1} />

<!-- People.svelte -->
<script>
  export const name = 'lang'; // default value
  export const age;
</script>
<p>
  name: {name}<br/>
  age: {age}
</p>

Logic

<script>
let isLogined = false;
const toggle = () => {
	isLogined = !isLogined;
}
const list = [
  {
    id: 'un01', name: 'dao', age: 12,
  },
  {
    id: 'un02', name: 'lang', age: 22,
  },
]
</script>
<button on:click={toggle}>
	{#if !isLogined}login{/if}
	{#if isLogined}logout{/if}
</button>
<button on:click={toggle}>
	{#if !isLogined}login
	{:else}logout{/if}
</button>
<ul>
  {#each list as item, i (item.id)} <!-- 相当于react key -->
  	<li>{i} - {item.name}, {item.age}</li>
  {/each}
</ul>

Promise

<script>
	const getUser = async () => {
		const response = await fetch('https://randomuser.me/api/');
		if(response.status === 200){
			return response.json()
		}
	}
</script>

{#await getUser()}
	<div>loading...</div>
	{:then data}
	<div>
		{data.results[0].gender} - {data.results[0].name.first}, {data.results[0].name.last}
	</div>
	{:catch error}
	<div>
		{error.message}
	</div>
{/await}

Event

<script>
	let count = 0;
	const setCount = () => {
		count += 1;
	}
</script>
<h1>
	{count}
</h1>
<button on:click|once={setCount}>
	click
</button>
<!-- 在某些框架中,出于性能原因,您可能会看到一些避免内联事件处理程序的建议,尤其是在循环内部。 该建议不适用于Svelte,无论您选择哪种形式,编译器都将始终做正确的事情。 -->
<button on:click={() => count += 1}>
	click
</button>

Event Modifiers

preventDefault运行处理程序之前调用event.preventDefault()。 例如,对客户端表单处理有用。
stopPropagation调用event.stopPropagation(),以防止事件到达下一个元素
passive改进了触摸/滚轮事件的滚动性能(Svelte会在安全的地方自动添加它)
nonpassive显式设置为passive:false
capture在捕获阶段而不是冒泡阶段()触发处理程序
once首次运行处理程序后将其删除
self仅当event.target是元素本身时才触发处理程序

Component Event

与DOM事件不同,组件事件不会冒泡。 如果要在某个深度嵌套的组件上侦听事件,则中间组件必须转发该事件。

<!-- App.svelte -->
<script>
	import People from './People.svelte';
	let name = 'lang';
	let age = 5;
	const getName = (event) => {
		name = event.detail.name;
		age = event.detail.age;
	}
</script>
<People on:getName={getName} />
<PeopleOuter on:getName={getName} />
<div>
	{name} {age}
</div>

<!-- People.svelte -->
<script>
	import {createEventDispatcher} from 'svelte';
	const dispatch = createEventDispatcher();
	const setName = () => {
		dispatch('getName', {
			name: 'daolang',
			age: 12
		})
	}
</script>
<button on:click={setName}>
click
</button>

<!-- PeopleOuter.svelte -->
<script>
  import People from './People.svelte';
</script>
<People on:getName />

Form binding

<script>
	let formObj = {
		username: '',
		age: 10,
		agree: false,
		gender: 'male',
		country: 'korea',
		message: '',
	}
</script>

<form>
	<h3>Input</h3>
	<label>username <input bind:value={formObj.username} /></label>
	<h3>Range</h3>
	<label>age <input bind:value={formObj.age} type="range" min={0} max={99} />{formObj.age}</label>
	<h3>Radio</h3>
	<label>male <input type="radio" bind:group={formObj.gender} value="male" /></label>
	<label>famale <input type="radio" bind:group={formObj.gender} value="female" /></label>
	<h3>Radio</h3>
	<select bind:value={formObj.country}>
		<option value="china">china</option>
		<option value="japan">japan</option>
		<option value="korea">korea</option>
	</select>
	<h3>Textarea</h3>
	<textarea bind:value={formObj.message} />
</form>

Component binding

<!-- App.svelte -->
<script>
	import Pad from './Pad.svelte'
  let pin = ''
  $: view = pin || 'enter pin'
	
  const handleSubmit = () => {
    alert(`submit ${pin}`)
  }
</script>
<h1>{view}
</h1>
<Pad bind:value={pin} on:submit={handleSubmit} />
<!-- Pad.svelte -->
<script>
	import { createEventDispatcher } from 'svelte';
	export let value = ''
	const dispatch = createEventDispatcher();
	const clickNum = (e) => value += e.target.innerText;
	const clickClear = () => value = '';
	const clickSubmit = () => dispatch('submit')
</script>

<div>
	<button on:click={clickNum}>1</button>
	<button on:click={clickNum}>2</button>
	<button on:click={clickNum}>3</button>
	<button on:click={clickNum}>4</button>
	<button on:click={clickNum}>5</button>
	<button on:click={clickNum}>6</button>
	<button on:click={clickNum}>7</button>
	<button on:click={clickNum}>8</button>
	<button on:click={clickNum}>9</button>
	<button on:click={clickClear}>clear</button>
	<button on:click={clickNum}>0</button>
	<button on:click={clickSubmit}>submit</button>
</div>

Lifecycle

  1. beforeUpdate
  2. render
  3. onMount
  4. afterUpdate
  5. onDestroy
  6. unMount(onMount return function)
<!-- App.svelte -->
<script>
	import Sub from './Sub.svelte';
	let isShow = true
	const toggle = () => isShow = !isShow;
</script>
<button on:click={toggle}>
	click
</button>
{#if isShow}
<Sub />
{/if}

<!-- Sub.svelte -->
<script>
	import { onMount, onDestroy, beforeUpdate, afterUpdate } from 'svelte';
	let status = 'sub page'
	onMount(() => {
		console.log('mount')
		return () => {
			console.log('unmount')
		}
	})
	// 销毁时运行 unmount 之前
	onDestroy(() => {	
		console.log('destroy')
	})
	// 数据更新前
	beforeUpdate(() => {
		console.log('before update')
	})
	// 数据更新后
	afterUpdate(() => {
		console.log('after update')
	})
	
	const setContents = () => {
		status = `sub page ${+new Date()}`
	}
</script>

<p>
	<span style="display: none">{console.log('render')}</span>
	{status}
</p>
<button on:click={setContents}>
	update page contents
</button>

在Svelte中更新组件状态时,它不会立即更新DOM。 而是等到下一个微任务,看是否还有其他需要应用的更改,包括其他组件。 这样做避免了不必要的工作,并使浏览器可以更有效地对事物进行批处理。