Reset gif animation
当浏览器创建 img
时, rc
属性中指定的源会被缓存到内存中, 以便将来重新使用。 这样可以提高页面加载/ 重新加载的速度, 并减少网络的负载。 而这种行为对每个人都适用, 因为在现实中, 这是最理想和最需要的选择 。
然而,和往常一样,也有例外。我提出了一个基于数据Url的动画更新选项,解决了几个问题。
Issues solved:
需要显示具有动画且没有循环的动画(loop=1 )的 < enger> / strong > 图像,这些图像可能具有相同的 < code> src 。 但是,当出现一张这样的图片时,它必须播放动画,而不以相同的 src
更改其他图片的动画。同一图片只能从服务器上装入一次 。 < a href="https://stackoverflow.com/ questions/68917982/how-can-yo-instantate-a-gif-files- a-react- app/68918284 > > 。
重置 gif 动画 。
在悬盘上开始动画
Reset src attribute
如果我们使用一个能清除图像 < code> src 属性的解决方案, 那么所有使用同一来源的图像都会重播动画。 不幸的是, 我仍然不完全理解为什么会发生这种情况, 但是它会干扰正确的工作 。
Cons
Pros
Modify url with random query
此解决方案包括在 < code> src code> 属性结尾处添加随机查询参数, 这样所有图像都会有不同的源, 因此它们会相互独立地动画 。 有一个大胖子 < nuger > no strong > : 这将导致不断请求服务器下载图片, 因此它们将不再缓存 。 如果我们需要显示 100 张相同的图片, 那么服务器将会收到 100 个请求 。 粗糙和坚硬, 但总是有效 。
Cons
- Each picture with a unique query will be reloaded from the server.
Pros
Modify dataUrl (Proposed Solution)
Data URLs, URLs prefixed with the data: scheme, allow content creators to embed small files inline in documents. They were formerly known as "data URIs" until that name was retired by the WHATWG.
MDN
此文档中的数据Url结构 :
data:[<mediatype>][;base64],<data>
这就是"https://datatracker.ietf.org/doc/html/rfc2397" rel="不跟随 noreferrer">的特写 所显示的:
dataurl := "data:" [ mediatype ] [ ";base64" ] "," data
mediatype := [ type "/" subtype ] *( ";" parameter )
data := *urlchar
parameter := attribute "=" value
如果您仔细查看 mediatype
的描述, 就会看到一些奇怪的 参数
。 但是, 还有一个 < a href=>。 https:// datatracker. ietf.org/doc/html/rfc2045#section-5. 1, rel= "nofollown norefererr" > 的特性 < /a> :
attribute := token
; Matching of attributes
; is ALWAYS case-insensitive.
value := token / quoted-string
token := 1*<any (US-ASCII) CHAR except SPACE, CTLs, or tspecials>
tspecials := "(" / ")" / "<" / ">" / "@" /
"," / ";" / ":" / "" / <">
"/" / "[" / "]" / "?" / "="
; Must be in quoted-string,
; to use within parameter values
As can be seen, we can specify any parameter, the main thing is that it meets the requirements presented above!
Therefore, we can embed an additional attribute in the mediatype, which will not affect the image in any way, but the data url will differ from the same image.
Generalized algorithm:
- We load the image through a regular request and remove the metadata from created dataUrl from blob.
fetch("https://cdn140.picsart.com/330970106009201.gif").then(async (res) => {
const blob = await res.blob();
const reader = new FileReader();
reader.onload = (ev) => {
// It would be reasonable to remove metadata to the point!
// But for simplicity, I m using this implementation.
const dataUrl = ev.currentTarget.result.replace(
"data:image/gif;base64",
""
);
};
reader.readAsDataURL(blob);
});
创建/编辑 img
元素, 包含 src
属性 \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\
就这样!
Example Vanila JS
const url = "https://cdn140.picsart.com/330970106009201.gif";
function loadImage(src) {
fetch(src)
.then((res) => res.blob())
.then(async(blob) => {
const reader = new FileReader();
reader.onload = (ev) => {
const dataUrl = ev.currentTarget.result.replace("data:image/gif;base64", "")
const container = document.getElementById("container");
while (container.firstChild) {
container.firstChild.remove()
}
for (let i = 0; i < 6; i++) {
const img = document.createElement("img");
img.setAttribute("src", `data:image/gif;base64;gif-id=${Date.now()}${dataUrl}`)
container.appendChild(img);
img.addEventListener( click , ev => {
img.setAttribute("src", `data:image/gif;base64;gif-id=${Date.now()}${dataUrl}`)
})
}
};
reader.readAsDataURL(blob);
});
}
loadImage(url);
function updateImage() {
const newSrc = document.getElementById("image-src");
loadImage(document.getElementById("image-src").value);
}
#main {
display: flex;
flex-direction: column;
gap: 5px;
}
img {
width: 128px;
height: 128px;
padding: 5px;
}
<div id="main">
<label>Change gif url if current will become unavailable </label>
<input id="image-src" value="https://cdn140.picsart.com/330970106009201.gif"></input>
<button onclick="updateImage()">Update image source attribute</button>
<span>Click to reset!</span>
<div id="container">
</div>
</div>
Example React
import React, { useState, useRef } from "react";
function App() {
const [stars, setStars] = useState(0);
const [data, setData] = useState(null);
const ref = useRef(null);
React.useEffect(() => {
fetch("https://cdn140.picsart.com/330970106009201.gif")
.then((res) => res.blob())
.then(async (text) => {
const reader = new FileReader();
reader.onload = (ev) => {
setData(ev.currentTarget.result.replace("data:image/gif;base64", ""));
};
reader.readAsDataURL(text);
});
}, []);
return (
<React.Fragment>
<p onClick={() => setStars((s) => s + 1)}>+</p>
{data &&
new Array(stars).fill().map((s, ind) => {
return <Star src={data} key={ind}></Star>;
})}
<p onClick={() => setStars((s) => (s === 0 ? 0 : s - 1))}>-</p>
</React.Fragment>
);
}
export function Star(props) {
const [id] = useState(Math.random());
return (
<img
className="icon"
src={`data:image/gif;base64;gif-id=${id}` + props.src}
alt="animated star"
/>
);
}
export default App;