SvelteJs学习——生命周期

1. 生命周期

每个组件都有一个生命周期,于创建时开始,于销毁时结束。以下是一些有帮助的函数,允许你在生命周期的关键时刻运行代码。

2. onMount 挂载

最常用的是onMount,它在组件第一次呈现给DOM之后运行。

用法:

<script>
	import { onMount } from "svelte";
	let finalVal = '初始值'
	onMount(() => {
		finalVal = '变更值' // 可以在此处发起网络请求,进行值的变更
	})
</script>
  • 由于服务端渲染,建议将获取数据的方式放置在onMount中,而不是放在script标签的最上面。除了onDestory之外,生命周期函数在SSR期间不会运行,这意味着我们可以避免抓取那些应该在组件被挂载DOM时才加载的数据。
  • 生命周期函数必须在组件初始化时调用,以便回调函数绑定到组件实例,而不是在setTimeout中。
  • 如果onMount回调函数返回一个函数,该函数将在组件被销毁时被调用。

3. onDestroy 销毁

要在组件被销毁时运行代码,请使用onDestroy。

  • 例如,我们可以在组件初始化时添加 一个setInterval函数,并在它不再使用时清除它,这样做可以防止内存泄漏。
	import { onDestory } from 'svelte'
	let seconds = 0
	const myInterval = setInterval(() => {
		seconds ++
	}, 1000);
	onDestory(() => {
		cleatInterval(myInterval)
	})
  • 虽然组件在初始化期间调用生命周期函数很重要,但从哪里调用它们并不重要。因此,为了方便管理,我们可以将区间逻辑抽象到某个文件中。这样,相同需要此逻辑的内容,可以引入对应的方法,在使用后进行清除
utils.js

import { onDestroy } from 'svelte';

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

	onDestroy(() => {
		clearInterval(interval);
	});
}
使用组件中:

	import { onInterval } from './utils.js';

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

4. beforeUpdate 和 afterUpdate

  • beforeUpdate 函数实现在DOM渲染完成前执行
  • afterUpdate 函数则相反,在异步数据加载完成后

以下是一个聊天机器人的小例子。生命周期主要用于在双方一问一答拼接内容时,计算聊天框的高度和聊天内容的高度,确保聊天内容展示在最新回复上。

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

	const eliza = new Eliza(); // 创建机器人聊天实例
	let comments = [ // 聊天框内容,初始聊天框由eliza发起
		{ author: 'eliza', text: eliza.getInitial() }
	]

	function handleKeydown(event) {
		// 如果是回车键
		if (event.which === 13) {
			const text = event.target.value
			// 如果没有内容直接回车,不执行任何操作
			if(!text) return;
			// 输入内容拼接至聊天数组中,通过author进行区分,样式展示
			comments = comments.concat({
				author: 'user',
				text
			})
			// 消息发送成功后将内容清空
			event.target.value = '';

			// 机器人回复消息
			const reply = eliza.transform(text)
			console.log(reply)

			// 过渡,用于未回复时表示正在输入的状态
			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)

		}
	}


	let div;
	let autoscroll;

	// 进行更新之前,将滚动高度设为展示当前内容
	beforeUpdate(() => {
		autoscroll = div && (div.offsetHeight + div.scrollTop) > (div.scrollHeight - 20);
	})
	// 数据更新后,滚动条根据y轴滑到最下面,展示最新回复
	afterUpdate(() => {
		if (autoscroll) div.scrollTo(0, div.scrollHeight);
	});
</script>
<main>
	<div class="chat">
		<!-- 聊天对话标题 -->
		<h1>聊天机器人</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>
</main>
<style>
	.chat {
		display: flex;
		flex-direction: column;
		height: 400px;
		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>

beforeUpdate函数需要在组件挂载前运行,所以我们需要先将div与组件标签绑定,并判断div是否已被正常渲染

5. tick

  • tick函数不同于其他生命周期函数,因为你可以随时调用它,而不用等待组件首次初始化。它返回一个带有resolve方法的Promise,每当组件pending状态变化便会立刻体现到DOM中。

  • 在Svelte中每当组件状态失效时,DOM不会立即更新。反而Svelte会等待下一个microtask以查看是否还有其他变化的状态或组件需要应用更新。这样做避免了浏览器做无用功,使之更加高效。

以下示例场景:在选中内容后,将选中内容大写,且不取消选中,光标不自动移动至最后。

<script>
import { tick } from "svelte";


	let text = 'Select some 1 text and then 2 hit 汉字 the tab key to toggle uppercase'
	async function handleKeyDown(event) {
		if (event.which !== 9) return
		event.preventDefault();
		// this指向的是当前textarea的DOM,其中解析出来的这三个变量分别代表选中内容的起始下标、结束下标、textarea全部内容值
		const { selectionStart, selectionEnd, value } = this;
		// 根据下标和全部内容截取出选中内容
		const selection = value.slice(selectionStart, selectionEnd)
		// 使用正则表达式进行匹配, 如果包含小写那么转成大写,不然执行转换成小写
		const replacement = /[a-z]/.test(selection) ? selection.toUpperCase() : selection.toLowerCase();
		// 执行成功后,replacement已经是代码想要达成的值了,此时需要将该值更新到textarea的value上
		text = (value.slice(0, selectionStart) + replacement + (value.slice(selectionEnd)))
		// 增加tick,确保DOM更新后光标选中内容
		await tick()
		this.selectionStart = selectionStart;
		this.selectionEnd = selectionEnd;
	}

</script>
<main>
<textarea cols="30" rows="10" value={text} on:keydown={handleKeyDown}></textarea>
</main>
<style>

</style>

官方文档
如果有用,点个赞呗~

总结用法,希望可以帮助到你,
我是Ably,你无须超越谁,只要超越昨天的自己就好~

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值