Skip to content

Commit a7c49f6

Browse files
committed
fix: src and loading in lazy loaded images returns right value immediately
1 parent 8e83127 commit a7c49f6

File tree

2 files changed

+56
-8
lines changed

2 files changed

+56
-8
lines changed

.changeset/friendly-crews-sin.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'svelte': patch
3+
---
4+
5+
fix: `src` and `loading` in lazy loaded images returns right value immediately

packages/svelte/src/internal/client/dom/elements/attributes.js

Lines changed: 51 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,19 @@
11
import { DEV } from 'esm-env';
2-
import { hydrating } from '../hydration.js';
3-
import { get_descriptors, get_prototype_of } from '../../../shared/utils.js';
4-
import { create_event, delegate } from './events.js';
5-
import { add_form_reset_listener, autofocus } from './misc.js';
6-
import * as w from '../../warnings.js';
7-
import { LOADING_ATTR_SYMBOL } from '../../constants.js';
8-
import { queue_idle_task } from '../task.js';
92
import { is_capture_event, is_delegated, normalize_attribute } from '../../../../utils.js';
3+
import { clsx } from '../../../shared/attributes.js';
4+
import { define_property, get_descriptors, get_prototype_of } from '../../../shared/utils.js';
5+
import { LOADING_ATTR_SYMBOL } from '../../constants.js';
106
import {
117
active_effect,
128
active_reaction,
139
set_active_effect,
1410
set_active_reaction
1511
} from '../../runtime.js';
16-
import { clsx } from '../../../shared/attributes.js';
12+
import * as w from '../../warnings.js';
13+
import { hydrating } from '../hydration.js';
14+
import { queue_idle_task } from '../task.js';
15+
import { create_event, delegate } from './events.js';
16+
import { add_form_reset_listener, autofocus } from './misc.js';
1717

1818
/**
1919
* The value/checked attribute in the template actually corresponds to the defaultValue property, so we need
@@ -515,11 +515,54 @@ export function handle_lazy_img(element) {
515515
// templates.
516516
if (!hydrating && element.loading === 'lazy') {
517517
var src = element.src;
518+
var loading = element.loading;
518519
// @ts-expect-error
519520
element[LOADING_ATTR_SYMBOL] = null;
520521
element.loading = 'eager';
521522
element.removeAttribute('src');
523+
524+
// since we are removing src before the first animation frame if someone
525+
// access src or loading on mount or in an action they will have the wrong value
526+
// so we define those two properties so that if accessed through JS it will
527+
// return the correct value. Since we can't undo this we also mimic the behavior
528+
// of setting the attribute in the setter
529+
define_property(element, 'src', {
530+
get() {
531+
return src;
532+
},
533+
set(new_src) {
534+
element.setAttribute('src', new_src);
535+
src = new_src;
536+
},
537+
configurable: true,
538+
enumerable: true
539+
});
540+
define_property(element, 'loading', {
541+
get() {
542+
return loading;
543+
},
544+
set(new_loading) {
545+
element.setAttribute('loading', new_loading);
546+
loading = new_loading;
547+
},
548+
configurable: true,
549+
enumerable: true
550+
});
551+
552+
// same story as above with getAttribute...we fake it until we restore the
553+
// old `setAttribute` value after the first animation frame
554+
const old_get_attribute = element.getAttribute;
555+
element.getAttribute = (name) => {
556+
if (name === 'src') {
557+
return src;
558+
}
559+
if (name === 'loading') {
560+
return loading;
561+
}
562+
return old_get_attribute.call(element, name);
563+
};
522564
requestAnimationFrame(() => {
565+
element.getAttribute = old_get_attribute;
523566
// @ts-expect-error
524567
if (element[LOADING_ATTR_SYMBOL] !== 'eager') {
525568
element.loading = 'lazy';

0 commit comments

Comments
 (0)