gifアニメーションをリセット
ブラウザがレンダリングすると、属性でimg
指定されたソースsrc
が将来の再利用のためにメモリにキャッシュされます。これにより、ページの読み込み/再読み込みの速度を上げるだけでなく、ネットワークの負荷を減らすことができます。そして、この動作はほとんどすべての人に適しています。実際には、これが最も最適で要求の厳しいオプションだからです。
ただし、いつものように、例外があります。私はいくつかの問題を解決するdataUrlベースのアニメーション更新オプションを思いついた。
解決された問題:
ループのないアニメーション(ループ= 1 )でgif画像を表示する必要があります。これは同じである可能性があります。ただし、そのような画像が1つ表示された場合は、同じ画像の他の画像のアニメーションを変更せずにアニメーションを再生する必要があります。同じ画像をサーバーから1回だけロードする必要があります。スタックオーバーフローsrc
src
gifアニメーションをリセットします。
ホバーでアニメーションを開始します
src属性をリセット
画像の属性をクリアするソリューションを使用するsrc
と、同じソースを持つすべての画像がアニメーションを再生します。残念ながら、なぜこれが起こっているのかまだ完全には理解していませんでしたが、それは正しい作業を妨げます。
短所
- 同じsrcを持つすべての画像のアニメーションをリセットします。
- モバイルデバイスに問題があります
長所
ランダムクエリでURLを変更する
このソリューションは、属性の最後にランダムなクエリパラメータを追加することで構成されsrc
ます。これにより、すべての画像のソースが異なり、互いに独立してアニメーション化されます。1つの大きな脂肪NOがあります:これは、画像をダウンロードするようにサーバーに絶えず要求することになり、したがって、それらはもはやキャッシュされません。また、100枚の同一の画像を表示する必要がある場合、サーバーへのリクエストは100回になります。ラフでタフですが、常に機能します。
短所
- 一意のクエリを持つ各画像がサーバーから再読み込みされます。
長所
dataUrlの変更(提案されたソリューション)
データURL(data:スキームの前に付けられたURL)を使用すると、コンテンツ作成者は小さなファイルをドキュメントにインラインで埋め込むことができます。それらは、その名前がWHATWGによって廃止されるまで、以前は「データURI」と呼ばれていました。
MDN
このドキュメントのdataUrl構造:
data:[<mediatype>][;base64],<data>
そして、これは仕様でどのように示されているかです:
dataurl := "data:" [ mediatype ] [ ";base64" ] "," data
mediatype := [ type "/" subtype ] *( ";" parameter )
data := *urlchar
parameter := attribute "=" value
の説明をよく見ると、そこにmediatype
奇妙な parameter
ことが示されています。しかし、仕様もあります:
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
ご覧のとおり、任意のパラメーターを指定できます。主なことは、上記の要件を満たしていることです。したがって、メディアタイプに追加の属性を埋め込むことができます。これは画像にまったく影響を与えませんが、データのURLは同じ画像とは異なります。
一般化されたアルゴリズム:
- 通常のリクエストで画像を読み込み、作成されたdataUrlからメタデータを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
"src=data:image/gif;base64;${Math.random()}${dataUrl}"
以上です!
バニラ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>
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;