@lightningjs/blits 1.30.1 → 1.30.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.editorconfig +7 -7
- package/.eslintignore +1 -1
- package/.eslintrc.cjs +65 -65
- package/.github/workflows/comment-lint-results.yml +124 -124
- package/.github/workflows/comment-test-results.yml +108 -108
- package/.github/workflows/deploy-docs.yml +27 -27
- package/.github/workflows/run-blits-tests.yml +141 -141
- package/.github/workflows/run-lint.yml +127 -127
- package/.husky/pre-commit +1 -1
- package/.vscode/extensions.json +7 -7
- package/.vscode/settings.json +9 -9
- package/CHANGELOG.md +1019 -1012
- package/COPYING +1 -0
- package/LICENSE +202 -202
- package/NOTICE +12 -12
- package/README.md +33 -33
- package/bin/index.js +8 -8
- package/blits.d.ts +6 -6
- package/docs/README.md +19 -19
- package/docs/_sidebar.md +37 -37
- package/docs/built-in/directives.md +50 -50
- package/docs/built-in/for-loop.md +203 -203
- package/docs/built-in/layout.md +168 -168
- package/docs/components/component_state.md +90 -90
- package/docs/components/computed_properties.md +45 -45
- package/docs/components/lifecycle_events.md +42 -42
- package/docs/components/methods.md +45 -45
- package/docs/components/props.md +56 -56
- package/docs/components/user_input.md +186 -186
- package/docs/components/utility_methods.md +320 -320
- package/docs/components/watchers.md +34 -34
- package/docs/essentials/application_root.md +19 -19
- package/docs/essentials/components.md +68 -68
- package/docs/essentials/displaying_images.md +67 -67
- package/docs/essentials/displaying_text.md +135 -135
- package/docs/essentials/element_attributes.md +195 -195
- package/docs/essentials/settings.md +117 -117
- package/docs/essentials/template_syntax.md +83 -83
- package/docs/getting_started/file_structure.md +58 -58
- package/docs/getting_started/getting_started.md +45 -45
- package/docs/getting_started/intro.md +20 -20
- package/docs/index.html +47 -47
- package/docs/performance/lazy-loading.md +161 -161
- package/docs/plugins/global_app_state.md +98 -98
- package/docs/plugins/language.md +172 -172
- package/docs/plugins/text-to-speech-announcer.md +119 -119
- package/docs/plugins/theme.md +176 -176
- package/docs/router/basics.md +175 -175
- package/docs/router/hooks.md +70 -70
- package/docs/router/transitions.md +146 -146
- package/docs/sidebar.json +171 -171
- package/docs/transitions_animations/transitions.md +150 -150
- package/index.d.ts +1099 -1099
- package/index.js +28 -28
- package/jsconfig.json +12 -12
- package/package.json +56 -56
- package/public/assets/fps_sprite.base64.js +1 -1
- package/scripts/postpublish.js +59 -59
- package/scripts/prepublishOnly.js +84 -84
- package/scripts/prepush.js +78 -78
- package/src/announcer/announcer.js +162 -162
- package/src/announcer/speechSynthesis.js +107 -107
- package/src/application.js +100 -100
- package/src/component/base/announcer.js +27 -27
- package/src/component/base/events.js +69 -69
- package/src/component/base/index.js +33 -33
- package/src/component/base/methods.js +244 -244
- package/src/component/base/router.js +41 -41
- package/src/component/base/timeouts_intervals.js +99 -99
- package/src/component/base/utils.js +72 -72
- package/src/component/setup/computed.js +48 -48
- package/src/component/setup/index.js +62 -62
- package/src/component/setup/input.js +30 -30
- package/src/component/setup/methods.js +37 -37
- package/src/component/setup/props.js +62 -62
- package/src/component/setup/props.test.js +238 -238
- package/src/component/setup/routes.js +42 -42
- package/src/component/setup/state.js +59 -59
- package/src/component/setup/watch.js +35 -35
- package/src/component.js +437 -437
- package/src/component.test.js +388 -388
- package/src/components/Circle.js +73 -73
- package/src/components/Circle.orig.js +31 -31
- package/src/components/FPScounter.js +1510 -1510
- package/src/components/FPScounter.orig.js +121 -121
- package/src/components/RouterView.js +81 -81
- package/src/components/RouterView.orig.js +54 -54
- package/src/components/Sprite.js +94 -94
- package/src/components/Sprite.orig.js +58 -58
- package/src/components/index.js +28 -28
- package/src/components/index.orig.js +28 -28
- package/src/constants.js +21 -21
- package/src/engine.js +1 -1
- package/src/engines/L3/element.js +744 -744
- package/src/engines/L3/element.test.js +579 -579
- package/src/engines/L3/fontLoader.js +38 -38
- package/src/engines/L3/index.js +7 -7
- package/src/engines/L3/launch.js +123 -123
- package/src/engines/L3/shaderLoader.js +12 -12
- package/src/engines/index.js +1 -1
- package/src/focus.js +90 -90
- package/src/helpers/deepEqualArray.js +50 -50
- package/src/helpers/deepEqualArray.test.js +127 -127
- package/src/helpers/fetchJson.js +34 -34
- package/src/helpers/sequence.js +26 -26
- package/src/launch.js +123 -123
- package/src/lib/blitsfileconverter/blitsfileconverter.js +52 -52
- package/src/lib/codegenerator/generator.js +788 -788
- package/src/lib/codegenerator/generator.test.js +3801 -3801
- package/src/lib/colors/colors.js +92 -92
- package/src/lib/colors/colors.test.js +290 -290
- package/src/lib/colors/htmlColors.js +168 -168
- package/src/lib/componentId.js +49 -49
- package/src/lib/componentId.test.js +84 -84
- package/src/lib/eventListeners.js +123 -123
- package/src/lib/eventListeners.test.js +236 -236
- package/src/lib/hooks.js +59 -59
- package/src/lib/lifecycle.js +85 -85
- package/src/lib/log.js +117 -117
- package/src/lib/precompiler/precompiler.js +73 -73
- package/src/lib/reactivity/effect.js +93 -93
- package/src/lib/reactivity/effect.test.js +35 -35
- package/src/lib/reactivity/reactive.js +208 -208
- package/src/lib/reactivity/reactive.test.js +27 -27
- package/src/lib/reactivityguard/computedprops.js +218 -218
- package/src/lib/symbols.js +108 -108
- package/src/lib/templateparser/parser.js +386 -386
- package/src/lib/templateparser/parser.test.js +1411 -1411
- package/src/lib/utils.js +27 -27
- package/src/plugin.js +27 -27
- package/src/plugins/appstate.js +26 -26
- package/src/plugins/index.js +20 -20
- package/src/plugins/language.js +152 -152
- package/src/plugins/log.js +25 -25
- package/src/plugins/theme.js +94 -94
- package/src/router/router.js +514 -514
- package/src/router/router.test.js +473 -473
- package/src/router/transitions/fadeIn.js +27 -27
- package/src/router/transitions/fadeInOut.js +33 -33
- package/src/router/transitions/index.js +21 -21
- package/src/router/transitions/slideIn.js +28 -28
- package/src/router/transitions/slideInOut.js +33 -33
- package/src/settings.js +40 -40
- package/vite/blitsFileConverter.js +67 -67
- package/vite/index.js +28 -28
- package/vite/msdfGenerator.js +269 -269
- package/vite/preCompiler.js +42 -42
- package/vite/reactivityGuard.js +45 -45
- package/vscode/data/template-attributes.json +589 -589
package/docs/_sidebar.md
CHANGED
|
@@ -1,37 +1,37 @@
|
|
|
1
|
-
- Getting started
|
|
2
|
-
- [Intro](/getting_started/intro.md)
|
|
3
|
-
- [Getting started](/getting_started/getting_started.md)
|
|
4
|
-
- [File structure](/getting_started/file_structure.md)
|
|
5
|
-
- Essentials
|
|
6
|
-
- [Application root](/essentials/application_root.md)
|
|
7
|
-
- [Component basics](/essentials/components.md)
|
|
8
|
-
- [Template syntax](/essentials/template_syntax.md)
|
|
9
|
-
- [Supported element attributes](/essentials/element_attributes.md)
|
|
10
|
-
- [Displaying images](/essentials/displaying_images.md)
|
|
11
|
-
- [Displaying text](/essentials/displaying_text.md)
|
|
12
|
-
- Components
|
|
13
|
-
- [State](/components/component_state.md)
|
|
14
|
-
- [Props](/components/props.md)
|
|
15
|
-
- [Computed properties](/components/computed_properties.md)
|
|
16
|
-
- [Watchers](/components/watchers.md)
|
|
17
|
-
- [Hooking into lifecycle events](/components/lifecycle_events.md)
|
|
18
|
-
- [Handling User input](/components/user_input.md)
|
|
19
|
-
- [Methods](/components/methods.md)
|
|
20
|
-
- [Utility methods](/components/utility_methods.md)
|
|
21
|
-
- Transitions and Animations
|
|
22
|
-
- [Transitions](/transitions_animations/transitions.md)
|
|
23
|
-
- Built-in components
|
|
24
|
-
- [Directives](/built-in/directives.md)
|
|
25
|
-
- [For loop](/built-in/for-loop.md)
|
|
26
|
-
- [Layout](/built-in/layout.md)
|
|
27
|
-
- Router
|
|
28
|
-
- [Basics](/router/basics.md)
|
|
29
|
-
- [Hooks](/router/hooks.md)
|
|
30
|
-
- [Transitions](/router/transitions.md)
|
|
31
|
-
- Plugins
|
|
32
|
-
- [Text-to-Speech / Announcer](/plugins/text-to-speech-announcer.md)
|
|
33
|
-
- [Language](/plugins/language.md)
|
|
34
|
-
- [Theme](/plugins/theme.md)
|
|
35
|
-
- [Global App State](/plugins/global_app_state.md)
|
|
36
|
-
- Performance
|
|
37
|
-
- [Lazy loading]('/performance/lazy-loading.md')
|
|
1
|
+
- Getting started
|
|
2
|
+
- [Intro](/getting_started/intro.md)
|
|
3
|
+
- [Getting started](/getting_started/getting_started.md)
|
|
4
|
+
- [File structure](/getting_started/file_structure.md)
|
|
5
|
+
- Essentials
|
|
6
|
+
- [Application root](/essentials/application_root.md)
|
|
7
|
+
- [Component basics](/essentials/components.md)
|
|
8
|
+
- [Template syntax](/essentials/template_syntax.md)
|
|
9
|
+
- [Supported element attributes](/essentials/element_attributes.md)
|
|
10
|
+
- [Displaying images](/essentials/displaying_images.md)
|
|
11
|
+
- [Displaying text](/essentials/displaying_text.md)
|
|
12
|
+
- Components
|
|
13
|
+
- [State](/components/component_state.md)
|
|
14
|
+
- [Props](/components/props.md)
|
|
15
|
+
- [Computed properties](/components/computed_properties.md)
|
|
16
|
+
- [Watchers](/components/watchers.md)
|
|
17
|
+
- [Hooking into lifecycle events](/components/lifecycle_events.md)
|
|
18
|
+
- [Handling User input](/components/user_input.md)
|
|
19
|
+
- [Methods](/components/methods.md)
|
|
20
|
+
- [Utility methods](/components/utility_methods.md)
|
|
21
|
+
- Transitions and Animations
|
|
22
|
+
- [Transitions](/transitions_animations/transitions.md)
|
|
23
|
+
- Built-in components
|
|
24
|
+
- [Directives](/built-in/directives.md)
|
|
25
|
+
- [For loop](/built-in/for-loop.md)
|
|
26
|
+
- [Layout](/built-in/layout.md)
|
|
27
|
+
- Router
|
|
28
|
+
- [Basics](/router/basics.md)
|
|
29
|
+
- [Hooks](/router/hooks.md)
|
|
30
|
+
- [Transitions](/router/transitions.md)
|
|
31
|
+
- Plugins
|
|
32
|
+
- [Text-to-Speech / Announcer](/plugins/text-to-speech-announcer.md)
|
|
33
|
+
- [Language](/plugins/language.md)
|
|
34
|
+
- [Theme](/plugins/theme.md)
|
|
35
|
+
- [Global App State](/plugins/global_app_state.md)
|
|
36
|
+
- Performance
|
|
37
|
+
- [Lazy loading]('/performance/lazy-loading.md')
|
|
@@ -1,50 +1,50 @@
|
|
|
1
|
-
# Directives
|
|
2
|
-
|
|
3
|
-
Blits comes with a few built-in attributes that tap into specific behaviour provided by the framework - also known as _directives_. Most of them can be used in the template on both Elements and Components.
|
|
4
|
-
|
|
5
|
-
## Show-directive
|
|
6
|
-
|
|
7
|
-
The `show` attribute allows you to conditionally show and hide Components and Elements.
|
|
8
|
-
|
|
9
|
-
When passed a _truthy_ value, such as `true` or `1`, the element will be made visible. And when passed a _falsey_ value (`false` or `0`) it will not be visible.
|
|
10
|
-
|
|
11
|
-
```xml
|
|
12
|
-
<Element>
|
|
13
|
-
<Element w="100" h="100" color="purple" :show="$active"></Element>
|
|
14
|
-
<Element w="100" h="100" y="200" color="purple" show="false"></Element>
|
|
15
|
-
</Element>
|
|
16
|
-
```
|
|
17
|
-
|
|
18
|
-
## Is-directive
|
|
19
|
-
|
|
20
|
-
The `is` directive allows you to dynamically instantiate a Component based on a `state` variable or a passed `prop`.
|
|
21
|
-
|
|
22
|
-
It is very useful in combination with API driven Apps, where the type of Component to use, depends on what data is returned (i.e. a `Poster` or a `HeroImage`).
|
|
23
|
-
|
|
24
|
-
The `is`-component should always be used together with the built-in `Component`-tag.
|
|
25
|
-
|
|
26
|
-
```js
|
|
27
|
-
export default Blits.Component('DynamicComponents', {
|
|
28
|
-
template: `
|
|
29
|
-
<Element>
|
|
30
|
-
<Component is="$firstComponent" />
|
|
31
|
-
<Component is="$secondComponent" x="500" />
|
|
32
|
-
</Element>
|
|
33
|
-
`,
|
|
34
|
-
props: ['firstComponent', 'secondComponent'],
|
|
35
|
-
})
|
|
36
|
-
```
|
|
37
|
-
|
|
38
|
-
At the moment it's not possible to use the `is`-attribute as a _reactive_ attribute and have a component change type after instantiation.
|
|
39
|
-
|
|
40
|
-
## Ref-attribute
|
|
41
|
-
|
|
42
|
-
The declarative coding style that is promoted in Blits components, should generally remove the need to directly interact with individual Elements or Components in your template. However, in some cases you may need to reference them directly. For example, in order to delegate the focus.
|
|
43
|
-
|
|
44
|
-
For this use case, you can specify a `ref`-attribute on Elements (or Components). And by using the helper function `this.select()`, which is available on every Blits component, you can gain access to the child Element or Component inside your business logic.
|
|
45
|
-
|
|
46
|
-
The `select()`-function accepts the `ref`-value that you are looking for as a single argument, and returns the Element or Component if found.
|
|
47
|
-
|
|
48
|
-
<!-- ### If-directive
|
|
49
|
-
|
|
50
|
-
Todo -->
|
|
1
|
+
# Directives
|
|
2
|
+
|
|
3
|
+
Blits comes with a few built-in attributes that tap into specific behaviour provided by the framework - also known as _directives_. Most of them can be used in the template on both Elements and Components.
|
|
4
|
+
|
|
5
|
+
## Show-directive
|
|
6
|
+
|
|
7
|
+
The `show` attribute allows you to conditionally show and hide Components and Elements.
|
|
8
|
+
|
|
9
|
+
When passed a _truthy_ value, such as `true` or `1`, the element will be made visible. And when passed a _falsey_ value (`false` or `0`) it will not be visible.
|
|
10
|
+
|
|
11
|
+
```xml
|
|
12
|
+
<Element>
|
|
13
|
+
<Element w="100" h="100" color="purple" :show="$active"></Element>
|
|
14
|
+
<Element w="100" h="100" y="200" color="purple" show="false"></Element>
|
|
15
|
+
</Element>
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
## Is-directive
|
|
19
|
+
|
|
20
|
+
The `is` directive allows you to dynamically instantiate a Component based on a `state` variable or a passed `prop`.
|
|
21
|
+
|
|
22
|
+
It is very useful in combination with API driven Apps, where the type of Component to use, depends on what data is returned (i.e. a `Poster` or a `HeroImage`).
|
|
23
|
+
|
|
24
|
+
The `is`-component should always be used together with the built-in `Component`-tag.
|
|
25
|
+
|
|
26
|
+
```js
|
|
27
|
+
export default Blits.Component('DynamicComponents', {
|
|
28
|
+
template: `
|
|
29
|
+
<Element>
|
|
30
|
+
<Component is="$firstComponent" />
|
|
31
|
+
<Component is="$secondComponent" x="500" />
|
|
32
|
+
</Element>
|
|
33
|
+
`,
|
|
34
|
+
props: ['firstComponent', 'secondComponent'],
|
|
35
|
+
})
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
At the moment it's not possible to use the `is`-attribute as a _reactive_ attribute and have a component change type after instantiation.
|
|
39
|
+
|
|
40
|
+
## Ref-attribute
|
|
41
|
+
|
|
42
|
+
The declarative coding style that is promoted in Blits components, should generally remove the need to directly interact with individual Elements or Components in your template. However, in some cases you may need to reference them directly. For example, in order to delegate the focus.
|
|
43
|
+
|
|
44
|
+
For this use case, you can specify a `ref`-attribute on Elements (or Components). And by using the helper function `this.select()`, which is available on every Blits component, you can gain access to the child Element or Component inside your business logic.
|
|
45
|
+
|
|
46
|
+
The `select()`-function accepts the `ref`-value that you are looking for as a single argument, and returns the Element or Component if found.
|
|
47
|
+
|
|
48
|
+
<!-- ### If-directive
|
|
49
|
+
|
|
50
|
+
Todo -->
|
|
@@ -1,204 +1,204 @@
|
|
|
1
|
-
# For loop
|
|
2
|
-
|
|
3
|
-
The for loop is technically also a [directive](../directives.md), but such an important one that it deserves its own section.
|
|
4
|
-
|
|
5
|
-
The for loop directive can be used when you want to repeat multiple instances of an Element or a Component, without having to specify them hardcoded one by one in your template.
|
|
6
|
-
|
|
7
|
-
The for loop takes an `Array` of data, loops over it and for each Array-item an Element or Component is created. The `Array` can be a fixed one, but it can also dynamically be filled or modified and have it's changes reflect in the rendered result.
|
|
8
|
-
|
|
9
|
-
> Important: the for loop is a powerful and often used directive. Within Blits it's optimized to be as performant as possible. But if used incorrectly, it can be the cause of slow performance. So please read carefully through this entire section.
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
## Basic syntax
|
|
13
|
-
|
|
14
|
-
The for-loop directive should be added as an attribute on the Element or Component that you want to repeat for each item in your Array. In the template syntax a `for ... in` construct is used. This ultimately transpiles down to a classic, optimized for loop.
|
|
15
|
-
|
|
16
|
-
```js
|
|
17
|
-
export default Blits.Component('ForLoop', {
|
|
18
|
-
template: `
|
|
19
|
-
<Element>
|
|
20
|
-
<Element :for="item in $items" w="100" h="100" color="lime" />
|
|
21
|
-
</Element>
|
|
22
|
-
`,
|
|
23
|
-
state() {
|
|
24
|
-
return {
|
|
25
|
-
items: ['Item 1', 'Item 2', 'Item 3']
|
|
26
|
-
}
|
|
27
|
-
},
|
|
28
|
-
})
|
|
29
|
-
```
|
|
30
|
-
|
|
31
|
-
The example above will generate 3 _lime green_ elements, based on the array of `items` in the Component state. They will appear on top of each other though, since they have no `x` and `y` positioning (which default to 0).
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
## Using the index
|
|
35
|
-
|
|
36
|
-
In order to fix the example above and make all 3 elements visible, we can use the `index` of the Array to position each item correctly.
|
|
37
|
-
|
|
38
|
-
All we need to do is declare the `index` in the `for`-directive and subsequently use it in the `x`-attribute, with a simple calculation.
|
|
39
|
-
|
|
40
|
-
You may choose any name for the `index` variable (like `i` or `forIndex`). This may be useful when you already have the `index`-key specified as a `state` or `prop` variable on your component, causing a conflict.
|
|
41
|
-
|
|
42
|
-
```js
|
|
43
|
-
export default Blits.Component('ForLoop', {
|
|
44
|
-
template: `
|
|
45
|
-
<Element>
|
|
46
|
-
<Element :for="(item, index) in $items" w="100" h="100" color="lime" :x="$index * 150" />
|
|
47
|
-
</Element>
|
|
48
|
-
`,
|
|
49
|
-
state() {
|
|
50
|
-
return {
|
|
51
|
-
items: ['Item 1', 'Item 2', 'Item 3']
|
|
52
|
-
}
|
|
53
|
-
},
|
|
54
|
-
})
|
|
55
|
-
```
|
|
56
|
-
|
|
57
|
-
You will now see that each Element is positioned next to each other, with a 50px space in between.
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
## Using variables inside a for loop
|
|
61
|
-
|
|
62
|
-
When iterating over an Array in the for loop, you can reference the current Array item under the name specified in the for-in construct, prefixed with a `$`-sign. Besides this scoped Array item context, you _also_ have access to any `prop`, `state` or `computed` variable as you loop over an Array.
|
|
63
|
-
|
|
64
|
-
Consider the example below, that loops over an array of _Objects_, and _also_ references the `alpha` state variable.
|
|
65
|
-
|
|
66
|
-
```js
|
|
67
|
-
export default Blits.Component('ForLoop', {
|
|
68
|
-
template: `
|
|
69
|
-
<Element>
|
|
70
|
-
<Element
|
|
71
|
-
:for="(item, index) in $items"
|
|
72
|
-
w="100"
|
|
73
|
-
h="100"
|
|
74
|
-
:color="$item.color"
|
|
75
|
-
:x="$index * 150"
|
|
76
|
-
alpha="$alpha"
|
|
77
|
-
/>
|
|
78
|
-
</Element>
|
|
79
|
-
`,
|
|
80
|
-
state() {
|
|
81
|
-
return {
|
|
82
|
-
alpha: 0.5,
|
|
83
|
-
items: [{
|
|
84
|
-
id: 1,
|
|
85
|
-
color: 'green'
|
|
86
|
-
}, {
|
|
87
|
-
id: 2,
|
|
88
|
-
color: 'blue'
|
|
89
|
-
}, {
|
|
90
|
-
id: 3,
|
|
91
|
-
color: 'yellow'
|
|
92
|
-
}]
|
|
93
|
-
}
|
|
94
|
-
},
|
|
95
|
-
})
|
|
96
|
-
```
|
|
97
|
-
|
|
98
|
-
This will generate 3 squares aligned next to each other, each with a different color and they will use the _alpha_ specific in the Component state.
|
|
99
|
-
|
|
100
|
-
## The importance of using the key attribute
|
|
101
|
-
|
|
102
|
-
The examples above have demonstrated the basic usage of the for-loop. But they are all missing one _very important_ ingredient to make sure that for-loops that are subject to change, continue to perform well. Meet the `key`-attribute.
|
|
103
|
-
|
|
104
|
-
For performance reasons, it is essential to be able track the _identity_ of an Element or Component, whenever changes are made to the Array in the for loop.
|
|
105
|
-
|
|
106
|
-
Think of _identity_ as the field that makes an item in the Array unique, such as an `id` or a `hash`. It's basically the thing that allows you to distinguish between the poster of _The Matrix_ and the poster of _Frozen 2_, for example.
|
|
107
|
-
|
|
108
|
-
Providing this information, allows the for-loop to decide whether it should _update_ an existing Component or Element instance. Or whether we're dealing with a new Array item, and a new instance should be _created_.
|
|
109
|
-
|
|
110
|
-
Correctly using the `key`-attribute enables Blits to _reuse_ existing instances whenever possible - which obviously is good for performance.
|
|
111
|
-
|
|
112
|
-
It's important that the `key`-attribute is _unique_ for each Array item. Also beware that we can't rely on the `index` parameter provided in for loop, because that only identifies the position in the Array, and not the actual item itself.
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
```js
|
|
116
|
-
export default Blits.Component('ForLoop', {
|
|
117
|
-
template: `
|
|
118
|
-
<Element>
|
|
119
|
-
<Element
|
|
120
|
-
:for="(item, index) in $items"
|
|
121
|
-
w="100"
|
|
122
|
-
h="100"
|
|
123
|
-
:color="$item.color"
|
|
124
|
-
:x="$index * 150"
|
|
125
|
-
alpha="$alpha"
|
|
126
|
-
key="$item.id"
|
|
127
|
-
/>
|
|
128
|
-
<!-- ^^ id is the unique field that identifies each array item -->
|
|
129
|
-
</Element>
|
|
130
|
-
`,
|
|
131
|
-
state() {
|
|
132
|
-
return {
|
|
133
|
-
alpha: 0.5,
|
|
134
|
-
items: [{
|
|
135
|
-
id: 1,
|
|
136
|
-
color: 'green'
|
|
137
|
-
}, {
|
|
138
|
-
id: 2,
|
|
139
|
-
color: 'blue'
|
|
140
|
-
}, {
|
|
141
|
-
id: 3,
|
|
142
|
-
color: 'yellow'
|
|
143
|
-
}]
|
|
144
|
-
}
|
|
145
|
-
},
|
|
146
|
-
hooks: {
|
|
147
|
-
ready() {
|
|
148
|
-
let count = 3
|
|
149
|
-
this.$setInterval(() => {
|
|
150
|
-
this.items.push({id: count++, color: randomColor()})
|
|
151
|
-
}, 2000)
|
|
152
|
-
}
|
|
153
|
-
}
|
|
154
|
-
})
|
|
155
|
-
```
|
|
156
|
-
|
|
157
|
-
In the example above we have added the `key`-attribute in the template. Now whenever we push a new item to the `items`-array, the for-loop will reuse the Elements previously created and only instantiate a new Element for the newly added item.
|
|
158
|
-
|
|
159
|
-
If we would omit the `key`-attribute, then whenever we push a new item to the Array, the for-loop would dispose all the old Elements and create new instances for _each_ item in the array.
|
|
160
|
-
|
|
161
|
-
## Referencing elements in the for loop
|
|
162
|
-
|
|
163
|
-
When you specify a `for`-attribute on an Element or a Component, it will effectively create multiple Elements / Components depending
|
|
164
|
-
on the length of the Array.
|
|
165
|
-
|
|
166
|
-
Generally it's not recommended to access and interact directly with Elements in a template, and that also goes for items in a For loop. But in some cases you may need to, for example to delegate focus to a specific item in the For loop.
|
|
167
|
-
|
|
168
|
-
The `ref`-attribute can be used in combination with the `for`-attribute as well.
|
|
169
|
-
|
|
170
|
-
Setting the _ref_ in a for loop context, can be done by either passing a string (i.e. `myitem`) and as Elements get generated in the for loop, the `index` value will be appended to it (i.e. `myitem0`, `myitem1`, etc.). Alternatively you can make the attribute interpolated and define the value for each item yourself (i.e. `:ref="'item' + $item.id"`).
|
|
171
|
-
|
|
172
|
-
## Using the range attribute
|
|
173
|
-
|
|
174
|
-
Sometimes you may only need to render a portion of an array rather than all the items.
|
|
175
|
-
|
|
176
|
-
To do this you can use the `range` variable to specify a subset of items to render. You should specify a `from` and `to` value (`from` is inclusive, and `to` is exclusive) inside the `range` variable (i.e. `range="{from: 0, to: 2}"`). You can also make the variable reactive, and use moving pointers to dynamically render your items.
|
|
177
|
-
|
|
178
|
-
This works differently to using the `show` directive on the items, as the items will be destroyed once they are outside the range, and created again when they fall back in it.
|
|
179
|
-
|
|
180
|
-
```js
|
|
181
|
-
export default Blits.Component('ForLoop', {
|
|
182
|
-
template: `
|
|
183
|
-
<Element>
|
|
184
|
-
<Element :for="(item, index) in $items" :range="{from: $selected - 1, to: $selected + 2}" w="100" h="100" color="lime" :x="$index * 150" />
|
|
185
|
-
</Element>
|
|
186
|
-
`,
|
|
187
|
-
state() {
|
|
188
|
-
return {
|
|
189
|
-
selected: 0,
|
|
190
|
-
items: ['Item 1', 'Item 2', 'Item 3', 'Item 4', 'Item 5', 'Item 6', 'Item 7']
|
|
191
|
-
}
|
|
192
|
-
},
|
|
193
|
-
input: {
|
|
194
|
-
left() {
|
|
195
|
-
this.selected = Math.max(0, this.selected - 1)
|
|
196
|
-
},
|
|
197
|
-
right() {
|
|
198
|
-
this.selected = Math.min(this.items.length, this.selected + 1)
|
|
199
|
-
}
|
|
200
|
-
}
|
|
201
|
-
})
|
|
202
|
-
```
|
|
203
|
-
|
|
1
|
+
# For loop
|
|
2
|
+
|
|
3
|
+
The for loop is technically also a [directive](../directives.md), but such an important one that it deserves its own section.
|
|
4
|
+
|
|
5
|
+
The for loop directive can be used when you want to repeat multiple instances of an Element or a Component, without having to specify them hardcoded one by one in your template.
|
|
6
|
+
|
|
7
|
+
The for loop takes an `Array` of data, loops over it and for each Array-item an Element or Component is created. The `Array` can be a fixed one, but it can also dynamically be filled or modified and have it's changes reflect in the rendered result.
|
|
8
|
+
|
|
9
|
+
> Important: the for loop is a powerful and often used directive. Within Blits it's optimized to be as performant as possible. But if used incorrectly, it can be the cause of slow performance. So please read carefully through this entire section.
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
## Basic syntax
|
|
13
|
+
|
|
14
|
+
The for-loop directive should be added as an attribute on the Element or Component that you want to repeat for each item in your Array. In the template syntax a `for ... in` construct is used. This ultimately transpiles down to a classic, optimized for loop.
|
|
15
|
+
|
|
16
|
+
```js
|
|
17
|
+
export default Blits.Component('ForLoop', {
|
|
18
|
+
template: `
|
|
19
|
+
<Element>
|
|
20
|
+
<Element :for="item in $items" w="100" h="100" color="lime" />
|
|
21
|
+
</Element>
|
|
22
|
+
`,
|
|
23
|
+
state() {
|
|
24
|
+
return {
|
|
25
|
+
items: ['Item 1', 'Item 2', 'Item 3']
|
|
26
|
+
}
|
|
27
|
+
},
|
|
28
|
+
})
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
The example above will generate 3 _lime green_ elements, based on the array of `items` in the Component state. They will appear on top of each other though, since they have no `x` and `y` positioning (which default to 0).
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
## Using the index
|
|
35
|
+
|
|
36
|
+
In order to fix the example above and make all 3 elements visible, we can use the `index` of the Array to position each item correctly.
|
|
37
|
+
|
|
38
|
+
All we need to do is declare the `index` in the `for`-directive and subsequently use it in the `x`-attribute, with a simple calculation.
|
|
39
|
+
|
|
40
|
+
You may choose any name for the `index` variable (like `i` or `forIndex`). This may be useful when you already have the `index`-key specified as a `state` or `prop` variable on your component, causing a conflict.
|
|
41
|
+
|
|
42
|
+
```js
|
|
43
|
+
export default Blits.Component('ForLoop', {
|
|
44
|
+
template: `
|
|
45
|
+
<Element>
|
|
46
|
+
<Element :for="(item, index) in $items" w="100" h="100" color="lime" :x="$index * 150" />
|
|
47
|
+
</Element>
|
|
48
|
+
`,
|
|
49
|
+
state() {
|
|
50
|
+
return {
|
|
51
|
+
items: ['Item 1', 'Item 2', 'Item 3']
|
|
52
|
+
}
|
|
53
|
+
},
|
|
54
|
+
})
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
You will now see that each Element is positioned next to each other, with a 50px space in between.
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
## Using variables inside a for loop
|
|
61
|
+
|
|
62
|
+
When iterating over an Array in the for loop, you can reference the current Array item under the name specified in the for-in construct, prefixed with a `$`-sign. Besides this scoped Array item context, you _also_ have access to any `prop`, `state` or `computed` variable as you loop over an Array.
|
|
63
|
+
|
|
64
|
+
Consider the example below, that loops over an array of _Objects_, and _also_ references the `alpha` state variable.
|
|
65
|
+
|
|
66
|
+
```js
|
|
67
|
+
export default Blits.Component('ForLoop', {
|
|
68
|
+
template: `
|
|
69
|
+
<Element>
|
|
70
|
+
<Element
|
|
71
|
+
:for="(item, index) in $items"
|
|
72
|
+
w="100"
|
|
73
|
+
h="100"
|
|
74
|
+
:color="$item.color"
|
|
75
|
+
:x="$index * 150"
|
|
76
|
+
alpha="$alpha"
|
|
77
|
+
/>
|
|
78
|
+
</Element>
|
|
79
|
+
`,
|
|
80
|
+
state() {
|
|
81
|
+
return {
|
|
82
|
+
alpha: 0.5,
|
|
83
|
+
items: [{
|
|
84
|
+
id: 1,
|
|
85
|
+
color: 'green'
|
|
86
|
+
}, {
|
|
87
|
+
id: 2,
|
|
88
|
+
color: 'blue'
|
|
89
|
+
}, {
|
|
90
|
+
id: 3,
|
|
91
|
+
color: 'yellow'
|
|
92
|
+
}]
|
|
93
|
+
}
|
|
94
|
+
},
|
|
95
|
+
})
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
This will generate 3 squares aligned next to each other, each with a different color and they will use the _alpha_ specific in the Component state.
|
|
99
|
+
|
|
100
|
+
## The importance of using the key attribute
|
|
101
|
+
|
|
102
|
+
The examples above have demonstrated the basic usage of the for-loop. But they are all missing one _very important_ ingredient to make sure that for-loops that are subject to change, continue to perform well. Meet the `key`-attribute.
|
|
103
|
+
|
|
104
|
+
For performance reasons, it is essential to be able track the _identity_ of an Element or Component, whenever changes are made to the Array in the for loop.
|
|
105
|
+
|
|
106
|
+
Think of _identity_ as the field that makes an item in the Array unique, such as an `id` or a `hash`. It's basically the thing that allows you to distinguish between the poster of _The Matrix_ and the poster of _Frozen 2_, for example.
|
|
107
|
+
|
|
108
|
+
Providing this information, allows the for-loop to decide whether it should _update_ an existing Component or Element instance. Or whether we're dealing with a new Array item, and a new instance should be _created_.
|
|
109
|
+
|
|
110
|
+
Correctly using the `key`-attribute enables Blits to _reuse_ existing instances whenever possible - which obviously is good for performance.
|
|
111
|
+
|
|
112
|
+
It's important that the `key`-attribute is _unique_ for each Array item. Also beware that we can't rely on the `index` parameter provided in for loop, because that only identifies the position in the Array, and not the actual item itself.
|
|
113
|
+
|
|
114
|
+
|
|
115
|
+
```js
|
|
116
|
+
export default Blits.Component('ForLoop', {
|
|
117
|
+
template: `
|
|
118
|
+
<Element>
|
|
119
|
+
<Element
|
|
120
|
+
:for="(item, index) in $items"
|
|
121
|
+
w="100"
|
|
122
|
+
h="100"
|
|
123
|
+
:color="$item.color"
|
|
124
|
+
:x="$index * 150"
|
|
125
|
+
alpha="$alpha"
|
|
126
|
+
key="$item.id"
|
|
127
|
+
/>
|
|
128
|
+
<!-- ^^ id is the unique field that identifies each array item -->
|
|
129
|
+
</Element>
|
|
130
|
+
`,
|
|
131
|
+
state() {
|
|
132
|
+
return {
|
|
133
|
+
alpha: 0.5,
|
|
134
|
+
items: [{
|
|
135
|
+
id: 1,
|
|
136
|
+
color: 'green'
|
|
137
|
+
}, {
|
|
138
|
+
id: 2,
|
|
139
|
+
color: 'blue'
|
|
140
|
+
}, {
|
|
141
|
+
id: 3,
|
|
142
|
+
color: 'yellow'
|
|
143
|
+
}]
|
|
144
|
+
}
|
|
145
|
+
},
|
|
146
|
+
hooks: {
|
|
147
|
+
ready() {
|
|
148
|
+
let count = 3
|
|
149
|
+
this.$setInterval(() => {
|
|
150
|
+
this.items.push({id: count++, color: randomColor()})
|
|
151
|
+
}, 2000)
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
})
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
In the example above we have added the `key`-attribute in the template. Now whenever we push a new item to the `items`-array, the for-loop will reuse the Elements previously created and only instantiate a new Element for the newly added item.
|
|
158
|
+
|
|
159
|
+
If we would omit the `key`-attribute, then whenever we push a new item to the Array, the for-loop would dispose all the old Elements and create new instances for _each_ item in the array.
|
|
160
|
+
|
|
161
|
+
## Referencing elements in the for loop
|
|
162
|
+
|
|
163
|
+
When you specify a `for`-attribute on an Element or a Component, it will effectively create multiple Elements / Components depending
|
|
164
|
+
on the length of the Array.
|
|
165
|
+
|
|
166
|
+
Generally it's not recommended to access and interact directly with Elements in a template, and that also goes for items in a For loop. But in some cases you may need to, for example to delegate focus to a specific item in the For loop.
|
|
167
|
+
|
|
168
|
+
The `ref`-attribute can be used in combination with the `for`-attribute as well.
|
|
169
|
+
|
|
170
|
+
Setting the _ref_ in a for loop context, can be done by either passing a string (i.e. `myitem`) and as Elements get generated in the for loop, the `index` value will be appended to it (i.e. `myitem0`, `myitem1`, etc.). Alternatively you can make the attribute interpolated and define the value for each item yourself (i.e. `:ref="'item' + $item.id"`).
|
|
171
|
+
|
|
172
|
+
## Using the range attribute
|
|
173
|
+
|
|
174
|
+
Sometimes you may only need to render a portion of an array rather than all the items.
|
|
175
|
+
|
|
176
|
+
To do this you can use the `range` variable to specify a subset of items to render. You should specify a `from` and `to` value (`from` is inclusive, and `to` is exclusive) inside the `range` variable (i.e. `range="{from: 0, to: 2}"`). You can also make the variable reactive, and use moving pointers to dynamically render your items.
|
|
177
|
+
|
|
178
|
+
This works differently to using the `show` directive on the items, as the items will be destroyed once they are outside the range, and created again when they fall back in it.
|
|
179
|
+
|
|
180
|
+
```js
|
|
181
|
+
export default Blits.Component('ForLoop', {
|
|
182
|
+
template: `
|
|
183
|
+
<Element>
|
|
184
|
+
<Element :for="(item, index) in $items" :range="{from: $selected - 1, to: $selected + 2}" w="100" h="100" color="lime" :x="$index * 150" />
|
|
185
|
+
</Element>
|
|
186
|
+
`,
|
|
187
|
+
state() {
|
|
188
|
+
return {
|
|
189
|
+
selected: 0,
|
|
190
|
+
items: ['Item 1', 'Item 2', 'Item 3', 'Item 4', 'Item 5', 'Item 6', 'Item 7']
|
|
191
|
+
}
|
|
192
|
+
},
|
|
193
|
+
input: {
|
|
194
|
+
left() {
|
|
195
|
+
this.selected = Math.max(0, this.selected - 1)
|
|
196
|
+
},
|
|
197
|
+
right() {
|
|
198
|
+
this.selected = Math.min(this.items.length, this.selected + 1)
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
})
|
|
202
|
+
```
|
|
203
|
+
|
|
204
204
|
In the example above, there are 7 items in the array, but we only render the items immediately before and after the selected item at any time.
|