|
3 | 3 |
|
4 | 4 | import type { BoxProps } from '@/components/Box/util' |
5 | 5 | import type { Component } from 'vue' |
6 | | - import type { Status } from './util' |
7 | 6 |
|
8 | | - import { customRef } from '@/ref/custom-ref' |
9 | | - import { useRect } from '@/ref/use-rect' |
10 | | - import { clean } from '@/utils/object/data' |
11 | | - import { assert } from '@/utils/object/is' |
12 | | - import { onUnmounted, ref, shallowReactive, watch } from 'vue' |
13 | | - import { getData } from './util' |
| 7 | + import { useFetch } from '@/ref/use-fetch' |
| 8 | + import { ref, watch } from 'vue' |
| 9 | + import { getSrc } from './util' |
14 | 10 |
|
| 11 | + import Box from '../Box/box.vue' |
15 | 12 | import ViewObserver from '../Misc/view-observer.vue' |
16 | 13 | import DefaultLoader from './default-loader.vue' |
17 | | - import Box from '../Box/box.vue' |
18 | 14 |
|
19 | 15 | interface BlockImageProps extends /* @vue-ignore */ BoxProps { |
20 | 16 | src?: string |
|
29 | 25 | loader?: Component |
30 | 26 | } |
31 | 27 |
|
32 | | - const [root, setRoot] = customRef<HTMLElement>() |
33 | | - const rect = useRect(root) |
34 | | -
|
35 | 28 | const props = withDefaults(defineProps<BlockImageProps>(), { |
36 | 29 | fit: 'cover', |
37 | 30 | position: 'center', |
38 | 31 | cover: false, |
39 | 32 | loader: DefaultLoader |
40 | 33 | }) |
41 | 34 |
|
42 | | - const image = ref<string>('') |
43 | | - const status = shallowReactive<Status>({ |
44 | | - progress: 0, |
45 | | - error: false, |
46 | | - visible: false |
47 | | - }) |
48 | | -
|
49 | | - function resolve() { |
50 | | - assert(rect.ready, 'rect must be ready') |
51 | | -
|
52 | | - getData( |
53 | | - { |
54 | | - src: props.src, |
55 | | - width: props.width || rect.width, |
56 | | - height: props.height || rect.height |
57 | | - }, |
58 | | - image, |
59 | | - status |
60 | | - ) |
61 | | - } |
| 35 | + const visible = ref(false) |
| 36 | + const fetch = useFetch(() => getSrc(props), 'url-blob', { init: false }) |
62 | 37 |
|
63 | 38 | watch( |
64 | | - () => rect.ready && status.visible, |
| 39 | + visible, |
65 | 40 | (visible) => { |
66 | | - if (!visible || !props.lazy) return |
67 | | - if (status.progress || status.error || image.value) return |
68 | | - resolve() |
69 | | - } |
70 | | - ) |
71 | | -
|
72 | | - watch(() => props.src, resolve) |
73 | | - watch( |
74 | | - () => rect.ready, |
75 | | - () => !props.lazy && resolve() |
| 41 | + if (fetch.ready || fetch.loading || fetch.error) return |
| 42 | + if (!props.lazy || visible) fetch.refetch() |
| 43 | + }, |
| 44 | + { immediate: true } |
76 | 45 | ) |
77 | 46 |
|
78 | | - onUnmounted(() => clean(image.value)) |
79 | 47 | defineOptions({ name: 'MdBlockImage' }) |
80 | 48 | </script> |
81 | 49 |
|
|
84 | 52 | :as="Box" |
85 | 53 | offset="50" |
86 | 54 | class="md-block-image md-image" |
87 | | - :ref="setRoot" |
88 | | - :loading="!image || undefined" |
89 | | - :error="status.error || undefined" |
90 | | - @viewchange="status.visible = $event" |
| 55 | + :loading="fetch.loading || undefined" |
| 56 | + :error="fetch.error || undefined" |
| 57 | + v-model="visible" |
91 | 58 | > |
92 | 59 | <div class="md-loader"> |
93 | 60 | <component |
94 | 61 | :is="loader" |
95 | | - :error="status.error" |
96 | | - :progress="status.progress" |
97 | | - :ready="!!image" |
98 | | - @retry="resolve" |
| 62 | + :error="fetch.error" |
| 63 | + :progress="fetch.progress" |
| 64 | + :ready="fetch.ready" |
| 65 | + @retry="fetch.refetch" |
99 | 66 | /> |
100 | 67 | </div> |
101 | 68 | <img |
102 | 69 | class="md-image-element" |
103 | | - v-if="!status.error" |
104 | | - :src="image" |
| 70 | + v-if="!fetch.error" |
| 71 | + :src="fetch.data" |
105 | 72 | :alt |
106 | 73 | :width |
107 | 74 | :height |
|
0 commit comments