写点什么

被称为“三大框架”替代方案,Svelte 如何简化 Web 开发工作(上)

  • 2019-10-09
  • 本文字数:10950 字

    阅读完需:约 36 分钟

被称为“三大框架”替代方案,Svelte如何简化Web开发工作(上)

Web 框架层出不穷,作为主流 Web 框架之一的 Svelte,有着独特的优势。它不仅可以构建完整的 Web 应用程序,还可以创建自定义元素,并在其他框架实现的已有 Web 应用程序中使用。本文将对 Svelte 进行详细的介绍,并带领读者了解使用 Svelte 从头开始构建 Web 应用程序所需的基础知识。


Svelte 是什么?

Svelte 是 React、Vue 和 Angular 等 Web 框架的替代方案。与其同类产品一样,Svelte 可用于构建完整的 Web 应用程序。它还能用来创建自定义元素,这些自定义元素可以在使用其他框架实现的已有 Web 应用程序中使用。


Svelte 由 Rich Harris 开发,Rich Harris 曾在《卫报》工作,目前任职于《纽约时报》。Harris 先前创建的Ractive Web框架被《卫报》采用,并成为 Vue 的一部分功能的灵感来源。Harris 还创建了Rollup模块打包器,它是 Webpack 和 Parcel 的替代品。


Svelte 尚未得到应有的重视。人们提到它时往往更关注它生成打包代码的能力,它打包出来的代码明显比竞争对手更小。但除此之外 Svelte 还简化了许多工作,包括定义组件、管理组件状态、管理应用程序状态以及添加动画等。


本文对 Svelte 做了详尽的介绍,并带读者了解用它从头开始构建 Web 应用程序所需的基础知识。

为什么要用 Svelte?

与其他 Web 框架创建的应用程序相比,Svelte 应用程序的包体积较小。它将应用程序代码编译到一个只包含少量框架代码的优化过的 JavaScript 文件来做到了这一点。


Svelte 是用 TypeScript 实现的 Web 应用程序编译器。它不是运行时库。


例如,稍后介绍的 Todo 应用程序的包体积只有等效 React 应用程序的 13%。这两款应用程序的链接在这里这里


这个网站统计了现实世界中 Web 应用使用多种 Web 框架构建的相关数据。根据统计,使用一些流行框架的应用经过 gzip 压缩后的大小(KB)分别为:


  • Angular + ngrx:134

  • React + Redux:193

  • Vue:41.8

  • Svelte:9.7


某些 Web 框架(包括 React 和 Vue)使用虚拟 DOM 来优化渲染更改。重新渲染组件时,框架会在内存中构建 DOM 的新版本,然后将其与以前的版本做对比,不一样的部分才会被应用到实际的 DOM 上。


尽管这比更新实际 DOM 中的所有内容要快,但构建虚拟 DOM 并将其与前一个 DOM 进行比较是需要花时间的。


Svelte 无需使用虚拟 DOM 就可以提供反应性。为了做到这一点,它会跟踪影响各个组件渲染的顶级组件变量的更改,并仅在检测到更改时才重新渲染 DOM 的这些部分。这样就能获得良好的性能表现。


Svelte 大大简化了组件和应用程序状态管理。相关功能包括上下文、存储和模块上下文,稍后将逐一详细介绍。


Svelte 为可访问性问题提供了运行时警告。例如,没有 alt 属性的<img>元素会被标记出来。


Svelte 当前不支持 TypeScript,但正在推进相关工作


Svelte Native 支持开发移动应用程序。它基于 NativeScript。

Svelte 会消失吗?

有人说一旦应用程序构建完毕,Svelte 就会消失。


Svelte 库主要由 node_modules/svelte 目录中的.js 文件定义。主要函数在 internal.js 中定义,目前大约有 1400 行代码。


其他库文件则针对特定功能,具体包括:


  • easing.js

  • motion.js

  • register.js

  • store.js

  • transition.js


输入 npm run build 会在 public 目录中生成文件,包括 bundle.js。应用程序使用的 Svelte 库函数将复制到 bundle.js 的顶部。后文展示的 Todo 应用程序中,这里大约是 500 行代码。


因此 Svelte 库代码不会消失;只是它与其他 Web 框架相比体积很小。

重要资源

下面是学习 Svelte 时需要查看的重要资源列表:



这是 Rich Harris 在 You Gotta Love Frontend(YGLF)Code Camp 2019 上的演讲。它解释了 Svelte 3 背后的动力,并提供了一些简要介绍。



想要尝试编写少量 Svelte 代码的话这个网站很有用。它还可以显示生成的代码并保存代码,以供分享和提交问题。


入门

下面我们来一步步创建并运行一个 Svelte 应用程序。


  1. https://nodejs.org安装 Node.js。


这将安装 node、npm 和 npx 命令。


  1. npx degit sveltejs/template app-name


Rich Harris 创建了 degit 工具来简化项目框架。它会下载一个 git 仓库,默认为 master 分支。本例中“sveltejs”是用户名,“template”是存储库。第二个参数是要创建的目录名称。


  1. cd app-name

  2. npm install

  3. npm run dev


这将启动本地 HTTP 服务器并提供实时重载,这与 npm run start 是不一样的,后者忽略了实时重载。语法错误是在运行该命令的窗口中,而不是在浏览器中报告的。这是因为如果出现了错误,Svelte 不会生成该应用程序的新版本。


  1. 浏览localhost:5000


这一步会输出紫色的“Hello world!”。


现在你可以开始修改应用程序了。


初探package.json文件会发现两件事。首先是 Svelte 默认使用 Rollup 来打包模块。需要的话,可以将其更改为使用 Webpack 或 Parcel。其次是 Svelte 应用程序没有必需的运行时依赖项,只有 devDependencies。


最重要的起始文件包括:


  1. public/index.html

  2. src/main.js

  3. src/App.svelte


这些文件使用 tab 缩进,但需要的话可以将 tab 替换为空格。


  1. 文件 public/index.html包含以下内容:


<!DOCTYPE html><html>  <head>    <meta charset="utf8" />    <meta name="viewport" content="width=device-width" />    <title>Svelte app</title>    <link rel="icon" type="image/png" href="favicon.png" />    <link rel="stylesheet" href="global.css" />    <link rel="stylesheet" href="bundle.css" />  </head>  <body>    <script src="bundle.js"></script>  </body></html>
复制代码


请注意这里提取了两个 CSS 文件和一个 JavaScript 文件。


  • global.css包含可以影响任何组件的 CSS。

  • bundle.css由每个组件中的 CSS 生成。

  • bundle.js是由每个组件中的 JavaScript 和 HTML,以及应用程序中其他所有的 JavaScript 生成的。


  1. 文件src/main.js包含以下内容:


import App from './App.svelte'; const app = new App({  target: document.body,  props: {    name: 'world'  }}); export default app;
复制代码


这里会渲染 App 组件。target 属性指定应在何处渲染组件。对于大多数应用程序来说,这就是文档的主体。


name prop 会传递给 App 组件。


通常来说最顶层的组件不需要 props,此处的 props 属性可以删除。


  1. 文件src/App.svelte包含以下内容:


<script>   export let name;</script> <style>  h1 {    color: purple;  }</style> <h1> Hello {name}! </h1>
复制代码


可以在使用该组件的文件中将导出的变量设置为 props。


大括号用于输出 JavaScript 表达式的值。这里称为插值。稍后我们将看到,大括号也用于动态属性值。

定义组件

流行的 Web 框架使用多种 JavaScript 容器来定义组件。


  • Angular 使用类。

  • React 使用函数或类。

  • Vue 使用对象字面量。


Svelte 不使用任何 JavaScript 容器。


Svelte 组件由包含 JavaScript 代码、CSS 和 HTML 的.svelte 文件定义。它们组合在一起形成组件定义,该定义将自动成为默认导出。


.svelte 文件可以在 src 目录下的任何位置。它们包含以下三部分,这三部分都是可选的。


<script>  // 确定范围的JavaScript在这里。</script> <style>  /* 确定范围的CSS规则在这里。*/</style> <!-- 要渲染的HTML在这里。-->
复制代码


请注意,每个部分都可以使用不同的注释语法。

组件名称

Svelte 组件定义未指定组件名称。其他框架中组件名称是在源文件中由类名称、函数名称或属性值提供的,这里不是这样;导入.svelte 文件时组件名称会被关联,并且必须以大写字母开头。


小写名称保留给预定义元素,例如 HTML 和 SVG 提供的元素。


例如:


// 有些令人困惑import AnyNameIWant from './some-name.svelte'; // 较清晰的写法import SameName from './SameName.svelte';
复制代码

共享数据

在 Svelte 组件之间共享数据有四种方法。


  1. Props


它们将数据从父组件传递到子组件。


  1. 上下文


祖先组件可以用它们来使数据可用于后代组件。


  1. 存储


它们将数据存储在所有组件外,并使其对所有组件可用。


  1. 模块范围


它们将数据存储在组件模块中,并使数据可用于组件的所有实例。


这些内置方法非常有用,实际上你都不需要状态管理库。

Props

组件可以通过 props 接受输入。它们被指定为父组件渲染的组件元素上的属性。


例如,父组件可以执行以下操作:


<script>  import Hello from './Hello.svelte';</script> <Hello name="Mark" />
复制代码


这里 name prop 的值是字面量字符串。


作为 JavaScript 表达式或非字符串字面量的 prop 值必须用大括号括起来,不能用引号。


src/Hello.svelte 中定义的子组件可以这样做:


<script>  export let name = 'World';</script> <div>  Hello, {name}!</div>
复制代码


这里使用 export 关键字在组件的<script>部分中声明 props。这里用 Svelte 特有的方式使用了有效的 JavaScript 语法。


由于父元素可以更改值,因此必须使用 let 关键字而不是 const。


为 props 分配默认值是可选的。


目前 Svelte 没有像 React、Vue 和 Angular 那样(通过 TypeScript)进行 prop 类型检查的功能。

属性

元素的属性值可以用 JavaScript 表达式提供。


其语法为:


<element-name attribute-name =“ expression” />
复制代码


表达式也可以嵌入到字符串值中。


例如:


<Person fullName="{firstName} {middleInitial}. {lastName}" />
复制代码


当属性值位于与该属性同名的变量中时,可以使用简写语法。


例如:


<Person {fullName} />
复制代码


如果多个属性位于一个对象中,则可以使用散布运算符插入多个属性,其中键是属性名称,值是它们的值。


例如:


<script>  let score = 0;  const inputAttrs = {    type: 'number',    max: 10,    min: 0,    value: score  };</script> <input {...inputAttrs} bind:value={score} />
复制代码


上面的示例使用 bind 模拟双向数据绑定。这将在后文详细说明。

样式

.svelte 文件的<style>标记中的样式将自动确定组件的范围。


Svelte 将生成的相同的 CSS 类名称(svelte-hash)添加到可能受这些 CSS 规则影响的组件的每个渲染元素中,从而实现了作用域。


全局样式应在 public/global.css 中定义。


与标准 CSS 一样,样式标记中的注释必须使用/ * * /注释定界符。


"svelte3"ESLint 插件会对未使用的 CSS 选择器发出警告。


可以有条件地将 CSS 类添加到元素。在以下示例中,仅当 status 大于零时才添加 CSS 类 error。


<div class:error={status > 0}>{result}</div>
复制代码

导入组件

组件可以在其<script>标记内导入其他组件。


例如:


import Other from './Other.svelte';
复制代码


可以在组件的 HTML 部分中使用导入的组件。

插入 HTML

要渲染一个值为 HTML 字符串的 JavaScript 表达式,请使用语法{@html expression}


假设 markup 是一个包含 HTML 字符串的变量。下面的代码将渲染它:


<p>{@html markup}</p>
复制代码


为了避免跨站点脚本,请 escape 不受信任来源中的 HTML。

反应性

插值中引用的顶级变量的更改会自动导致这些插值被重新计算。


例如:


<script>  let count = 0;  const increment = () => count++;</script> <div>count = {count}</div><button on:click={increment}>+</button>

复制代码


必须分配一个新值以触发此操作。将新元素推送到数组上不会触发它。


可以使用以下方法:


myArr = myArr.concat(newValue); // 另一种技巧myArr.push(newValue);myArr = myArr;
复制代码

响应式声明

在 JavaScript 语句开头写一个名称,后面跟一个冒号,就会创建一个标签语句。标签语句可以用作 break 和 continue 语句的目标。


有趣的是,在同一范围的多个语句中使用相同的标签名称在 JavaScript 中不是错误。


当这个语法用在顶层语句(未嵌套在函数或块中)上且名称为美元符号时,Svelte 会将顶层语句视为响应式声明


这是 Svelte 编译器以特殊方式处理有效的 JavaScript 语法的另一个例子。当这类语句引用的任何变量的值更改时,它们自己就会重复。这有点像 Vue 中的计算属性


例如:


// average的值一开始就被计算// 如果total或count的值更改就重新计算。$: average = total/count; // count的值输出在devtools控制面板中// 当这个语句执行和每次更改时。// 这方便了调试工作!$: console.log('count =', count);
复制代码


将 $:应用于未声明变量的赋值时(比如上面的 average 赋值),不允许使用 let 关键字。


$:可以应用于一个块。


例如:


$: {  // 这里是要重复的语句}
复制代码


这也可以应用于多行语句,比如 if 语句。


例如:


$: if (someCondition) {  // 主体语句}
复制代码


如果条件或主体中引用的任何变量发生更改,上面的示例就会执行;但当然只有在条件为 true 时主体才执行。


例如,如果条件包括对函数的调用,则如果主体中的任何引用发生更改就会调用它们。

Markup 中的逻辑

在 markup 中添加条件逻辑和迭代逻辑有三种常见方法。


  1. React 使用 JSX,其中逻辑由大括号中的 JavaScript 代码实现。

  2. Angular 和 Vue 支持特定于框架的逻辑属性。例如,Angular 支持 ngIf 和 ngFor,而 Vue 支持 v-if 和 v-for。

  3. Svelte 支持包装元素的类似 Mustache 的自定义语法。例如{#if}和{#each}。

IF 语句

Svelte 的条件逻辑以{#if condition}开始。开头的 #表示块的起始标记。


用{/ if}标记结尾。开头的/表示块的结束标记。


有条件渲染的 markup 位于这两者之间。


它们之间可以包含的其他块标记有{:else if condition}和{:else}。开头的:表示块的继续标记。


例如:


{#if color === 'yellow'}  <div>Nice color!</div>{:else if color === 'orange'}  <div>That's okay too.</div>{:else}  <div>Questionable choice.</div>{/if}
复制代码


虽说这里的语法乍看起来似乎很奇怪,但它确实能有条件地渲染多个元素。Angular/Vue 中向元素添加特殊属性的方法需要指定一个公共父元素。

Each 语句

Svelte 的迭代从{#each iterable as element}开始。


用{/each}标记结尾。


每个元素要渲染的 markup 放在两者之间。


一般来说可迭代的是数组,但任何可迭代的值都能用。


{:else}之后的内容在可迭代内容为空时渲染。


例如,假设变量 colors 设置为[‘red’, ‘green’, ‘blue’]:


<!-- 分开行来使用color输出每种颜色。-->{#each colors as color}  <div style="color: {color}">{color}</div>{/each} <!-- 在单独的行上输出每种颜色,并在其前面     从1开始的位置后跟括号。-->{#each colors as color, index}  <div>{index + 1}) {color}</div>{/each} <!-- 这里使用解构来在"people"的对象中获取特定的属性。-->{#each people as {name, age}}  <div>{name} is {age} years old.</div>{:else}  <div>There are no people.</div>{/each}
复制代码


如果要添加、删除或修改列表中的项目,则应为每个元素提供唯一的标识符。这类似 React 和 Vue 中所需的 key prop。


在 Svelte 中,唯一标识符是 #each 语法的一部分,而不属于元素 prop。在以下示例中,每个 person 的唯一标识符是对应的 id 属性。


{#each people as person (person.id)}  <div>{person.name} is {person.age} years old.</div>{/each}
复制代码

Promise

Svelte 提供了 markup 语法来等待 promise 解析或拒绝。它可以根据 promise 的未完成、已解析或已拒绝的状态提供不同的输出。


以下示例假定组件具有返回 Promise 的 getData 函数。在:then 和:catch 之后可以使用任何变量名来接收解析或拒绝的值。


{#await getData()}  <div>Waiting for data ...</div>{:then result}  <div>result = {result}</div>{:catch error}  <div class="error">Error: {error.message}</div>{/await}
复制代码


下一个示例在等待 Promise 解析时省略了要渲染的 markup。:catch 部分也可以省略。


{#await getData() then result}  <div>result = {result}</div>{:catch error}  <div class="error">Error: {error.message}</div>{/await}
复制代码

插槽

插槽允许子内容传递到组件。接收组件可以决定是否渲染它,在何处渲染。


请注意,空格算作子内容。


接收组件可以标记使用渲染所有子内容的位置。这称为默认插槽


它还可以为没有向插槽提供内容的父元素提供默认内容来渲染。例如,<slot>Thanks for nothing!</slot>


命名插槽允许父元素提供多组内容,接收组件可以针对这些内容决定是否渲染以及在何处渲染。父元素使用 slot 属性标识它们。子元素则定义它们在何处用带有匹配的 name 属性的 slot 元素来渲染。


下面是来自父元素的 HTML 示例,该 HTML 元素的目标是子元素 ShippingLabel 中的多个命名槽:


<ShippingLabel>  <div slot="address">    123 Some Street,<br />    Somewhere, Some State 12345  </div>  <div slot="name">Mark Volkmann</div></ShippingLabel>
复制代码


这是 ShippingLabel.svelte:


<style>  label {    display: block;    font-weight: bold;  }</style> <div>  <label>Ship To:</label>  <slot name="name">unknown</slot>  <slot name="address" /></div>
复制代码

绑定表单元素

<input><textarea><select>这样的表单元素可以绑定到变量上。这将模拟双向数据绑定。


除了提供当前值之外,双向数据绑定还提供事件处理,以便在用户更改表单元素值时更新变量。


对于类型为 number 或 range 的<input>元素,双向数据绑定会自动将值从字符串强制转换为数字。


例如,考虑以下 HTML 表单:



这是使用单个 Svelte 组件的实现。注意在多处使用了 bind:。


<script>  const colors = ['red', 'orange', 'yellow', 'green', 'blue', 'purple'];  const flavors = ['vanilla', 'chocolate', 'strawberry'];  const seasons = ['Spring', 'Summer', 'Fall', 'Winter'];  let favoriteColor = '';  let favoriteFlavors = [];  let favoriteSeason = '';  let happy = true;  let name = '';  let story = '';</script> <style>  div {    margin-bottom: 10px;  }   input,  select {    border: solid gray 1px;    border-radius: 4px;    padding: 4px;  }   input[type='checkbox'],  input[type='radio'] {    margin-left: 5px;  }   label {    display: inline-block;    font-weight: bold;    margin-right: 5px;    vertical-align: top;  }</style> <div class="form">  <div>    <label>Name</label>    <input type="text" bind:value={name} />  </div>  <div>    <label>Happy?</label>    <!-- 对于checkbox, 要绑定到"checked"属性而非"value"上。 -->    <input type="checkbox" bind:checked={happy} />  </div>  <div>    <label>Favorite Flavors</label>    {#each flavors as flavor}    <label>      <!-- 使用"bind:group"和一组相关的checkbox           使值成为一组字符串。 -->      <input type="checkbox" value={flavor} bind:group={favoriteFlavors} />      {flavor}    </label>    {/each}  </div>  <div>    <label>Favorite Season</label>    {#each seasons as season}    <label>      <!-- 使用"bind:group"和一组相关的radio按钮           使值成为单个字符串。 -->      <input type="radio" value={season} bind:group={favoriteSeason} />      {season}    </label>    {/each}  </div>  <div>    <label>Favorite Color</label>    <!-- 要将选项更改为可滚动列表以启用多重选项,添加         "multiple"属性。 -->    <select bind:value={favoriteColor}>      <option />      {#each colors as color}      <!-- <option> 元素可以有一个"value"属性           其值可以是字符串、数字或对象。-->      <option>{color}</option>      {/each}    </select>  </div>  <div>    <label>Life Story</label>    <textarea bind:value={story} />  </div>   <!-- 这里报告了绑定设置的变量值,但前提是name有值。 -->  {#if name}  <div>    {name} likes {favoriteColor}, {favoriteSeason},    and is {happy ? 'happy' : 'unhappy'}.  </div>  <div>{name}'s favorite flavors are {favoriteFlavors}.</div>  <div>Story: {story}</div>  {/if}</div>
复制代码


除了绑定到基本变量之外,表单元素还可以绑定到对象属性。然后用户输入会使这些对象发生突变。

绑定定制 props

Svelte 可以将子组件 prop 绑定到父组件中的变量。这将允许子组件更改父组件变量的值。


例如,这是父组件:


<script>  import Child from './Child.svelte';  let pValue = 1;</script> <div>pValue = {pValue}</div><Child bind:cValue={pValue} />
复制代码


这是子组件:


<script>  export let cValue = '';  const double = () => (cValue *= 2);</script> <div>cValue = {cValue}</div><button on:click={double}>Double</button>
复制代码


按下 Child 组件中的按钮时,cValue 会加倍,并且加倍的值由于绑定到 cValue 而成为 pValue 的新值。

事件处理

事件处理由 on:event-name 属性指定,该属性的值是调度事件时要调用的函数。事件名称可以是标准 DOM 事件或自定义事件的名称。事件对象将传递给给定的函数。


例如:


<!-- 函数 "handleClick" 必须在上面的<script>部分中定义。--><button on:click={handleClick}>Press Me</button> <!-- 这里用匿名函数展示了内联事件处理。它为按钮设置了变量"clicked"到DOM元素。--><button on:click={event => clicked = event.target}>Press Me</button>
复制代码


可以为同一个事件指定多个事件处理函数,并且在分派事件时将分别调用每个函数。


例如:


<button on:click={doOneThing} on:click={doAnother}>Press Me</button>
复制代码


事件处理程序可以使用修饰符名称前面的竖线指定任意数量的事件修饰符。


例如:


<button on:click|once|preventDefault={handleClick}>Press Me</button>
复制代码


支持的修饰符有:


capture


它导致处理程序函数仅在捕获阶段,而不是默认的冒泡阶段被调用。


once


它将在第一次发生事件后删除处理程序。


passive


它可以提高滚动性能。更多信息参阅这里


preventDefault


它可以防止事件的默认操作发生。例如,它可以停止表单提交。


stopPropagtion


它可以防止捕获/冒泡流程中的后续处理程序被调用。


从 on:属性中省略事件处理函数可以快速将事件转发到父组件。


例如,假设组件结构的一部分是 A> B> C,并且 C 发出事件“foo”。B 可以使用<C on:foo/>将其转发到 A。


请注意,on:属性没有值。


此方法也可以用于转发 DOM 事件。


组件可以调度事件。


例如:


<script>  import {createEventDispatcher} from 'svelte';   // 组件实例化时必须调用,  // 可选或稍后调用都不行。  const dispatch = createEventDispatcher();   function sendEvent() {    // 事件关联的数据可以是一个原语或对象。    // 事件名称不应包含横线。    dispatch('someEventName', optionalData);  }</script>
复制代码


这些事件仅转到父组件。它们不会自动在组件结构中冒泡。


父组件使用 on:侦听子组件的事件。


例如,如果父组件定义了函数 handleEvent,则它可以在 Child 组件分派具有给定名称的事件时注册要调用的函数。


<Child on:someEventName = {handleEvent} />
复制代码

生命周期函数

Svelte 支持在组件实例的生命周期中发生四个特定事件时调用注册函数。这些事件包括:


  1. 已挂载时

  2. 更新前

  3. 更新后

  4. 被销毁时


术语“已挂载”表示已将组件实例添加到 DOM。


术语“被销毁”表示该组件实例已从 DOM 中删除。


要为这些事件注册函数,请从 svelte 包中导入所提供的生命周期函数。


import {afterUpdate, beforeUpdate, onDestroy, onMount} from 'svelte';
复制代码


然后调用这些函数,并在事件发生时向它们传递要调用的函数。


最常用的生命周期函数是 onMount。一种用法是将焦点移至给定的表单元素。另一种用途是从 REST 服务检索组件所需的数据。


下面是一个移动焦点的示例。


<script>  import {onMount} from 'svelte';  let name = '';  let nameInput;  onMount(() => nameInput.focus());</script> <input bind:this={nameInput} bind:value={name} />
复制代码


属性 bind:this 会将指定为其值的变量设置为对 input 的 DOM 元素的引用。这在传递给 onMount 的函数中使用,以将焦点移至 input。


从 DOM 中删除组件实例时,使用 onDestroy 注册要调用的函数的另一种方法是从通过 onMount 注册的函数返回该函数。这种方法有点像 React 中的 useEffect hook,不同之处在于 Svelte 中传递给 useEffect 的函数在挂载和更新时都运行。


生命周期函数可以从辅助函数中调用。这些可以在单独的.js 文件中定义,从而导入它们并用于多个组件。这很像定义自定义的 React hooks。


建议以“on”开头命名这些辅助函数,就像 React hook 名称以“use”开头那样。

动作

将特定元素添加到 DOM 时,动作(Action)会注册要调用的函数。


动作是在具有属性 use:fnName = {args}的元素上指定的。已注册的函数将传递 DOM 元素和参数(如果存在)。如果不需要除元素以外的其他参数,则省略= {args}。


这在某种程度上与 onMount 生命周期函数有关,该函数注册了将组件的每个实例添加到 DOM 时要调用的函数。将组件中的特定元素添加到 DOM 时,就将调用动作。


例如:


<script>  let name = '';  const focus = element => element.focus();</script> <!-- 输入元素添加到DOM时调用焦点函数。--><input bind:value={name} use:focus />
复制代码


动作函数可以选择返回具有 update 和 destroy 属性(也就是函数)的对象。这个功能不常用。


每当参数值更改时都会调用 update 函数。如果没有参数当然是不行的。


从 DOM 中删除元素时将调用 destroy 函数。

上下文

上下文(Context)提供了一种替代方法,可以使用 props 和存储(接下来介绍)来使组件中的数据在其他组件中可用。上下文数据只能在后代组件中访问。


要在组件中定义上下文,请导入 setContext 函数并调用它,并提供上下文键和值。


例如:


import {setContext} from 'svelte'; // Must be called during component instantiation.setContext('favorites', {color: 'yellow', number: 19});
复制代码


要在后代组件中使用上下文,请导入 getContext 函数并调用它,并提供上下文键。这将从已使用该键定义上下文的最近的祖先组件获取上下文值。


例如:


import {getContext} from 'svelte'; // 组件实例化时必须调用。const favorites = getContext('favorites');
复制代码


上下文键可以是任何类型的值,不只是字符串。


上下文值可以是任何类型的值,包括具有后代组件可以调用的方法的对象和函数。


如果创建了上下文的组件再使用相同的键和不同的值调用 setContext,则后代组件将不会接收到更新。它们只能看到组件初始化期间可用的内容。


与 props 和存储不同,上下文不是响应式的。


下面是一个使用上下文使数据在后代组件中可用的示例。


<!-- In A.svelte --><script>  import {setContext} from 'svelte';  import B from './B.svelte';  setContext('favorites', {color: 'yellow', number: 19});</script> <div>  This is in A.  <b ></b></div>
复制代码


<!-- In B.svelte --><script>  import C from './C.svelte';</script> <div>  This is in B.  <C /></div>
复制代码


<!-- In C.svelte --><script>  import {getContext} from 'svelte';  const {color, number} = getContext('favorites');</script> <div>  This is in C.  <div>favorite color is {color}</div>  <div>favorite number is {number}</div></div>
复制代码


这将渲染以下内容:


This is in A.This is in B.This is in C.favorite color is yellowfavorite number is 19
复制代码


原文链接:


https://objectcomputing.com/resources/publications/sett/july-2019-web-dev-simplified-with-svelte


2019-10-09 18:595866

评论 3 条评论

发布
用户头像
df
2019-10-12 20:01
回复
用户头像
dd
2019-10-12 20:01
回复
ad
2019-10-12 20:01
回复
没有更多了
发现更多内容

Coremail私有云邮箱:筑牢企业数据安全防线

科技热闻

案例研究|为什么 CDG 会选择从 DataDog 迁移至观测云?

观测云

可观测性

神仙级python入门教程(非常详细),从零基础入门到精通,建议收藏

没脾气

Python

RA8D1-Vision Board上OSPI-Flash实践

梦笔生花

瑞萨MCU

蓝易云 - javaee springMVC数字类型转换之通过注解的方式

百度搜索:蓝易云

Java 云计算 运维 服务器 云服务器

蓝易云 - 6元一年的云服务器

百度搜索:蓝易云

云计算 运维 服务器 服务器租用 高防服务器

跨越云端,华为云技术专家分享高效跨云迁移实践

华为云开发者联盟

云原生 华为云 数据迁移 华为云开发者联盟 企业号2024年6月PK榜

惊了!字节大佬总结的这份《零基础学python神级笔记全彩版》真的太强了

没脾气

Python 程序员 自学编程 架构师 自学python

蓝易云 - javaee springMVC cookie的存入和取出

百度搜索:蓝易云

云计算 运维 Cookie 云服务器 JavaEE

“专业敏捷教练课程” 7月6-7日 · CSP-SM认证上海线下面授周末班【晋升高阶享多重福利】

ShineScrum捷行

敏捷教练 专业敏捷教练 敏捷教练认证

GitHub爆火标星127k!这份字节Python背记手册到底有什么魔力?

没脾气

Python 程序员 自学编程 python教程 python自学

What’s new in Apache/dubbo-getty 1.5.0

apache/dubbo-go

dubbo

Pika 主从数据同步状态指标 “repl_connect_status” 简介

apache/dubbo-go

redis Pika

蓝易云 - javaee springMVC自定义转换类实现日期类型转换

百度搜索:蓝易云

Java json mvc 运维 服务器

Exploring Wi-Fi 6 Applications and Prospects in Industrial AGVs

wallyslilly

ipq5018

深度剖析集团型企业在新质生产力和数字化转型过程中面临的身份管理问题(二)

芯盾时代

iam 统一管理 统一身份 统一身份管理平台

使用Python实现深度学习模型:序列到序列模型(Seq2Seq)

华为云开发者联盟

Python 人工智能 华为云 华为云开发者联盟 企业号2024年6月PK榜

天润融通,荣获2024中国AI应用层创新企业

天润融通

人工智能 天润融通

Linux设备驱动系列(14) —— 使用全局工作队列

Linux内核拾遗

Linux内核 中断 工作队列

读书笔记《一如既往》

酱紫的小白兔

蓝易云 - javaee springMVC model的使用

百度搜索:蓝易云

Java 云计算 运维 服务器 云服务器

前端生成海报图技术选型与问题解决

vivo互联网技术

html2canvas 海报图生成 painter

什么是智能合约?

dappweb

智能合约开发

透明LED显示屏的未来发展趋势

Dylan

媒体 科技 LED显示屏 led显示屏厂家 市场

量子计算如何彻底改变区块链

区块链开发团队DappNetWork

被称为“三大框架”替代方案,Svelte如何简化Web开发工作(上)_文化 & 方法_Mark Volkmann_InfoQ精选文章