svelte 学习记录(一)

svtelte 是一款更小、更轻量的框架,比现在的三大框架都更轻量,但是应用不广泛。之中的利弊可以移步知乎等论坛

https://www.zhihu.com/question/53150351

Hello world

和vue 比较类似,他也有自己独特的 .svelte  后缀的文件

app.svelte

<h1>Hello world!</h1>

这个文件会输出对应的 html、js和css 代码,(简直是比vue还要精简)

动态绑定变量

<script>
let name = 'world';
</script>

<h1>Hello {name}!</h1>

{} 号将script 中的变量绑定到html中,和jsx语法类似

动态绑定属性

<script>
let src = 'tutorial/image.gif'
</script>

<img src={src}/>
// 或者简写
<img {src}/>

css 样式

通过<style> 中写样式

<style>
	p {
		color: purple;
		font-family: 'Comic Sans MS', cursive;
		font-size: 2em;
	}
</style>

<p>This is a paragraph.</p>

引入组件

<script>import 需要的组件 调用就可以了

<script>
	import Nested from './Nested.svelte';
</script>

<p>This is a paragraph.</p>
<Nested/>

引入html 代码片段

通过@html 使用html代码片段,不要忘记之后加个空格哦

<script>
	let string = `this string contains some <strong>HTML!!!</strong>`;
</script>

<p>{{@html string}</p>

svelte 开发工具插件

更多其他工具 

挂在到实际节点上

import App from './App.svelte';

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

响应式编程

通过on:click 绑定点击事件 修改变量之后{} 赋值

<script>
	let count = 0;

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

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

计算属性

类似vue的computed  ,通过$:声明一个变量

<script>
	let count = 0;
	$: doubled = count * 2;

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

<button on:click={handleClick}>
	Clicked {doubled} {count === 1 ? 'time' : 'times'}
</button>
// 等价于 {count * 2}

监听变量

通过$: 之后执行代码,来监听变量,还可加条件监听,类似 react的useEffect 或vue的watch

// case 1
$: console.log(`the count is ${count}`);

// case 2

$: {
	console.log(`the count is ${count}`);
	alert(`I SAID THE COUNT IS ${count}`);
}

// case 3
$: if (count >= 10) {
	alert(`count is dangerously high!`);
	count = 9;
}

解决修改array或object 更新问题

数组pushpop shift 、unshift 和 splice  不会触发更新,解决办法就是重新 =

// case 1
function addNumber() {
	numbers.push(numbers.length + 1);
	numbers = numbers;
}

// case 2 (惯用套路)

function addNumber() {
	numbers = [...numbers, numbers.length + 1];
}

操作属性也是可以触发更新的 

function addNumber() {
	numbers[numbers.length] = numbers.length + 1;
}

function addNumber() {
	numbers.b += 1;
}

 

object 传递引用修改无效 

const foo = obj.foo;
foo.bar = 'baz';

// 解决方法
obj = obj;

props 声明

通过export 对外声明组件变量

<script>
	export let answer;
    
    // 这样写 2 为anwer的默认值
    export let answer = 2;
</script>

<p>The answer is {answer}</p>

通过三点表达式 简化传递属性

<Info {...pkg}/>

还可以使用$$props获取未声明传递的属性  类似react jsx写法

逻辑判断

if语句

{#if} 开始判断 {:else}{:else if}中间拼接 {/if}结束

<script>
	let user = { loggedIn: false };

	function toggle() {
		user.loggedIn = !user.loggedIn;
	}
</script>
{#if user.loggedIn}
<button on:click={toggle}>
	Log out
</button>
{/if}

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


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

for 循环

cats  是item 、 i是索引值

{#each cats as cat, i}
	<li><a target="_blank" href="https://www.youtube.com/watch?v={cat.id}">
		{i + 1}: {cat.name}
	</a></li>
{/each}

列表渲染key

id 作为key ,利于正确更新 。默认用thing 更新,会造成更新异常

{#each things as thing (thing.id)}
	<Thing current={thing.color}/>
{/each}

await 代码块

利于promise 处理,用于网络请求

{#await promise}
	<p>...waiting</p>
{:then number}
	<p>The number is {number}</p>
{:catch error}
	<p style="color: red">{error.message}</p>
{/await}
{#await promise then value}
	<p>the value is {value}</p>
{/await}

事件

通过 on: 绑定事件

<script>
	let m = { x: 0, y: 0 };

	function handleMousemove(event) {
		m.x = event.clientX;
		m.y = event.clientY;
	}
</script>

<style>
	div { width: 100%; height: 100%; }
</style>

<div on:mousemove={handleMousemove}>
	The mouse position is {m.x} x {m.y}
</div>

// 不建议这样绑定
<div on:mousemove={e=>m={x:e.clientX,y:e.clientY}}>
   The mouse position is {m.x} x {m.y}
</div>

事件绑定修饰符

  • once : 绑定事件只执行一次
  • preventDefault: 执行时 event.preventDefault()
  • stopPropagation: 执行时 event.stopPropagation()
  • passive : 提高scroll事件滚动流畅的效果
  • capture : 事件捕获
  • self: 事件发生对象为绑定对象触发。

on:click|once|capture={...}  链式 类似vue 语法.stop

<script>
	function handleClick() {
		alert('no more alerts')
	}
</script>

<button on:click|once={handleClick}>
	Click me
</button>

组件的自定义事件

通过createEventDispatcher 创建事件触发器 dispatch

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

	const dispatch = createEventDispatcher();

	function sayHello() {
		dispatch('message', {
			text: 'Hello!'
		});
	}
</script>

注意自定义事件不会冒泡 、所以需要中间组件进行事件转发。通过event.detail 传递

<script>
	import Inner from './Inner.svelte';
	import { createEventDispatcher } from 'svelte';

	const dispatch = createEventDispatcher();

	function forward(event) {
		dispatch('message', event.detail);
	}
</script>

<Inner on:message={forward}/>

简写

<script>
	import Inner from './Inner.svelte';
</script>

<Inner on:message/>

双向绑定

通过bind:  双向绑定进行绑定值 

<script>
	let name = 'world';
</script>

<input bind:value={name}>

<h1>Hello {name}!</h1>
<script>
	let a = 1;
	let b = 2;
</script>

<label>
//  自动处理
	<input type=number bind:value={a} min=0 max=10>
	<input type=range bind:value={a} min=0 max=10>
</label>

<label>
	<input type=number bind:value={b} min=0 max=10>
	<input type=range bind:value={b} min=0 max=10>
</label>

<p>{a} + {b} = {a + b}</p>
<label>
	<input type=checkbox bind:checked={yes}>
	Yes! Send me regular email spam
</label>

使用bind:group处理 单选按钮组或者多选按钮组 

<script>
	let scoops = 1;
	let flavours = ['Mint choc chip'];

	function join(flavours) {
		if (flavours.length === 1) return flavours[0];
		return `${flavours.slice(0, -1).join(', ')} and ${flavours[flavours.length - 1]}`;
	}
</script>

<h2>Size</h2>

<label>
	<input type=radio bind:group={scoops} value={1}>
	One scoop
</label>

<label>
	<input type=radio bind:group={scoops} value={2}>
	Two scoops
</label>

<label>
	<input type=radio bind:group={scoops} value={3}>
	Three scoops
</label>

<h2>Flavours</h2>

<label>
	<input type=checkbox bind:group={flavours} value="Cookies and cream">
	Cookies and cream
</label>

<label>
	<input type=checkbox bind:group={flavours} value="Mint choc chip">
	Mint choc chip
</label>

<label>
	<input type=checkbox bind:group={flavours} value="Raspberry ripple">
	Raspberry ripple
</label>

{#if flavours.length === 0}
	<p>Please select at least one flavour</p>
{:else if flavours.length > scoops}
	<p>Can't order more flavours than scoops!</p>
{:else}
	<p>
		You ordered {scoops} {scoops === 1 ? 'scoop' : 'scoops'}
		of {join(flavours)}
	</p>
{/if}
<textarea bind:value={value}></textarea>
<select bind:value={selected} on:change="{() => answer = ''}">

<select multiple bind:value={flavours}>
	{#each menu as flavour}
		<option value={flavour}>
			{flavour}
		</option>
	{/each}
</select>

动态绑定富文本代码片段 

<div
	contenteditable="true"
	bind:innerHTML={html}
></div>

video 、audio标签绑定

  • duration(只读):视频总时间
  • buffered(只读):一个数组包含{start, end}对象
  • seekable(只读):
  • played(只读):
  • seeking(只读):
  • ended(只读):

其他四个 可以双向绑定的

  •  currentTime: 当前进度
  • playbackRate:播放速度  设置1为正常速度
  • paused : 暂停
  • volume: 音量大小 0到1
<video
	poster="https://sveltejs.github.io/assets/caminandes-llamigos.jpg"
	src="https://sveltejs.github.io/assets/caminandes-llamigos.mp4"
	on:mousemove={handleMousemove}
	on:mousedown={handleMousedown}
	bind:currentTime={time}
	bind:duration
	bind:paused
></video>

任何块状元素都有属性clientWidthclientHeightoffsetWidth 和 offsetHeight  (都是只读) 

<div bind:clientWidth={w} bind:clientHeight={h}>
	<span style="font-size: {size}px">{text}</span>
</div>

通过bind:this 获取节点本身,必须要mounted后才能渲染到。 类似 react和vue 的ref

<canvas
	bind:this={canvas}
	width={32}
	height={32}
></canvas>

绑定组件的自定义属性 

<Keypad bind:value={pin} on:submit={handleSubmit}/>

生命周期

onMount 生命周期应用广泛你可以在这边,初始化发起http请求。

注意:在SSR环境中。除了onDestroy ,其他生命周期都不会触发.

要在组件初始化的时候,调用生命周期的钩子函数,不要在setTimeout中使用

onMount 如果返回一个方法,那个方法会在组件销毁时候调用。类似react 的useEffect

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

	let photos = [];

	onMount(async () => {
		const res = await fetch(`https://jsonplaceholder.typicode.com/photos?_limit=20`);
		photos = await res.json();
	});
</script>

onDestory 组件销毁时候调用。比如说setInterval 。避免内存泄漏

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

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

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

可以封装一下类似react hooks 的工具

// utils.js
import { onDestroy } from 'svelte';

export function onInterval(callback, milliseconds) {
	const interval = setInterval(callback, milliseconds);

	onDestroy(() => {
		clearInterval(interval);
	});
}
// 在组件中使用
<script>
	import { onInterval } from './utils.js';

	let seconds = 0;
	onInterval(() => seconds += 1, 1000);
</script>

beforeUpdateafterUpdate 用于组件更新时候的hook(吐槽下: 官方的例子真的是简洁易懂)

<script>
	import Eliza from 'elizabot';
	import { beforeUpdate, afterUpdate } from 'svelte';

	let div;
	let autoscroll;

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

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

	const eliza = new Eliza();

	let comments = [
		{ author: 'eliza', text: eliza.getInitial() }
	];

	function handleKeydown(event) {
		if (event.which === 13) {
			const text = event.target.value;
			if (!text) return;

			comments = comments.concat({
				author: 'user',
				text
			});

			event.target.value = '';

			const reply = eliza.transform(text);

			setTimeout(() => {
				comments = comments.concat({
					author: 'eliza',
					text: '...',
					placeholder: true
				});

				setTimeout(() => {
					comments = comments.filter(comment => !comment.placeholder).concat({
						author: 'eliza',
						text: reply
					});
				}, 500 + Math.random() * 500);
			}, 200 + Math.random() * 200);
		}
	}
</script>

<style>
	.chat {
		display: flex;
		flex-direction: column;
		height: 100%;
		max-width: 320px;
	}

	.scrollable {
		flex: 1 1 auto;
		border-top: 1px solid #eee;
		margin: 0 0 0.5em 0;
		overflow-y: auto;
	}

	article {
		margin: 0.5em 0;
	}

	.user {
		text-align: right;
	}

	span {
		padding: 0.5em 1em;
		display: inline-block;
	}

	.eliza span {
		background-color: #eee;
		border-radius: 1em 1em 1em 0;
	}

	.user span {
		background-color: #0074D9;
		color: white;
		border-radius: 1em 1em 0 1em;
		word-break: break-all;
	}
</style>

<div class="chat">
	<h1>Eliza</h1>

	<div class="scrollable" bind:this={div}>
		{#each comments as comment}
			<article class={comment.author}>
				<span>{comment.text}</span>
			</article>
		{/each}
	</div>

	<input on:keydown={handleKeydown}>
</div>

tick 神奇的hooks ,不只再组件初始化的时候可以调用

<script>
	import {tick} from 'svelte';
	let text = `Select some text and hit the tab key to toggle uppercase`;

	async function handleKeydown(event) {
		if (event.which !== 9) return;

		event.preventDefault();

		const { selectionStart, selectionEnd, value } = this;
		const selection = value.slice(selectionStart, selectionEnd);

		const replacement = /[a-z]/.test(selection)
			? selection.toUpperCase()
			: selection.toLowerCase();

		text = (
			value.slice(0, selectionStart) +
			replacement +
			value.slice(selectionEnd)
		);

		 await tick() // 再执行后面代码前,先把之前代码执行完成
		this.selectionStart = selectionStart;
		this.selectionEnd = selectionEnd;
	}
</script>

<style>
	textarea {
		width: 100%;
		height: 200px;
	}
</style>

<textarea value={text} on:keydown={handleKeydown}></textarea>

 

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

今天又懒得加班

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值