本文概述
Web应用程序正日益流行。他们是一个成长中的世界, 人们因其简单性, 速度和跨平台可用性而选择了它。单页应用程序(SPA)在此过程中发挥了重要作用。 Angular, Vue.js和React之类的框架可帮助开发人员在短时间内提供最佳用户体验, 从而使代码可支持和可扩展。这些工具长期以来一直是该领域最受欢迎的工具, 与新创建的软件包相比具有许多优势。感觉就像是SPA世界中的寡头。但是, 一群瞄准该市场的前瞻性开发商可能会与一个严重的竞争对手Svelte竞争。
Svelte是一种用于构建用户界面的新方法。让我们深入研究一下, 通过创建一个通用的登录表单来使它如此新鲜。
架构
Svelte在架构上比任何其他库都快。可以通过转移用于构建虚拟DOM的框架的步骤来实现。无需在运行过程中使用任何工具, 而是在构建阶段将其编译为Vanilla JS, 因此该应用程序无需依赖项即可启动。
斯维尔特 | Other SPA libraries (React, Vue.js, Angular, etc.) |
---|---|
1.打开一个网站2.使用纯JS渲染页面 | 1.打开一个网站2.等待直到加载用于构建虚拟DOM的代码3.使用库渲染页面 |
上表描述了Svelte为什么在启动性能方面绝对是赢家。不能通过任何优化来实现, 而只能使用可用的浏览器JavaScript编译器而不是侧面编译器。
安装
苗条的安装非常简单, 使用非常方便。第一步是下载项目的模板:
npx degit sveltejs/template svelte-login-form
完成上述命令意味着我们有了一个Svelte项目模板。目前为空, 尚未安装所需的NPM软件包。解决这个问题。
cd svelte-login-form
npm install
现在, 可以使用以下命令启动应用程序:
npm run dev
组件
任何Svelte组件都可以包含以下部分:
- 脚本
- 样式
- 模板
让我们看一下src / App.svelte文件中的示例。
<script>
export let name;
</script>
<style>
h1 {
color: purple;
}
</style>
<h1>{name}</h1>
上面的代码恰好包含三个部分:
-
脚本标签, 这是一个可选的JavaScript块, 其中包含应在组件内部使用的变量和函数声明。
-
样式标签, 这是另一个可选块。除了一个重要的区别外, 它非常类似于常见的HTML样式标签。在此块中描述的规则仅适用于此组件。将样式应用于p元素不会影响页面上的所有段落。太好了, 因为你不必输入班级名称, 也永远不会意外覆盖其他规则。
-
最后也是唯一需要的块是模板块-在这种情况下, 是h1标签。这是你组件的演示/视图。它与样式和脚本块紧密相关, 因为它们决定了视图的样式和行为方式。
Svelte是一个试图将模块化引入前端游戏的库。它不仅在分离不同的组件方面, 而且在隔离逻辑, 视图和模板时, 都保持了这种模块化。
返回我们正在建立的登录表单, 让我们在src文件夹中创建一个新文件LoginForm.svelte, 其内容如下:
<style>
form {
background: #fff;
padding: 50px;
width: 250px;
height: 400px;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
box-shadow: 0px 20px 14px 8px rgba(0, 0, 0, 0.58);
}
label {
margin: 10px 0;
align-self: flex-start;
font-weight: 500;
}
input {
border: none;
border-bottom: 1px solid #ccc;
margin-bottom: 20px;
transition: all 300ms ease-in-out;
width: 100%;
}
input:focus {
outline: 0;
border-bottom: 1px solid #666;
}
button {
margin-top: 20px;
background: black;
color: white;
padding: 10px 0;
width: 200px;
border-radius: 25px;
text-transform: uppercase;
font-weight: bold;
cursor: pointer;
transition: all 300ms ease-in-out;
}
button:hover {
transform: translateY(-2.5px);
box-shadow: 0px 1px 10px 0px rgba(0, 0, 0, 0.58);
}
h1 {
margin: 10px 20px 30px 20px;
font-size: 40px;
}
</style>
<form>
<h1>????</h1>
<label>Email</label>
<input name="email" placeholder="[email protected]" />
<label>Password</label>
<input name="password" type="password" placeholder="password" />
<button type="submit">Log in ????</button>
</form>
这是一个哑巴样式的组件, 稍后我们将使其变得更智能。要在我们的网站上看到此组件, 我们应该在根组件-App中渲染它。我们去编辑src / App.svelte, 使其看起来像这样:
<script>
import LoginForm from "./LoginForm.svelte";
</script>
<style>
section {
height: 100vh;
width: 100%;
display: flex;
justify-content: center;
align-items: center;
background: linear-gradient(to right, #cd76e2, #e358ab);
}
</style>
<section>
<LoginForm />
</section>
如果一切都正确完成并且应用程序仍在运行, 则我们的表单将显示在localhost:5000。让我们通过使表格更智能来提升Svelte技能。
有状态
Svelte中的任何组件都可以具有其状态。状态是可以在模板内部使用的一个特殊变量或一组特殊变量。为什么我说”特别”?每当更改此类变量时, 都会向模板发出通知, 并以最新状态呈现内容。这使应用程序可以非常快速地对用户交互做出反应。
我们将声明电子邮件和密码状态变量, 将在其中存储相应字段的表单值。这意味着我们的电子邮件和密码变量将始终与表单值保持同步, 因此我们随时准备提交这些值, 而不必担心提交值和表单中的实际值之间会有任何差异。
<script>
let email = "";
let password = "";
let isLoading = false;
const handleSubmit = () => {
isLoading = true;
// Simulate network request
setTimeout(() => {
isLoading = false;
// Authorize the user
}, 1000);
};
</script>
<style>
/* Style is unchanged */
</style>
<form on:submit|preventDefault={handleSubmit}>
<h1>????</h1>
<label>Email</label>
<input name="email" placeholder="[email protected]" bind:value={email} />
<label>Password</label>
<input name="password" type="password" bind:value={password} />
{#if isLoading}Logging in...{:else}Log in ????{/if}
</form>
状态变量看起来像普通的JavaScript变量, 但是要使它们与表单值同步(将它们绑定到表单字段), 必须使用bind:value指令。还有一些不熟悉的事情:
-
on:submit | preventDefault是防止默认事件行为的简写。这种方式比每次都要编写e.preventDefault()更为舒适。
-
{#if isLoading}登录中……{:else}登录????{/ if}是Svelte模板语法的一部分。由于模板块中没有JS, 因此有使用ifs, loop等的特殊语法。
最后, 让我们使用可用选项, 方法是使用状态向表单添加验证。可以通过创建另一个状态变量错误来实现, 该错误将在表单中使用无效值提交时填充错误。
<script>
let email = "";
let password = "";
let isLoading = false;
let errors = {};
const handleSubmit = () => {
errors = {};
if (email.length === 0) {
errors.email = "Field should not be empty";
}
if (password.length === 0) {
errors.password = "Field should not be empty";
}
if (Object.keys(errors).length === 0) {
isLoading = true;
// Simulate network request
setTimeout(() => {
isLoading = false;
// Authorize the user
}, 1000);
}
};
</script>
<style>
// Previous styles unchanged
.errors {
list-style-type: none;
padding: 10px;
margin: 0;
border: 2px solid #be6283;
color: #be6283;
background: rgba(190, 98, 131, 0.3);
}
</style>
<form on:submit|preventDefault={handleSubmit}>
<h1>????</h1>
<label>Email</label>
<input name="email" placeholder="[email protected]" bind:value={email} />
<label>Password</label>
<input name="password" type="password" bind:value={password} />
<button type="submit">
{#if isLoading}Logging in...{:else}Log in ????{/if}
</button>
{#if Object.keys(errors).length > 0}
<ul class="errors">
{#each Object.keys(errors) as field}
<li>{field}: {errors[field]}</li>
{/each}
</ul>
{/if}
</form>
该表格几乎是完整的。唯一剩下的就是成功身份验证后的成功消息。
我们创建一个状态变量来跟踪成功的提交, 默认情况下为false。成功提交表单后, 此变量的值应设置为true。
let isSuccess = false;
成功操作后, 还应更改处理表单提交的功能, 以遵循切换isSuccess的逻辑。
const handleSubmit = () => {
errors = {};
if (email.length === 0) {
errors.email = "Field should not be empty";
}
if (password.length === 0) {
errors.password = "Field should not be empty";
}
if (Object.keys(errors).length === 0) {
isLoading = true;
// Simulate network request
setTimeout(() => {
isLoading = false;
isSuccess = true;
// Authorize the user
}, 1000);
}
};
此修改使表单在提交完成后立即进入成功状态。
但是, 如果你检查开发服务器, 将不会发现表单的行为有任何变化。我们更改了代码, 但尚未修改模板。我们需要向模板中添加说明, 以在用户成功登录后显示成功消息。Svelte的模板语法使我们可以轻松实现此目的:
<form on:submit|preventDefault={handleSubmit}>
{#if isSuccess}
<div class="success">
????
<br />
You've been successfully logged in.
</div>
{:else}
<h1>????</h1>
<label>Email</label>
<input name="email" placeholder="[email protected]" bind:value={email} />
<label>Password</label>
<input name="password" type="password" bind:value={password} />
<button type="submit">
{#if isLoading}Logging in...{:else}Log in ????{/if}
</button>
{#if Object.keys(errors).length > 0}
<ul class="errors">
{#each Object.keys(errors) as field}
<li>{field}: {errors[field]}</li>
{/each}
</ul>
{/if}
{/if}
</form>
具有属性的摘要
我们整理了有关内部组件状态的所有信息。现在是时候遍历称为属性(props)的外部依赖项了。道具是传递到组件中的输入或参数, 用于向组件描述应显示的内容或组件的行为方式。
属性声明看起来类似于状态, 除了关键字export。
<script>
export let answer;
</script>
<p>The answer is {answer}</p>
<script>
import Nested from './Nested.svelte';
</script>
<Nested answer={42}/>
都是关于属性的。声明并通过-使用道具所需的全部知识。
但是这些属性如何应用于登录表单组件?通过将提交功能提取到属性中, 道具可以使我们的登录表单更通用。它将允许你将此组件与所需的任何提交操作(请求到测试服务器, 请求到实际服务器等)一起使用。该道具将称为提交, 并且将是一个函数, 如果submit操作成功, 则该函数返回已解决的promise;如果发生错误, 则返回被拒绝的promise。让我们通过上面的示例声明道具:
export let submit;
登录表单中的提交处理程序也应进行编辑以使用新的Submit属性。
const handleSubmit = () => {
errors = {};
if (email.length === 0) {
errors.email = "Field should not be empty";
}
if (password.length === 0) {
errors.password = "Field should not be empty";
}
if (Object.keys(errors).length === 0) {
isLoading = true;
submit({ email, password })
.then(() => {
isSuccess = true;
isLoading = false;
})
.catch(err => {
errors.server = err;
isLoading = false;
});
}
};
该组件似乎已准备就绪。但是, 如果你返回该表单并尝试提交该表单, 则会注意到按钮的状态并未因加载而发生变化。此外, 控制台中还有一个例外:Uncaught TypeError:submit不是函数。当然, 我们声明了道具, 但忘了通过它。让我们在应用程序组件中声明一个函数, 然后将其传递给登录表单。
const submit = ({ email, password }) =>
new Promise((resolve, reject) => setTimeout(resolve, 1000));
<section>
<LoginForm submit={submit} />
</section>
现在, 该表格正在按预期工作。它既可以显示错误, 也可以通知用户登录是否成功。
上下文共享
似乎列出了构建应用程序所需的一切。有了属性和内部状态, 我们就可以开始了。不过, 这只是部分正确。这两个要点使设计高复杂性SPA成为可能。但是, 如果你尝试在许多不同的组件之间共享数据, 则会发现非常困难。
最简单的示例是具有全局可访问的用户变量。许多组件都应根据用户的角色, 年龄, 状态等来更改与用户相关的行为。但是, 通过使用道具将用户传递到应用程序中的每个组件来重复自己的做法并非易事。
Svelte为此提供了一个解决方案:上下文API。
上下文API为组件提供了一种彼此”对话”的机制, 而无需传递数据和功能(作为道具)或调度大量事件。这是一项高级功能, 但很有用。
让我们将用户上下文添加到我们正在设计的登录表单中。在src文件夹中创建具有以下内容的文件userContext.js:
export const key = "userContext";
export const initialValue = null;
键是上下文的唯一标识符, 因为应用程序可能具有无限数量的必须保持可访问性的不同上下文。 initialValue只是上下文设置之前的默认值。
下一步是将上下文添加到我们的应用程序中。导航到App.svelte文件并添加2个导入语句:
import { onMount, setContext } from "svelte";
import {
key as userContextKey, initialValue as userContextInitialValue
} from "./userContext";
查看上面的代码, 你可能会想知道我们从svelte包中导入了什么。 onMount是一个辅助函数, 需要使用回调函数作为参数。在安装当前组件时(在加载组件的最开始时)将执行此回调。 setContext是上下文的setter函数。它需要上下文的键和一个新值作为其参数。
让我们使用onMount函数设置上下文的默认值:
onMount(() => {
setContext(userContextKey, userContextInitialValue);
});
并修改提交功能以设置用户上下文:
const submit = ({ email, password }) =>
new Promise((resolve, reject) => {
setTimeout(() => {
setContext(userContextKey, {
name: "Foo", lastName: "Bar", email: "[email protected]"
});
resolve();
}, 1000);
});
而已。成功提交将用户上下文更改为伪造的用户对象, 可以通过上下文获取程序getContext访问该对象:
<script>
import { getContext } from 'svelte';
import { key as userContextKey } from "./userContext";
const user = getContext(key);
</script>
摘要
Svelte是一款功能强大且功能强大的工具, 具有灵活的API。除了本文中介绍的基础知识之外, Svelte还具有以下功能:
- 反应性声明和陈述
- 等待模板块
- 尺寸绑定
- 像Redux这样的全球商店
- 动画和过渡助手
- 调试助手
综上所述, Svelte是一个很棒的图书馆, 可以满足建造SPA等的所有需求。它可以与市场上最大的竞争对手竞争, 甚至获胜。不过, 现在可以使用的是前端开发人员社区的支持。
注意:可以在teimurjan / svelte-login-form GitHub存储库中找到本文中的所有代码。可在此处获得登录表单的演示。