如何检测 reactjs 是否支持 avif?
how to detect that avif is supported or not in reactjs?
我正在尝试通过将图像格式化为 avif 来优化图像。但是有些浏览器不支持avif。
所以我创建了一个这样的效用函数
function isAvifSupported() {
let returnValue;
const avif = new Image();
avif.src =
"data:image/avif;base64,AAAAIGZ0eXBhdmlmAAAAAGF2aWZtaWYxbWlhZk1BMUIAAADybWV0YQAAAAAAAAAoaGRscgAAAAAAAAAAcGljdAAAAAAAAAAAAAAAAGxpYmF2aWYAAAAADnBpdG0AAAAAAAEAAAAeaWxvYwAAAABEAAABAAEAAAABAAABGgAAAB0AAAAoaWluZgAAAAAAAQAAABppbmZlAgAAAAABAABhdjAxQ29sb3IAAAAAamlwcnAAAABLaXBjbwAAABRpc3BlAAAAAAAAAAIAAAACAAAAEHBpeGkAAAAAAwgICAAAAAxhdjFDgQ0MAAAAABNjb2xybmNseAACAAIAAYAAAAAXaXBtYQAAAAAAAAABAAEEAQKDBAAAACVtZGF0EgAKCBgANogQEAwgMg8f8D///8WfhwB8+ErK42A=";
avif.onload = function () {
returnValue = true
};
return returnValue;
}
但是当我尝试调用这个函数时它总是return未定义。但是当我使用avif网站已经提供的功能时。它工作正常。下面是它的代码
function AddClass(class) { document.documentElement.classList.add(class) };
var avif = new Image();
avif.src = "data:image/avif;base64,AAAAIGZ0eXBhdmlmAAAAAGF2aWZtaWYxbWlhZk1BMUIAAADybWV0YQAAAAAAAAAoaGRscgAAAAAAAAAAcGljdAAAAAAAAAAAAAAAAGxpYmF2aWYAAAAADnBpdG0AAAAAAAEAAAAeaWxvYwAAAABEAAABAAEAAAABAAABGgAAAB0AAAAoaWluZgAAAAAAAQAAABppbmZlAgAAAAABAABhdjAxQ29sb3IAAAAAamlwcnAAAABLaXBjbwAAABRpc3BlAAAAAAAAAAIAAAACAAAAEHBpeGkAAAAAAwgICAAAAAxhdjFDgQ0MAAAAABNjb2xybmNseAACAAIAAYAAAAAXaXBtYQAAAAAAAAABAAEEAQKDBAAAACVtZGF0EgAKCBgANogQEAwgMg8f8D///8WfhwB8+ErK42A=";
avif.onload = function () { AddClass("avif") };
avif.onerror = function () {
var webp = new Image();
webp.src = "data:image/webp;base64,UklGRhoAAABXRUJQVlA4TA0AAAAvAAAAEAcQERGIiP4HAA==";
webp.onload = function () { AddClass("webp") }
}
但是上面定义的函数在dom的顶层添加了css。而不是添加 class,它必须 return true 或 false。这样我就可以像这样轻松处理。
let updatedImageUrl = isAvifSupported() ? `${imageUrl}?fm=avif` ? imageUrl
但我不知道如何解决这个问题。请推荐一个解决方案。
您的代码段的主要问题是您没有考虑异步调用。
onload
将在函数 returns 之后调用。要解决此问题,您必须提供回调并实现承诺,如下例所示。
function isAvifSupported() {
return new Promise(resolve => {
var image = new Image();
image.onload = image.onerror = function() {
resolve(image.width === 2);
};
image.src = "data:image/avif;base64,AAAAIGZ0eXBhdmlmAAAAAGF2aWZtaWYxbWlhZk1BMUIAAADybWV0YQAAAAAAAAAoaGRscgAAAAAAAAAAcGljdAAAAAAAAAAAAAAAAGxpYmF2aWYAAAAADnBpdG0AAAAAAAEAAAAeaWxvYwAAAABEAAABAAEAAAABAAABGgAAAB0AAAAoaWluZgAAAAAAAQAAABppbmZlAgAAAAABAABhdjAxQ29sb3IAAAAAamlwcnAAAABLaXBjbwAAABRpc3BlAAAAAAAAAAIAAAACAAAAEHBpeGkAAAAAAwgICAAAAAxhdjFDgQ0MAAAAABNjb2xybmNseAACAAIAAYAAAAAXaXBtYQAAAAAAAAABAAEEAQKDBAAAACVtZGF0EgAKCBgANogQEAwgMg8f8D///8WfhwB8+ErK42A=";
});
}
isAvifSupported().then(console.log);
作为灵感,我调整了 the standard modernizr 片段以适合您的用例并使用了您的虚拟图像。
请记住,因为您必须使用异步调用,所以功能检测也必须是异步的。
isAvifSupported().then(
isSupported => {
const updatedImageUrl = isSupported ?
`${imageUrl}?fm=avif` :
imageUrl;
}
);
根据您的项目,您可能需要重构一些东西来实现承诺(或回调)解决方案,但遗憾的是,无法同步检查 avif 支持。
以下功能可以正常工作。它是@Stefan Judis 的扩展答案版本。我根据我的项目修改了这个
import React, { useEffect, useState } from "react";
import "./styles.css";
const url =
"https://images.ctfassets.net/{space_id}/1WJFyl9C8q18KI6OQG7mPu/{unique_name}/name.jpg";
const ImageFormat = () => {
const [imageFormat, setImageFormat] = useState("");
function addImageProcess(src) {
return new Promise((resolve, reject) => {
let img = new Image();
img.onload = () => resolve("avif");
img.onerror = () => {
const webp = new Image();
webp.src =
"data:image/webp;base64,UklGRhoAAABXRUJQVlA4TA0AAAAvAAAAEAcQERGIiP4HAA==";
webp.onload = async () => {
resolve("webp");
};
webp.onerror = () => {
reject("");
};
};
img.src = src;
});
}
useEffect(() => {
async function logImageFormat(imageUrl) {
let imageFormatValue = await addImageProcess(imageUrl);
setImageFormat(`${url}?fm=${imageFormatValue}&w=3500`);
}
logImageFormat(
"data:image/avif;base64,AAAAIGZ0eXBhdmlmAAAAAGF2aWZtaWYxbWlhZk1BMUIAAADybWV0YQAAAAAAAAAoaGRscgAAAAAAAAAAcGljdAAAAAAAAAAAAAAAAGxpYmF2aWYAAAAADnBpdG0AAAAAAAEAAAAeaWxvYwAAAABEAAABAAEAAAABAAABGgAAAB0AAAAoaWluZgAAAAAAAQAAABppbmZlAgAAAAABAABhdjAxQ29sb3IAAAAAamlwcnAAAABLaXBjbwAAABRpc3BlAAAAAAAAAAIAAAACAAAAEHBpeGkAAAAAAwgICAAAAAxhdjFDgQ0MAAAAABNjb2xybmNseAACAAIAAYAAAAAXaXBtYQAAAAAAAAABAAEEAQKDBAAAACVtZGF0EgAKCBgANogQEAwgMg8f8D///8WfhwB8+ErK42A="
);
}, []);
return (
<>
<div className="App">{imageFormat}</div>
</>
);
};
export default ImageFormat;
我正在尝试通过将图像格式化为 avif 来优化图像。但是有些浏览器不支持avif。
所以我创建了一个这样的效用函数
function isAvifSupported() {
let returnValue;
const avif = new Image();
avif.src =
"data:image/avif;base64,AAAAIGZ0eXBhdmlmAAAAAGF2aWZtaWYxbWlhZk1BMUIAAADybWV0YQAAAAAAAAAoaGRscgAAAAAAAAAAcGljdAAAAAAAAAAAAAAAAGxpYmF2aWYAAAAADnBpdG0AAAAAAAEAAAAeaWxvYwAAAABEAAABAAEAAAABAAABGgAAAB0AAAAoaWluZgAAAAAAAQAAABppbmZlAgAAAAABAABhdjAxQ29sb3IAAAAAamlwcnAAAABLaXBjbwAAABRpc3BlAAAAAAAAAAIAAAACAAAAEHBpeGkAAAAAAwgICAAAAAxhdjFDgQ0MAAAAABNjb2xybmNseAACAAIAAYAAAAAXaXBtYQAAAAAAAAABAAEEAQKDBAAAACVtZGF0EgAKCBgANogQEAwgMg8f8D///8WfhwB8+ErK42A=";
avif.onload = function () {
returnValue = true
};
return returnValue;
}
但是当我尝试调用这个函数时它总是return未定义。但是当我使用avif网站已经提供的功能时。它工作正常。下面是它的代码
function AddClass(class) { document.documentElement.classList.add(class) };
var avif = new Image();
avif.src = "data:image/avif;base64,AAAAIGZ0eXBhdmlmAAAAAGF2aWZtaWYxbWlhZk1BMUIAAADybWV0YQAAAAAAAAAoaGRscgAAAAAAAAAAcGljdAAAAAAAAAAAAAAAAGxpYmF2aWYAAAAADnBpdG0AAAAAAAEAAAAeaWxvYwAAAABEAAABAAEAAAABAAABGgAAAB0AAAAoaWluZgAAAAAAAQAAABppbmZlAgAAAAABAABhdjAxQ29sb3IAAAAAamlwcnAAAABLaXBjbwAAABRpc3BlAAAAAAAAAAIAAAACAAAAEHBpeGkAAAAAAwgICAAAAAxhdjFDgQ0MAAAAABNjb2xybmNseAACAAIAAYAAAAAXaXBtYQAAAAAAAAABAAEEAQKDBAAAACVtZGF0EgAKCBgANogQEAwgMg8f8D///8WfhwB8+ErK42A=";
avif.onload = function () { AddClass("avif") };
avif.onerror = function () {
var webp = new Image();
webp.src = "data:image/webp;base64,UklGRhoAAABXRUJQVlA4TA0AAAAvAAAAEAcQERGIiP4HAA==";
webp.onload = function () { AddClass("webp") }
}
但是上面定义的函数在dom的顶层添加了css。而不是添加 class,它必须 return true 或 false。这样我就可以像这样轻松处理。
let updatedImageUrl = isAvifSupported() ? `${imageUrl}?fm=avif` ? imageUrl
但我不知道如何解决这个问题。请推荐一个解决方案。
您的代码段的主要问题是您没有考虑异步调用。
onload
将在函数 returns 之后调用。要解决此问题,您必须提供回调并实现承诺,如下例所示。
function isAvifSupported() {
return new Promise(resolve => {
var image = new Image();
image.onload = image.onerror = function() {
resolve(image.width === 2);
};
image.src = "data:image/avif;base64,AAAAIGZ0eXBhdmlmAAAAAGF2aWZtaWYxbWlhZk1BMUIAAADybWV0YQAAAAAAAAAoaGRscgAAAAAAAAAAcGljdAAAAAAAAAAAAAAAAGxpYmF2aWYAAAAADnBpdG0AAAAAAAEAAAAeaWxvYwAAAABEAAABAAEAAAABAAABGgAAAB0AAAAoaWluZgAAAAAAAQAAABppbmZlAgAAAAABAABhdjAxQ29sb3IAAAAAamlwcnAAAABLaXBjbwAAABRpc3BlAAAAAAAAAAIAAAACAAAAEHBpeGkAAAAAAwgICAAAAAxhdjFDgQ0MAAAAABNjb2xybmNseAACAAIAAYAAAAAXaXBtYQAAAAAAAAABAAEEAQKDBAAAACVtZGF0EgAKCBgANogQEAwgMg8f8D///8WfhwB8+ErK42A=";
});
}
isAvifSupported().then(console.log);
作为灵感,我调整了 the standard modernizr 片段以适合您的用例并使用了您的虚拟图像。
请记住,因为您必须使用异步调用,所以功能检测也必须是异步的。
isAvifSupported().then(
isSupported => {
const updatedImageUrl = isSupported ?
`${imageUrl}?fm=avif` :
imageUrl;
}
);
根据您的项目,您可能需要重构一些东西来实现承诺(或回调)解决方案,但遗憾的是,无法同步检查 avif 支持。
以下功能可以正常工作。它是@Stefan Judis 的扩展答案版本。我根据我的项目修改了这个
import React, { useEffect, useState } from "react";
import "./styles.css";
const url =
"https://images.ctfassets.net/{space_id}/1WJFyl9C8q18KI6OQG7mPu/{unique_name}/name.jpg";
const ImageFormat = () => {
const [imageFormat, setImageFormat] = useState("");
function addImageProcess(src) {
return new Promise((resolve, reject) => {
let img = new Image();
img.onload = () => resolve("avif");
img.onerror = () => {
const webp = new Image();
webp.src =
"data:image/webp;base64,UklGRhoAAABXRUJQVlA4TA0AAAAvAAAAEAcQERGIiP4HAA==";
webp.onload = async () => {
resolve("webp");
};
webp.onerror = () => {
reject("");
};
};
img.src = src;
});
}
useEffect(() => {
async function logImageFormat(imageUrl) {
let imageFormatValue = await addImageProcess(imageUrl);
setImageFormat(`${url}?fm=${imageFormatValue}&w=3500`);
}
logImageFormat(
"data:image/avif;base64,AAAAIGZ0eXBhdmlmAAAAAGF2aWZtaWYxbWlhZk1BMUIAAADybWV0YQAAAAAAAAAoaGRscgAAAAAAAAAAcGljdAAAAAAAAAAAAAAAAGxpYmF2aWYAAAAADnBpdG0AAAAAAAEAAAAeaWxvYwAAAABEAAABAAEAAAABAAABGgAAAB0AAAAoaWluZgAAAAAAAQAAABppbmZlAgAAAAABAABhdjAxQ29sb3IAAAAAamlwcnAAAABLaXBjbwAAABRpc3BlAAAAAAAAAAIAAAACAAAAEHBpeGkAAAAAAwgICAAAAAxhdjFDgQ0MAAAAABNjb2xybmNseAACAAIAAYAAAAAXaXBtYQAAAAAAAAABAAEEAQKDBAAAACVtZGF0EgAKCBgANogQEAwgMg8f8D///8WfhwB8+ErK42A="
);
}, []);
return (
<>
<div className="App">{imageFormat}</div>
</>
);
};
export default ImageFormat;