Svelte provides various built-in special elements.
1、<svelte:self>
First introduced <svelte:self>
, it represents the current component, allowing recursion into itself in some cases, which is useful for showing views like folder trees, where folders can contain other folders.
The following is an example of displaying the folder tree Folder
:
Folder.svelte
<script>
export let name = 'noname';
export let folders = []
</script>
<style>
ul { padding: 0.2em 0 0 1.5em; margin: 0 0 0 0.5em; list-style: none; }
li { padding: 0.2em 0; }
</style>
<span>- {name}</span>
<ul>
{#each folders as f}
<li>
<!-- 此处展示下一级的文件夹 -->
</li>
{/each}
</ul>
App.svelte
<script>
import Folder from './Folder.svelte';
let folders = [
{
name: '音乐',
folders: [
{ name: '流行音乐' },
{ name: '纯音乐' },
{ name: '吉他' }
]
},
{
name: '电影',
folders: [
{
name: '喜剧片',
folders: [
{ name: '周星驰' },
{ name: '黄渤' },
{ name: '沈腾' }
]
},
{
name: '动作片',
folders: [ { name: '李连杰' } ]
}
]
}
];
</script>
<Folder name="D盘" {folders} />
The current results only show the root directory:
To display all subdirectories, this is not possible:
Folder.svelte
{#each folders as f}
<li>
<Folder {...f} />
</li>
{/each}
That is, you cannot use itself directly in Folder.svelte <Folder>
because a module cannot import itself. But we can use <svelte:self>
the delegate itself:
Folder.svelte
{#each folders as f}
<li>
<svelte:self {...f} />
</li>
{/each}
final result:
Based on <svelte:self>
the function of referencing the constructor of its own component, it is very easy to cause stack overflow.
Just imagine, components Folder
are used in components Folder
. If there is no "restriction", it will be rendered endlessly by default until the stack explodes and an error is reported.
Therefore, <svelte:self>
it must be wrapped in #if
a block or #each
a block, or 插槽
passed to a component, and the rest are prohibited.
2、<svelte:component>
Components can <svelte:component>
be "morphed" by doing away with a series of if
blocks...
For example we have 3 very simple components (display text in different colors):
Red.svelte
<strong style="color: red">red text</strong>
Green.svelte
<strong style="color: green">green text</strong>
Blue.svelte
<strong style="color: blue">blue text</strong>
If our main program needs to display different color text according to the selection of a drop-down box:
Then the program may need a lot of if
judgments:
App.svelte
<script>
import Red from './Red.svelte';
import Green from './Green.svelte';
import Blue from './Blue.svelte';
let selected;
</script>
<select bind:value={selected}>
<option value="red">红</option>
<option value="green">绿</option>
<option value="blue">蓝</option>
</select>
{#if selected == 'red'}
<Red />
{:else if selected == 'green'}
<Green />
{:else }
<Blue />
{/if}
By using <svelte:component>
, you can eliminate many if
and use these 3 components more dynamically:
App.svelte
<script>
import Red from './Red.svelte';
import Green from './Green.svelte';
import Blue from './Blue.svelte';
let selected = '0';
$: component = [Red, Green, Blue][selected]
</script>
<select bind:value={selected}>
<option value="0">红</option>
<option value="1">绿</option>
<option value="2">蓝</option>
</select>
<svelte:component this={component} />
this
The value of can be any component's constructor, if a false value is provided, the component will not be rendered.
3、<svelte:window>
Just as any DOM element can listen to events, you can <svelte:window>
listen to window
object events, such as mouse movement events, by:
App.svelte
<script>
let x, y
</script>
<svelte:window on:mousemove={ e => ({x, y} = e) } />
<p>鼠标位置:{x}, {y}</p>
You can also add event modifiers
preventDefault
like this in the same way as DOM elements.
to bind
We can also bind some window
attributes. For some businesses, we may need to monitor the size of the browser window. The native writing method is window.onresize
realized by monitoring.
In Svelte it's even simpler and supports bindings:
App.svelte
<script>
let width, height
</script>
<svelte:window bind:innerWidth={width} bind:innerHeight={height} />
<p>Window Size: width={width}, height={height}</p>
The list of properties that support binding is as follows:
innerWidth
- Gets the width of the browser window's content area, including vertical scrollbars (if any)innerHeight
- Gets the height of the browser window's content area, including horizontal scrollbars (if any)outerWidth
- Get the width of the browser windowouterHeight
- get the height of the browser windowscrollX
- The number of pixels the document has scrolled in the horizontal directionscrollY
- the number of pixels the document has scrolled verticallyonline
-window.navigator.onLine
is an alias, representing when the browser can access the network.
All but scrollX
two scrollY
properties are read-only.
4、<svelte:body>
Similar to <svelte:window>
, <svelte:body>
elements allow you to listen to document.body
events on them. This is useful for mouseenter
and events, which cannot be fired on.mouseleave
window
App.svelte
<script>
let msg = ''
</script>
<svelte:body
on:mouseenter={() => msg = 'Enter'}
on:mouseleave={() => msg = 'Leave'}
/>
<div>{msg}</div>
5、<svelte:head>
<svelte:head>
element allows you to insert other elements into your document <head>
:
App.svelte
<svelte:head>
<!-- 插入到 <head> 的内容写在这里 -->
</svelte:head>
<h1>Hello world!</h1>
<head>
Elements such as <script>
, <link>
, <title>
and etc. can be inserted in :<meta>
App.svelte
<svelte:head>
<link rel="stylesheet" href="./global.css">
</svelte:head>
In server-side rendering (SSR) mode,
<svelte:head>
the content of is returned separately from the rest of the HTML.
6、<svelte:fragment>
Looking back at Section 3 in Chapter 13命名插槽
"Slots" - Naming the slot, when we provide content to the content, we inevitably need to use an element or component, for example:
<span slot="address">42 Wallaby Way Sydney</span>
If there is no span
element, there slot="address"
is nowhere to put it.
Assume that in some cases, we may affect the original layout of the component with the help of other elements, and even be forced to abandon the original UI description scheme, such as the example below to list the materials required for making pineapple bags :
Material.svelte
<h4>菠萝包的食材用料:</h4>
<ul>
<li>盐</li>
<li>砂糖</li>
<li>奶粉</li>
<slot name="bottom" />
</ul>
<style>
h4 { background: green; padding: 1em; color: #fff; }
</style>
In the example, a position is reserved for the user to add more materials, such as bottom
adding another "high-gluten flour" to the position:
App.svelte
<script>
import Material from './Material.svelte'
</script>
<Material>
<li slot="bottom">高筋面粉</li>
</Material>
Judging from the displayed result graph, it is perfect at present:
&amp;lt;svelte:fragment&amp;gt; 示例
There is also "low-gluten flour" in the pineapple buns. If you want to put it in bottom
the place, then embarrassing things will happen:
App.svelte
<script>
import Material from './Material.svelte'
</script>
<Material>
<li slot="bottom">高筋面粉</li>
<li slot="bottom">低筋面粉</li>
</Material>
Svelte does not allow two content with the same slot name (refer to Section 3 in Chapter 13, "Slots"), and you will receive an error message: "Duplicate slot name "bottom" in <Material>".
The next solution that immediately comes to mind is this:
App.svelte
<script>
import Material from './Material.svelte'
</script>
<Material>
<div slot="bottom">
<li>高筋面粉</li>
<li>低筋面粉</li>
</div>
</Material>
In order to give new words to express sorrow. Imposed one div
as a container to see the result seems to be right again:
But don't be fooled by appearances, here's the actual HTML:
If you use a horizontal layout for all materials, this problem will be revealed:
Material.svelte
...
<style>
h4 { background: green; padding: 1em; color: #fff; }
/* 使列表呈横向布局 */
ul { display: flex; }
:global(.list li) { margin: auto 20px; }
</style>
You may have noticed that the last style rule, is used:global( )
, this is because the<slot>
added<li>
material items via the do not<li>
automatically apply the same styles as in the Material component .
Because the style is the default in the component局部作用域
.
In this case, you must use this style with全局
styles (via the :global pseudo-class), so that the styles<slot>
in<li>
Material can be applied in the content<li>
.
The result looks like this:
This is the problem of "may affect the original layout of the component" mentioned above . <svelte:fragment>
It was created to solve this problem. Just <div>
change it to the following <svelte:fragment>
, and the problem will be solved:
App.svelte
<script>
import Material from './Material.svelte'
</script>
<Material>
<svelte:fragment slot="bottom">
<li>高筋面粉</li>
<li>低筋面粉</li>
</svelte:fragment>
</Material>
7、<svelte:options>
<svelte:options>
Options that allow you to configure the compiler.
For example, if you want to generate property accessors for components (not generated by default):
App.svelte
<script>
export let x = 'hello'
</script>
<svelte:options accessors />
<p>{x}</p>
After being svelte:options
added accessors
, the final generated App
class is as follows:
class App extends SvelteComponent {
constructor(options) {
super();
init(this, options, instance, create_fragment, safe_not_equal, { x: 0 });
}
get x() {
return this.$$.ctx[0];
}
set x(x) {
this.$set({ x });
flush();
}
}
export default App;
You can notice that the variable x
has been generated as App
an attribute of the class. If this compilation option is not specified, the generated App class will look like this:
class App extends SvelteComponent {
constructor(options) {
super();
init(this, options, instance, create_fragment, safe_not_equal, { x: 0 });
}
}
export default App;
The purpose of generating attribute accessors is to provide easier access for the user. This option is usually required when you write a Svelte component and want to use it in React or Vue at the same time.
The following are the possible values that are allowed to be set here:
immutable={true}
: You are sure that mutable data will not be used, so the compiler can perform a simple reference equality check to determine if the value has changed.immutable={false}
: The default value, Svelte will handle the change of mutable objects in the default wayaccessors={true}
: Add getters and setters for component propsaccessors={false}
:Defaultsnamespace="..."
: The namespace of this component will be used, most commonly the"svg"
tag="..."
: The tag name specified when compiling the component into a custom element
Please refer to the API documentation for details on these options.
Summarize
For <svelte:options>
99.9% of the cases, you don't need to manually interfere with the compiler's default options unless you have a very clear reason.
<svelte:fragment>
Similar to the function of Vue <template>
, it is expected to be a container for elements, but at the same time it does not need to be rendered.
<svelte:window>
Some very useful bindings are provided, such as size-related innerWidth
sums innerHeight
and scrollbar-related sums scrollX
, scrollY
both of which also support assignment, which can make writing programs in this area easier.