Skip to content

Commit 6b94dc5

Browse files
feat(nuxt): sources for <picture> element
1 parent 8acfc8a commit 6b94dc5

File tree

3 files changed

+81
-16
lines changed

3 files changed

+81
-16
lines changed

docs/integrations/nuxt.md

Lines changed: 40 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22

33
unlazy is not only framework-agnostic, but also provides a Nuxt module that you can use in your Nuxt application.
44

5+
The auto-imported `UnLazyImage` component is a drop-in replacement for the native `<img>` element and `<picture>` element respectively if you provide the `sources` prop.
6+
57
## Installation
68

79
Install the `@unlazy/nuxt` package using your favorite package manager:
@@ -91,19 +93,19 @@ The `UnLazyImage` component accepts the following props:
9193

9294
## Examples
9395

94-
```html
95-
<!-- Inlined placeholder image as data URI -->
96+
::: tip
97+
In every `srcSet` example, the `sizes` attribute is automatically calculated given the `auto-sizes` prop.
98+
:::
99+
100+
### Inlined placeholder image
101+
102+
```html [Inlined placeholder image]
96103
<UnLazyImage
97104
placeholder-src="data:image/svg+xml, ..."
98-
src-set="image-320w.jpg 320w, image-640w.jpg 640w"
99-
auto-sizes
105+
src="/foo/bar.jpg"
100106
/>
101107
```
102108

103-
::: tip
104-
In every `srcSet` example, the `sizes` attribute is automatically calculated given the `auto-sizes` prop.
105-
:::
106-
107109
### BlurHash
108110

109111
::: code-group
@@ -151,3 +153,33 @@ In every `srcSet` example, the `sizes` attribute is automatically calculated giv
151153
/>
152154
```
153155
:::
156+
157+
### Multiple image sources
158+
159+
In this example, we're using the `UnLazyImage` component with an `exampleImgSrc` for the default image source, and an array of objects named `exampleSources` for the `sources` prop. Each object in the array includes a `type` and a `srcSet` property. In addition, the `blurhash` attribute is set to a predefined BlurHash string, and the `autoSizes` attribute is set to `true`, which will enable automatic calculation of the `sizes` attribute.
160+
161+
```vue
162+
<script setup lang="ts">
163+
import UnlazyImg from 'unlazy/UnlazyImg.vue'
164+
165+
const exampleImgSrc = '/images/foo.jpg'
166+
const exampleSources = [
167+
{
168+
type: 'image/webp',
169+
srcSet: '/images/foo.webp 1x, /images/foo@2x.webp 2x'
170+
},
171+
{
172+
type: 'image/jpeg',
173+
srcSet: '/images/foo.jpg 1x, /images/foo@2x.jpg 2x'
174+
}
175+
]
176+
</script>
177+
178+
<template>
179+
<UnLazyImage
180+
:src="exampleImgSrc"
181+
:sources="exampleSources"
182+
blurhash="LEHV6nWB2yk8pyo0adR*.7kCMdnj"
183+
auto-sizes
184+
/>
185+
</template>

packages/nuxt/playground/app.vue

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -27,8 +27,7 @@ function loadImage() {
2727
<PlaygroundDivider><strong>SSR</strong>-decoded BlurHash</PlaygroundDivider>
2828
<UnLazyImage
2929
:blurhash="blurhash"
30-
:blurhash-ratio="2"
31-
data-srcset="image-320w.jpg 320w, image-640w.jpg 640w"
30+
src-set="image-320w.jpg 320w, image-640w.jpg 640w"
3231
width="640"
3332
height="320"
3433
/>
@@ -41,8 +40,7 @@ function loadImage() {
4140
<UnLazyImage
4241
:ssr="false"
4342
:blurhash="blurhash"
44-
:blurhash-ratio="2"
45-
data-srcset="image-320w.jpg 320w, image-640w.jpg 640w"
43+
src-set="image-320w.jpg 320w, image-640w.jpg 640w"
4644
width="640"
4745
height="320"
4846
/>
@@ -57,7 +55,7 @@ function loadImage() {
5755
<PlaygroundDivider><strong>SSR</strong>-decoded ThumbHash</PlaygroundDivider>
5856
<UnLazyImage
5957
:thumbhash="thumbhash"
60-
data-src="/images/sunrise-evan-wallace.jpg"
58+
src="/images/sunrise-evan-wallace.jpg"
6159
width="480"
6260
height="640"
6361
style="aspect-ratio: 3/4;"
@@ -72,7 +70,7 @@ function loadImage() {
7270
<UnLazyImage
7371
:ssr="false"
7472
:thumbhash="thumbhash"
75-
data-src="/images/sunrise-evan-wallace.jpg"
73+
src="/images/sunrise-evan-wallace.jpg"
7674
width="480"
7775
height="640"
7876
style="aspect-ratio: 3/4;"
@@ -86,9 +84,10 @@ function loadImage() {
8684
<UnLazyImage
8785
thumbhash="HBkSHYSIeHiPiHh8eJd4eTN0EEQG"
8886
:lazy-load="shouldLoadImage"
89-
data-src="/images/fall-evan-wallace.jpg"
87+
src="/images/fall-evan-wallace.jpg"
9088
width="480"
9189
height="640"
90+
style="aspect-ratio: 3/2;"
9291
@click="loadImage"
9392
/>
9493
<p class="text-sm text-gray-500">

packages/nuxt/src/runtime/components/UnLazyImage.vue

Lines changed: 35 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,16 @@ import { onBeforeUnmount, onMounted, ref, useRuntimeConfig, watchEffect } from '
77
88
const props = withDefaults(
99
defineProps<{
10+
/** Image source URL to be lazy-loaded. */
1011
src?: ImgHTMLAttributes['src']
12+
/** Image source set to be lazy-loaded. */
13+
srcSet?: ImgHTMLAttributes['srcset']
14+
/** Image source URLs for different resolutions. This will render the `<picture>` element instead of `<img>`. */
15+
sources?: {
16+
type: string
17+
srcSet: string
18+
sizes?: string
19+
}[]
1120
/**
1221
* A flag to indicate whether the sizes attribute should be automatically calculated.
1322
* @default false
@@ -17,6 +26,8 @@ const props = withDefaults(
1726
blurhash?: string
1827
/** A ThumbHash string representing the blurry placeholder image. */
1928
thumbhash?: string
29+
/** Optional image source URL for a custom placeholder image. Will be ignored if a BlurHash or ThumbHash is provided. */
30+
placeholderSrc?: string
2031
/** The size of the longer edge (width or height) of the BlurHash image to be decoded, depending on the aspect ratio. This option only applies when the `blurhash` prop is used. */
2132
placeholderSize?: number
2233
/** Aspect ratio (width / height) of the decoded BlurHash image. Only applies to SSR-decoded placeholder images from a BlurHash string. */
@@ -31,9 +42,12 @@ const props = withDefaults(
3142
}>(),
3243
{
3344
src: undefined,
45+
srcSet: undefined,
46+
sources: undefined,
3447
autoSizes: false,
3548
blurhash: undefined,
3649
thumbhash: undefined,
50+
placeholderSrc: undefined,
3751
placeholderSize: undefined,
3852
placeholderRatio: undefined,
3953
lazyLoad: true,
@@ -85,9 +99,29 @@ onBeforeUnmount(() => {
8599

86100
<template>
87101
<img
102+
v-if="!props.sources?.length"
88103
ref="target"
89-
:src="pngPlaceholder || src"
104+
:src="pngPlaceholder || placeholderSrc"
105+
:data-src="src"
106+
:data-srcset="srcSet"
90107
:data-sizes="autoSizes ? 'auto' : undefined"
91108
loading="lazy"
92109
>
110+
<picture v-else>
111+
<source
112+
v-for="(source, index) in props.sources"
113+
:key="index"
114+
:type="source.type"
115+
:data-srcset="source.srcSet"
116+
:data-sizes="source.sizes"
117+
>
118+
<img
119+
ref="target"
120+
:src="pngPlaceholder || placeholderSrc"
121+
:data-src="src"
122+
:data-srcset="srcSet"
123+
:data-sizes="autoSizes ? 'auto' : undefined"
124+
loading="lazy"
125+
>
126+
</picture>
93127
</template>

0 commit comments

Comments
 (0)