svelte special element

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 ifblocks...

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  ifand 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} />

thisThe 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 windowobject 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 windowattributes. 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 window
  • outerHeight - get the height of the browser window
  • scrollX - The number of pixels the document has scrolled in the horizontal direction
  • scrollY - the number of pixels the document has scrolled vertically
  • online -  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.bodyevents on them. This is useful for mouseenterand events, which cannot be fired on.mouseleavewindow

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;amp;lt;svelte:fragment&amp;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 way
  • accessors={true}: Add getters and setters for component props
  • accessors={false}:Defaults
  • namespace="...": 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  innerWidthsums  innerHeightand scrollbar-related sums  scrollX ,  scrollYboth of which also support assignment, which can make writing programs in this area easier.

Guess you like

Origin blog.csdn.net/ramblerviper/article/details/124943638