大家好。这是文章“ 摆脱jQuery到Svelte,不费吹灰之力 ”的继续。下面我将谈论我遇到的困难,其中没有很多,只有一个如此根本的问题,如果没有社区的支持,我将无法应对。介绍
我打算分块重写前端,这并不是完全不能解决的事情,也不能完全解决问题-我不得不分批重写。首先,因为jQuery方法是必须的,所以Svelte方法是声明性的。其次,由于使用jQuery,我们的范围始终是全局的,因此我们可以从任何代码行访问网页的所有元素,我们可以通过ID或CSS选择器来访问它们,而Svelte建议使用组件以及在我们看到的组件内部仅组件本身,我们没有外部或内部元素,因此我们无法直接访问它们。使用Svelte,我们可以得到真正的面向对象操作:我们不能自己进行更改,只能告诉组件更改的必要性。如何进行这些更改,只知道组件内部的代码。太好了:)Svelte有两种与组件通信的机制。绑定变量(绑定,映射)
我们声明一个变量并将其映射到component属性:<script>
import DetailTaskView from './DetailTaskView.svelte';
let task = {};
let isModal = false;
function renderTask(data) {
const isSuccess = data.hasOwnProperty(0);
if (isSuccess) {
isModal = true;
task = data[0];
}
}
import {fade} from 'svelte/transition';
</script>
{#if isModal}
<div transition:fade>
<DetailTaskView bind:isModal="{isModal}" {...task}/>
</div>
{/if}
我们做了什么?
我们声明了两个局部变量“ task”和“ isModal”,“ task”是要在组件中显示的信息,仅显示数据,不会更改,“ isModal”是组件可见性的标志,如果用户单击组件上的叉号,则组件应消失,十字符号属于该组件,因此我们对点击一无所知,但是我们了解到“ isModal”变量的值已更改,并且由于反应性,我们将计算出这个新值。如果需要双向绑定,则可以编写“ bind:”,该组件内部值的更改将报告给“父”组件。如果只需要告诉组件值,则可以使用缩写形式;如果组件属性名称与变量名称匹配,则可以编写“ {task}”或使用析构函数“ {... task}”。方便。但是,如果我们在一个组件中嵌入了另一个组件,并且还有第三个组件,那么当然会有一个bollerplate用于向上和向下滚动嵌套层次结构的值。事件冒泡
我可能会误认为术语,不要踢太多。父组件可以处理子组件的事件,但只能处理子组件报告的那些事件。
<script>
import SearchForm from './SearchForm.svelte';
async function applySample(event) {
const sample = event.detail.sample;
if(sample){
search(sample);
}
if(!sample){
renderPage();
}
}
</script>
<div class="container">
<h1> </h1>
<SearchForm on:search={applySample}/>
</div>
<script>
import { createEventDispatcher } from 'svelte';
const dispatch = createEventDispatcher();
let sample = '';
function search(event) {
event.preventDefault();
dispatch('search', {
sample: sample
});
}
</script>
<form class="form-horizontal" id="search"
on:submit={search}>
<div class="form-group">
<label class="control-label col-sm-2" for="sample">
</label>
<div class="col-sm-10">
<input id="sample" class="form-control" type="search"
placeholder=" "
autocomplete="on" bind:value={sample}
/>
</div>
</div>
</form>
这里发生了什么 ?
在父组件中,“ applySample”函数由子“ SearchForm”组件的“ on:search”事件执行,该函数从事件对象接收参数(event.detail)并对其进行处理。组件中会发生什么?
输入元素的“值”属性映射到“样本”变量;通过(“表单”元素的)“上:提交”事件,执行“搜索”功能,该函数创建“搜索”事件并将{样本:样本“对象”写入“详细信息”属性}-即搜索字符串的值。因此,搜索字符串的值将传递给父组件,由他决定如何处理该值。该组件仅负责显示输入表单并传输输入的值,该组件不执行搜索和显示结果,因此我们承担责任。美丽!从命令式到声明式的过渡
不幸的是,在这里无法清楚地显示出差异。换句话说,这听起来像是:如果使用jQuery时,我创建了html标记,然后将其插入到正确的位置,然后使用Svelte我生成具有组件属性的数组,然后在循环中添加具有预先计算的属性的组件:
<script>
import {createEventDispatcher} from 'svelte';
import OrdinalPlace from './OrdinalPlace.svelte';
let pagingPlaces;
function addPlace(
paging = [], index = Number.NEGATIVE_INFINITY,
text = "", css = "") {
paging.push({index:index,text:text,css:css});
return paging;
}
const dispatch = createEventDispatcher();
function browsePage(event) {
const pageIndex = event.detail.index;
dispatch('move', {
index: pageIndex
});
}
</script>
{#if pagingPlaces.length}
<table class = "table table-hover-cells table-bordered">
<tbody>
<tr>
{#each pagingPlaces as place (place.index)}
<OrdinalPlace on:move="{browsePage}"
{...place}>
</OrdinalPlace>
{/each}
</tr>
</tbody>
</table>
{/if}
<script>
export let index = -1;
export let text = "";
export let css = "";
let number = index +1;
function skip() {
return !(text === "");
}
let letSkip = skip();
let noSkip = !letSkip;
import { createEventDispatcher } from "svelte";
const dispatch = createEventDispatcher();
function moveTo() {
if(noSkip){
dispatch("move", {index:index});
}
}
</script>
<td class="{css}" on:click="{moveTo}">
{#if letSkip}
{text}
{/if}
{#if noSkip}
{number}
{/if}
</td>
怎么运行的 ?
创建分页组件时,我们形成一个“元素”数组以转到某些页面-“ pagingPlaces”,然后循环浏览所有元素并插入一个组件以显示一个分页位置-“ OrdinalPlace”。同样,采用声明式方法,我们不会自己形成每个职位,而是告诉组件我们需要显示具有此类属性的职位。在这里,我们看到了一个事件出现的混乱情况。要转到搜索结果页面,用户单击“ OrdinalPlace”组件,该组件无法加载页面,因此它将创建带有“ page index”参数的“ move”事件,并且该事件将拾取父组件“ Paging”,因此也无法加载页面它引发'move'事件,并且下一个父组件已经将其拾取并以某种方式进行处理。Svelte和组件方法促使我们分担责任并遵循SOLID。最大的伏击
上面的示例显示了一个基本问题的解决方案,如果没有提示,我将无法解决该问题。Svelte会缓存所有组件,您需要帮助他跟踪这些组件中的更改。这是有问题的代码: {#each pagingPlaces as place (place.index)}
<OrdinalPlace on:move="{browsePage}"
{...place}>
</OrdinalPlace>
{/each}
为了显示分页中的页面列表,我们遍历了数组,Svelte为组件分配了每个组件的数组索引,现在,Svelte决定基于此索引重绘组件,如果您在遍历数组元素时未指定索引,则不了解什么,我试图了解一天,然后我在大厅里寻求帮助,在大厅里,我没有立即找到一个熟悉这种耙子的人,但是由于这些家伙,他们帮助了我。使用数组时,请记住这一点:数组的任何传递都必须再次使用索引: {#each pagingPlaces as place (place.index)}
“将PagingPlaces作为位置(place.index)”-确保使用。当然,如果您以前使用过React / Vue,那么您可能已经熟悉此功能。视觉效果
我的应用程序使用模式窗口。jQuery为此设置了标记要求,没有它,jQuery.modal()方法将无法工作。Svelte使这更容易:{#if isModal}
<div transition:fade>
<DetailTaskView bind:isModal="{isModal}" {...task}/>
</div>
{/if}
具体来说,“过渡:淡入淡出”是导致页面上元素消失/外观的原因。没有人指示我们应该拥有什么标记。很好。除了该动画之外,Svelte还有其他一些内容:教程中的链接中的示例fly and tweened。其他
变量名
变量/参数/属性命名的麻烦在于,您必须使用一个词来调用对象的属性和在此写的变量,当您需要在电话上谈论代码时,手机规则就可以了,这样您就不必为此感到困惑并了解所有内容,例如重复的名称违反。阿贾克斯
这不适用于Svelte,但涉及拒绝使用jQuery,可以用fetch()替换jQuery.ajax,我做了这样的替换,您可以在存储库中看到它。结论
从使用jQuery到使用Svelte的过程将需要重写用于创建标记的逻辑,但这并不困难,而且只要看起来似乎就没有困难,尤其是在您的代码没有犯错的情况下。Svelte简化了标记并缩短了JS代码,使用Svelte使您的代码更可重用,并且可以抵抗随机错误。使用Svelte,它将对您和您的客户都有好处!参考文献
SvelteRepository的官方网站,以及从使用jQuery到使用俄语的Svelte in Telegram社区的Svelte Channel 的过渡,谢谢您的阅读。PS:我不知道为什么Habr从与社区频道的链接中排除冒号,正确的链接是:tg:// resolve?Domain = sveltejs