未验证 提交 07adc8ef 编写于 作者: S Steven 提交者: GitHub

Change Image component lazy=true to loading=lazy (#18138)

This PR updates the `<Image>` component to follow the same property naming as native `<img>`.

https://developer.mozilla.org/en-US/docs/Web/HTML/Element/Img#attr-loading

This currently allows two values,`loading=lazy` and `loading=eager`, but there might be new values added in a future spec.

cc @atcastle 
上级 fe4d16c7
import React, { ReactElement, useEffect, useRef } from 'react'
import Head from '../next-server/lib/head'
const VALID_LOADING_VALUES = ['lazy', 'eager', undefined] as const
type LoadingValue = typeof VALID_LOADING_VALUES[number]
const loaders = new Map<LoaderKey, (props: LoaderProps) => string>([
['imgix', imgixLoader],
['cloudinary', cloudinaryLoader],
......@@ -18,12 +21,12 @@ type ImageData = {
type ImageProps = Omit<
JSX.IntrinsicElements['img'],
'src' | 'srcSet' | 'ref' | 'width' | 'height'
'src' | 'srcSet' | 'ref' | 'width' | 'height' | 'loading'
> & {
src: string
quality?: string
priority?: boolean
lazy?: boolean
loading?: LoadingValue
unoptimized?: boolean
} & (
| { width: number; height: number; unsized?: false }
......@@ -142,7 +145,7 @@ export default function Image({
sizes,
unoptimized = false,
priority = false,
lazy,
loading,
className,
quality,
width,
......@@ -152,17 +155,23 @@ export default function Image({
}: ImageProps) {
const thisEl = useRef<HTMLImageElement>(null)
// Sanity Checks:
// If priority and lazy are present, log an error and use priority only.
if (priority && lazy) {
if (process.env.NODE_ENV !== 'production') {
if (process.env.NODE_ENV !== 'production') {
if (!VALID_LOADING_VALUES.includes(loading)) {
throw new Error(
`Image with src "${src}" has invalid "loading" property. Provided "${loading}" should be one of ${VALID_LOADING_VALUES.map(
String
).join(',')}.`
)
}
if (priority && loading === 'lazy') {
throw new Error(
`Image with src "${src}" has both "priority" and "lazy" properties. Only one should be used.`
`Image with src "${src}" has both "priority" and "loading=lazy" properties. Only one should be used.`
)
}
}
if (!priority && typeof lazy === 'undefined') {
let lazy = loading === 'lazy'
if (!priority && typeof loading === 'undefined') {
lazy = true
}
......
......@@ -9,7 +9,7 @@ const ClientSide = () => {
<Image
id="basic-image"
src="foo.jpg"
lazy={false}
loading="eager"
width={300}
height={400}
quality={60}
......@@ -18,7 +18,7 @@ const ClientSide = () => {
id="attribute-test"
data-demo="demo-value"
src="bar.jpg"
lazy={false}
loading="eager"
width={300}
height={400}
/>
......@@ -27,7 +27,7 @@ const ClientSide = () => {
data-demo="demo-value"
host="secondary"
src="foo2.jpg"
lazy={false}
loading="eager"
width={300}
height={400}
/>
......@@ -35,7 +35,7 @@ const ClientSide = () => {
id="unoptimized-image"
unoptimized
src="https://arbitraryurl.com/foo.jpg"
lazy={false}
loading="eager"
width={300}
height={400}
/>
......
......@@ -9,7 +9,7 @@ const Page = () => {
<Image
id="basic-image"
src="foo.jpg"
lazy={false}
loading="eager"
width={300}
height={400}
quality={60}
......@@ -18,7 +18,7 @@ const Page = () => {
id="attribute-test"
data-demo="demo-value"
src="bar.jpg"
lazy={false}
loading="eager"
width={300}
height={400}
/>
......@@ -27,7 +27,7 @@ const Page = () => {
data-demo="demo-value"
host="secondary"
src="foo2.jpg"
lazy={false}
loading="eager"
width={300}
height={400}
/>
......@@ -35,7 +35,7 @@ const Page = () => {
id="unoptimized-image"
unoptimized
src="https://arbitraryurl.com/foo.jpg"
lazy={false}
loading="eager"
width={300}
height={400}
/>
......
......@@ -5,12 +5,18 @@ const Lazy = () => {
return (
<div>
<p id="stubtext">This is a page with lazy-loaded images</p>
<Image id="lazy-top" src="foo1.jpg" height={400} width={300} lazy></Image>
<Image
id="lazy-top"
src="foo1.jpg"
height={400}
width={300}
loading="lazy"
></Image>
<div style={{ height: '2000px' }}></div>
<Image
id="lazy-mid"
src="foo2.jpg"
lazy
loading="lazy"
height={400}
width={300}
className="exampleclass"
......@@ -22,7 +28,22 @@ const Lazy = () => {
height={400}
width={300}
unoptimized
lazy
loading="lazy"
></Image>
<div style={{ height: '2000px' }}></div>
<Image
id="lazy-without-attribute"
src="foo4.jpg"
height={400}
width={300}
></Image>
<div style={{ height: '2000px' }}></div>
<Image
id="eager-loading"
src="foo5.jpg"
loading="eager"
height={400}
width={300}
></Image>
</div>
)
......
......@@ -132,6 +132,38 @@ function lazyLoadingTests() {
await browser.elementById('lazy-bottom').getAttribute('srcset')
).toBeFalsy()
})
it('should load the fourth image lazily after scrolling down', async () => {
expect(
await browser.elementById('lazy-without-attribute').getAttribute('src')
).toBeFalsy()
expect(
await browser.elementById('lazy-without-attribute').getAttribute('srcset')
).toBeFalsy()
let viewportHeight = await browser.eval(`window.innerHeight`)
let topOfBottomImage = await browser.eval(
`document.getElementById('lazy-without-attribute').parentElement.offsetTop`
)
let buffer = 150
await browser.eval(
`window.scrollTo(0, ${topOfBottomImage - (viewportHeight + buffer)})`
)
await waitFor(200)
expect(
await browser.elementById('lazy-without-attribute').getAttribute('src')
).toBe('https://example.com/myaccount/foo4.jpg?auto=format')
expect(
await browser.elementById('lazy-without-attribute').getAttribute('srcset')
).toBeTruthy()
})
it('should load the fifth image eagerly, without scrolling', async () => {
expect(await browser.elementById('eager-loading').getAttribute('src')).toBe(
'https://example.com/myaccount/foo5.jpg?auto=format'
)
expect(
await browser.elementById('eager-loading').getAttribute('srcset')
).toBeTruthy()
})
}
async function hasPreloadLinkMatchingUrl(url) {
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册