@dxtmisha/wiki 0.24.0 → 0.24.1
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/package.json +1 -1
- package/src/media/functional/en/about.mdx +55 -0
- package/src/media/functional/en/dataStorage.mdx +61 -83
- package/src/media/functional/en/useApiRef.mdx +517 -0
- package/src/media/functional/en/useBroadcastValueRef.mdx +344 -0
- package/src/media/functional/en/useCookieRef.mdx +348 -0
- package/src/media/functional/en/useGeoIntlRef.mdx +288 -0
- package/src/media/functional/en/useHashRef.mdx +302 -0
- package/src/media/functional/en/useLazyRef.mdx +329 -0
- package/src/media/functional/en/useLoadingRef.mdx +159 -0
- package/src/media/functional/en/useSessionRef.mdx +248 -0
- package/src/media/functional/en/useStorageRef.mdx +242 -0
- package/src/media/functional/en/useTranslateRef.mdx +312 -0
- package/src/media/functional/ru/about.mdx +55 -0
- package/src/media/functional/ru/dataStorage.mdx +59 -81
- package/src/media/functional/ru/useApiRef.mdx +517 -0
- package/src/media/functional/ru/useBroadcastValueRef.mdx +344 -0
- package/src/media/functional/ru/useCookieRef.mdx +348 -0
- package/src/media/functional/ru/useGeoIntlRef.mdx +288 -0
- package/src/media/functional/ru/useHashRef.mdx +302 -0
- package/src/media/functional/ru/useLazyRef.mdx +329 -0
- package/src/media/functional/ru/useLoadingRef.mdx +159 -0
- package/src/media/functional/ru/useSessionRef.mdx +248 -0
- package/src/media/functional/ru/useStorageRef.mdx +242 -0
- package/src/media/functional/ru/useTranslateRef.mdx +312 -0
|
@@ -0,0 +1,329 @@
|
|
|
1
|
+
import {Meta} from '@storybook/addon-docs/blocks'
|
|
2
|
+
|
|
3
|
+
<Meta title='@dxtmisha/functional/en/Composables/useLazyRef'/>
|
|
4
|
+
|
|
5
|
+
# Composable useLazyRef
|
|
6
|
+
|
|
7
|
+
Composable for tracking element visibility on screen using Intersection Observer API. Provides efficient lazy loading and rendering of components only when they become visible in the viewport. Perfect for optimizing performance with long lists, images, and heavy components.
|
|
8
|
+
|
|
9
|
+
## Key Features
|
|
10
|
+
|
|
11
|
+
- **Visibility tracking** — automatic detection when element appears in viewport
|
|
12
|
+
- **Intersection Observer API** — uses native browser API for efficient tracking
|
|
13
|
+
- **Automatic cleanup** — removes observers when components unmount
|
|
14
|
+
- **Reactive status** — returns reactive variable with visibility state
|
|
15
|
+
- **Configurable margins** — supports rootMargin for content preloading
|
|
16
|
+
- **Multiple elements** — manages tracking of multiple elements simultaneously
|
|
17
|
+
- **Graceful degradation** — works without IntersectionObserver in older browsers
|
|
18
|
+
|
|
19
|
+
## Function
|
|
20
|
+
|
|
21
|
+
### `useLazyRef`
|
|
22
|
+
|
|
23
|
+
Creates an instance for tracking element visibility on screen.
|
|
24
|
+
|
|
25
|
+
**Parameters:** none
|
|
26
|
+
|
|
27
|
+
**Returns:** object with methods:
|
|
28
|
+
- `intersectionObserver: IntersectionObserver | undefined` — observer instance
|
|
29
|
+
- `addLazyItem: (element: Ref<HTMLElement>) => ShallowRef<boolean>` — add element for tracking
|
|
30
|
+
- `removeLazyItem: (element?: HTMLElement) => void` — remove element from tracking
|
|
31
|
+
- `disconnectLazy: () => void` — disconnect all observers
|
|
32
|
+
|
|
33
|
+
```javascript
|
|
34
|
+
import { useLazyRef } from '@dxtmisha/functional'
|
|
35
|
+
|
|
36
|
+
// Create instance
|
|
37
|
+
const lazy = useLazyRef()
|
|
38
|
+
|
|
39
|
+
// Access methods
|
|
40
|
+
const isVisible = lazy.addLazyItem(elementRef)
|
|
41
|
+
lazy.removeLazyItem(element)
|
|
42
|
+
lazy.disconnectLazy()
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
## Basic Usage
|
|
46
|
+
|
|
47
|
+
### `addLazyItem`
|
|
48
|
+
|
|
49
|
+
Adds element to track its visibility on screen.
|
|
50
|
+
|
|
51
|
+
**Parameters:**
|
|
52
|
+
- `element: Ref<HTMLElement>` — reactive reference to HTML element
|
|
53
|
+
|
|
54
|
+
**Returns:** `ShallowRef<boolean>` — reactive variable with visibility status
|
|
55
|
+
|
|
56
|
+
```javascript
|
|
57
|
+
import { ref } from 'vue'
|
|
58
|
+
import { useLazyRef } from '@dxtmisha/functional'
|
|
59
|
+
|
|
60
|
+
const lazy = useLazyRef()
|
|
61
|
+
const imageRef = ref(null)
|
|
62
|
+
|
|
63
|
+
// Add element for tracking
|
|
64
|
+
const isVisible = lazy.addLazyItem(imageRef)
|
|
65
|
+
|
|
66
|
+
// isVisible.value === true when element is visible
|
|
67
|
+
// isVisible.value === false when element is not visible
|
|
68
|
+
|
|
69
|
+
// In older browsers without IntersectionObserver
|
|
70
|
+
// isVisible.value === true immediately (fallback)
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
### `removeLazyItem`
|
|
74
|
+
|
|
75
|
+
Removes element from tracking and cleans up resources.
|
|
76
|
+
|
|
77
|
+
**Parameters:**
|
|
78
|
+
- `element?: HTMLElement` — HTML element to remove
|
|
79
|
+
|
|
80
|
+
**Returns:** `void`
|
|
81
|
+
|
|
82
|
+
```javascript
|
|
83
|
+
const element = document.getElementById('my-element')
|
|
84
|
+
|
|
85
|
+
// Remove element from tracking
|
|
86
|
+
lazy.removeLazyItem(element)
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
### `disconnectLazy`
|
|
90
|
+
|
|
91
|
+
Disconnects all observers and stops tracking all elements.
|
|
92
|
+
|
|
93
|
+
**Parameters:** none
|
|
94
|
+
|
|
95
|
+
**Returns:** `void`
|
|
96
|
+
|
|
97
|
+
```javascript
|
|
98
|
+
// Complete cleanup on unmount
|
|
99
|
+
onBeforeUnmount(() => {
|
|
100
|
+
lazy.disconnectLazy()
|
|
101
|
+
})
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
## Usage in Components
|
|
105
|
+
|
|
106
|
+
### Lazy Image Loading
|
|
107
|
+
|
|
108
|
+
```javascript
|
|
109
|
+
import { ref, watch } from 'vue'
|
|
110
|
+
import { useLazyRef } from '@dxtmisha/functional'
|
|
111
|
+
|
|
112
|
+
export default {
|
|
113
|
+
setup() {
|
|
114
|
+
const lazy = useLazyRef()
|
|
115
|
+
const imageRef = ref(null)
|
|
116
|
+
const imageLoaded = ref(false)
|
|
117
|
+
|
|
118
|
+
const isVisible = lazy.addLazyItem(imageRef)
|
|
119
|
+
|
|
120
|
+
watch(isVisible, (visible) => {
|
|
121
|
+
if (visible && !imageLoaded.value) {
|
|
122
|
+
imageLoaded.value = true
|
|
123
|
+
}
|
|
124
|
+
})
|
|
125
|
+
|
|
126
|
+
return { imageRef, imageLoaded }
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
// Template:
|
|
131
|
+
// <div ref="imageRef">
|
|
132
|
+
// <img v-if="imageLoaded" src="/path/to/image.jpg" />
|
|
133
|
+
// <div v-else class="placeholder">Loading...</div>
|
|
134
|
+
// </div>
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
### Infinite Scroll
|
|
138
|
+
|
|
139
|
+
```javascript
|
|
140
|
+
import { ref, watch } from 'vue'
|
|
141
|
+
import { useLazyRef } from '@dxtmisha/functional'
|
|
142
|
+
|
|
143
|
+
export default {
|
|
144
|
+
setup() {
|
|
145
|
+
const lazy = useLazyRef()
|
|
146
|
+
const items = ref([1, 2, 3, 4, 5])
|
|
147
|
+
const sentinelRef = ref(null)
|
|
148
|
+
const loading = ref(false)
|
|
149
|
+
|
|
150
|
+
const isSentinelVisible = lazy.addLazyItem(sentinelRef)
|
|
151
|
+
|
|
152
|
+
watch(isSentinelVisible, async (visible) => {
|
|
153
|
+
if (visible && !loading.value) {
|
|
154
|
+
loading.value = true
|
|
155
|
+
await new Promise(resolve => setTimeout(resolve, 1000))
|
|
156
|
+
items.value.push(items.value.length + 1)
|
|
157
|
+
loading.value = false
|
|
158
|
+
}
|
|
159
|
+
})
|
|
160
|
+
|
|
161
|
+
return { items, sentinelRef, loading }
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
// Template:
|
|
166
|
+
// <div>
|
|
167
|
+
// <div v-for="item in items" :key="item">Item {{ item }}</div>
|
|
168
|
+
// <div ref="sentinelRef" class="sentinel">
|
|
169
|
+
// <div v-if="loading">Loading...</div>
|
|
170
|
+
// </div>
|
|
171
|
+
// </div>
|
|
172
|
+
```
|
|
173
|
+
|
|
174
|
+
## Advanced Usage
|
|
175
|
+
|
|
176
|
+
### Tracking Multiple Elements
|
|
177
|
+
|
|
178
|
+
```javascript
|
|
179
|
+
import { ref, onBeforeUnmount } from 'vue'
|
|
180
|
+
import { useLazyRef } from '@dxtmisha/functional'
|
|
181
|
+
|
|
182
|
+
export default {
|
|
183
|
+
setup() {
|
|
184
|
+
const lazy = useLazyRef()
|
|
185
|
+
const items = ref([
|
|
186
|
+
{ id: 1, ref: ref(null), visible: null },
|
|
187
|
+
{ id: 2, ref: ref(null), visible: null },
|
|
188
|
+
{ id: 3, ref: ref(null), visible: null }
|
|
189
|
+
])
|
|
190
|
+
|
|
191
|
+
// Add each element for tracking
|
|
192
|
+
items.value.forEach(item => {
|
|
193
|
+
item.visible = lazy.addLazyItem(item.ref)
|
|
194
|
+
})
|
|
195
|
+
|
|
196
|
+
onBeforeUnmount(() => {
|
|
197
|
+
lazy.disconnectLazy()
|
|
198
|
+
})
|
|
199
|
+
|
|
200
|
+
return { items }
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
// Template:
|
|
205
|
+
// <div v-for="item in items" :key="item.id">
|
|
206
|
+
// <div :ref="item.ref">
|
|
207
|
+
// <div v-if="item.visible.value">
|
|
208
|
+
// Content for item {{ item.id }}
|
|
209
|
+
// </div>
|
|
210
|
+
// <div v-else class="placeholder">...</div>
|
|
211
|
+
// </div>
|
|
212
|
+
// </div>
|
|
213
|
+
```
|
|
214
|
+
|
|
215
|
+
### Conditional Element Removal
|
|
216
|
+
|
|
217
|
+
```javascript
|
|
218
|
+
import { ref, watch } from 'vue'
|
|
219
|
+
import { useLazyRef } from '@dxtmisha/functional'
|
|
220
|
+
|
|
221
|
+
export default {
|
|
222
|
+
setup() {
|
|
223
|
+
const lazy = useLazyRef()
|
|
224
|
+
const elementRef = ref(null)
|
|
225
|
+
const showElement = ref(true)
|
|
226
|
+
|
|
227
|
+
const isVisible = lazy.addLazyItem(elementRef)
|
|
228
|
+
|
|
229
|
+
// Remove from tracking when hiding
|
|
230
|
+
watch(showElement, (show) => {
|
|
231
|
+
if (!show && elementRef.value) {
|
|
232
|
+
lazy.removeLazyItem(elementRef.value)
|
|
233
|
+
}
|
|
234
|
+
})
|
|
235
|
+
|
|
236
|
+
return {
|
|
237
|
+
elementRef,
|
|
238
|
+
showElement,
|
|
239
|
+
isVisible
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
```
|
|
244
|
+
|
|
245
|
+
### Preloading with rootMargin
|
|
246
|
+
|
|
247
|
+
```javascript
|
|
248
|
+
// Default rootMargin: '128px 0px'
|
|
249
|
+
// Elements start tracking 128px before entering viewport
|
|
250
|
+
|
|
251
|
+
const lazy = useLazyRef()
|
|
252
|
+
const imageRef = ref(null)
|
|
253
|
+
|
|
254
|
+
// Image will start loading 128px before visibility
|
|
255
|
+
const isVisible = lazy.addLazyItem(imageRef)
|
|
256
|
+
|
|
257
|
+
console.log('rootMargin provides smooth preloading')
|
|
258
|
+
```
|
|
259
|
+
|
|
260
|
+
## Handling Missing IntersectionObserver
|
|
261
|
+
|
|
262
|
+
```javascript
|
|
263
|
+
import { useLazyRef } from '@dxtmisha/functional'
|
|
264
|
+
|
|
265
|
+
const lazy = useLazyRef()
|
|
266
|
+
|
|
267
|
+
// Check API availability
|
|
268
|
+
if (lazy.intersectionObserver) {
|
|
269
|
+
console.log('IntersectionObserver available')
|
|
270
|
+
// Use lazy loading
|
|
271
|
+
} else {
|
|
272
|
+
console.log('IntersectionObserver not supported')
|
|
273
|
+
// isVisible will always be true (fallback)
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
const elementRef = ref(null)
|
|
277
|
+
const isVisible = lazy.addLazyItem(elementRef)
|
|
278
|
+
|
|
279
|
+
// In older browsers isVisible.value === true immediately
|
|
280
|
+
// Content loads immediately (graceful degradation)
|
|
281
|
+
```
|
|
282
|
+
|
|
283
|
+
## Performance Optimization
|
|
284
|
+
|
|
285
|
+
### Lazy Loading in Lists
|
|
286
|
+
|
|
287
|
+
```javascript
|
|
288
|
+
import { ref } from 'vue'
|
|
289
|
+
import { useLazyRef } from '@dxtmisha/functional'
|
|
290
|
+
|
|
291
|
+
export default {
|
|
292
|
+
setup() {
|
|
293
|
+
const lazy = useLazyRef()
|
|
294
|
+
const products = ref([
|
|
295
|
+
{ id: 1, name: 'Product 1', image: '/img1.jpg' },
|
|
296
|
+
{ id: 2, name: 'Product 2', image: '/img2.jpg' },
|
|
297
|
+
// ... 100 more products
|
|
298
|
+
])
|
|
299
|
+
|
|
300
|
+
// Create refs for each product
|
|
301
|
+
const productRefs = ref(products.value.map(() => ({
|
|
302
|
+
element: ref(null),
|
|
303
|
+
visible: null
|
|
304
|
+
})))
|
|
305
|
+
|
|
306
|
+
// Track visibility of each product
|
|
307
|
+
productRefs.value.forEach(item => {
|
|
308
|
+
item.visible = lazy.addLazyItem(item.element)
|
|
309
|
+
})
|
|
310
|
+
|
|
311
|
+
return {
|
|
312
|
+
products,
|
|
313
|
+
productRefs
|
|
314
|
+
}
|
|
315
|
+
}
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
// Template:
|
|
319
|
+
// <div v-for="(product, index) in products" :key="product.id">
|
|
320
|
+
// <div :ref="productRefs[index].element">
|
|
321
|
+
// <template v-if="productRefs[index].visible.value">
|
|
322
|
+
// <img :src="product.image" :alt="product.name" />
|
|
323
|
+
// <h3>{{ product.name }}</h3>
|
|
324
|
+
// </template>
|
|
325
|
+
// <div v-else class="product-skeleton">Loading...</div>
|
|
326
|
+
// </div>
|
|
327
|
+
// </div>
|
|
328
|
+
```
|
|
329
|
+
|
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
import {Meta} from '@storybook/addon-docs/blocks'
|
|
2
|
+
|
|
3
|
+
<Meta title='@dxtmisha/functional/en/Composables/useLoadingRef'/>
|
|
4
|
+
|
|
5
|
+
# Composable useLoadingRef
|
|
6
|
+
|
|
7
|
+
Composable for tracking global application loading status. Provides a reactive variable that automatically updates when loading state changes through the Loading class. Perfect for displaying global loading indicators, blocking UI during async operations, and coordinating multiple loading processes.
|
|
8
|
+
|
|
9
|
+
## Key Features
|
|
10
|
+
|
|
11
|
+
- **Global loading status** — single place to manage loading state for entire application
|
|
12
|
+
- **Reactivity** — automatic updates when loading status changes
|
|
13
|
+
- **Loading counter** — supports multiple concurrent loading operations
|
|
14
|
+
- **Automatic subscription** — composable automatically subscribes to Loading events
|
|
15
|
+
- **Type safety** — full TypeScript support
|
|
16
|
+
- **Easy integration** — easily integrates with any Vue components
|
|
17
|
+
- **Centralized control** — all components use single source of truth
|
|
18
|
+
|
|
19
|
+
## Function
|
|
20
|
+
|
|
21
|
+
### `useLoadingRef`
|
|
22
|
+
|
|
23
|
+
Creates a reactive variable tracking global loading status.
|
|
24
|
+
|
|
25
|
+
**Parameters:** none
|
|
26
|
+
|
|
27
|
+
**Returns:** `ShallowRef<boolean>` — reactive variable with loading status
|
|
28
|
+
|
|
29
|
+
```javascript
|
|
30
|
+
import { useLoadingRef } from '@dxtmisha/functional'
|
|
31
|
+
|
|
32
|
+
// Create reactive variable
|
|
33
|
+
const isLoading = useLoadingRef()
|
|
34
|
+
|
|
35
|
+
// isLoading.value === true when there are active loads
|
|
36
|
+
// isLoading.value === false when no loads
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
## Basic Usage
|
|
40
|
+
|
|
41
|
+
### Basic Loading Tracking
|
|
42
|
+
|
|
43
|
+
```javascript
|
|
44
|
+
import { useLoadingRef } from '@dxtmisha/functional'
|
|
45
|
+
import { Loading } from '@dxtmisha/functional'
|
|
46
|
+
|
|
47
|
+
// In component
|
|
48
|
+
const isLoading = useLoadingRef()
|
|
49
|
+
|
|
50
|
+
// Show loader
|
|
51
|
+
Loading.show()
|
|
52
|
+
console.log(isLoading.value) // true
|
|
53
|
+
|
|
54
|
+
// Hide loader
|
|
55
|
+
Loading.hide()
|
|
56
|
+
console.log(isLoading.value) // false
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
### Working with Multiple Loads
|
|
60
|
+
|
|
61
|
+
```javascript
|
|
62
|
+
import { useLoadingRef, Loading } from '@dxtmisha/functional'
|
|
63
|
+
|
|
64
|
+
const isLoading = useLoadingRef()
|
|
65
|
+
|
|
66
|
+
// First loading operation
|
|
67
|
+
Loading.show()
|
|
68
|
+
console.log(isLoading.value) // true (counter = 1)
|
|
69
|
+
|
|
70
|
+
// Second loading operation
|
|
71
|
+
Loading.show()
|
|
72
|
+
console.log(isLoading.value) // true (counter = 2)
|
|
73
|
+
|
|
74
|
+
// Complete first operation
|
|
75
|
+
Loading.hide()
|
|
76
|
+
console.log(isLoading.value) // true (counter = 1)
|
|
77
|
+
|
|
78
|
+
// Complete second operation
|
|
79
|
+
Loading.hide()
|
|
80
|
+
console.log(isLoading.value) // false (counter = 0)
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
## Usage in Components
|
|
84
|
+
|
|
85
|
+
### Global Loading Indicator
|
|
86
|
+
|
|
87
|
+
```javascript
|
|
88
|
+
import { useLoadingRef } from '@dxtmisha/functional'
|
|
89
|
+
|
|
90
|
+
export default {
|
|
91
|
+
setup() {
|
|
92
|
+
const isLoading = useLoadingRef()
|
|
93
|
+
|
|
94
|
+
return { isLoading }
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
// Template:
|
|
99
|
+
// <div v-if="isLoading" class="global-loader">
|
|
100
|
+
// <div class="spinner"></div>
|
|
101
|
+
// <p>Loading...</p>
|
|
102
|
+
// </div>
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
### Integration with API Requests
|
|
106
|
+
|
|
107
|
+
```javascript
|
|
108
|
+
import { Loading } from '@dxtmisha/functional'
|
|
109
|
+
import { useLoadingRef } from '@dxtmisha/functional'
|
|
110
|
+
|
|
111
|
+
export default {
|
|
112
|
+
setup() {
|
|
113
|
+
const isLoading = useLoadingRef()
|
|
114
|
+
|
|
115
|
+
const fetchUserData = async () => {
|
|
116
|
+
Loading.show()
|
|
117
|
+
|
|
118
|
+
try {
|
|
119
|
+
const response = await fetch('/api/user')
|
|
120
|
+
const data = await response.json()
|
|
121
|
+
} catch (error) {
|
|
122
|
+
console.error('Error:', error)
|
|
123
|
+
} finally {
|
|
124
|
+
Loading.hide()
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
return { isLoading, fetchUserData }
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
// Template:
|
|
133
|
+
// <button @click="fetchUserData" :disabled="isLoading">
|
|
134
|
+
// Load Data
|
|
135
|
+
// </button>
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
## Integration with Loading Class
|
|
139
|
+
|
|
140
|
+
Composable is tightly integrated with `Loading` class:
|
|
141
|
+
|
|
142
|
+
```javascript
|
|
143
|
+
import { Loading } from '@dxtmisha/functional'
|
|
144
|
+
import { useLoadingRef } from '@dxtmisha/functional'
|
|
145
|
+
|
|
146
|
+
// In component A
|
|
147
|
+
const isLoading = useLoadingRef()
|
|
148
|
+
|
|
149
|
+
// Anywhere in application
|
|
150
|
+
Loading.show() // isLoading.value automatically becomes true
|
|
151
|
+
|
|
152
|
+
// In another component B
|
|
153
|
+
Loading.hide() // isLoading.value in component A automatically updates
|
|
154
|
+
|
|
155
|
+
// Check status
|
|
156
|
+
console.log(Loading.is()) // true/false
|
|
157
|
+
|
|
158
|
+
// All components with useLoadingRef() will be synchronized
|
|
159
|
+
```
|