詳解JavaScript如何創(chuàng)建一個非自動播放的GIF網(wǎng)絡(luò)組件
今天,我將向您展示如何創(chuàng)建一個允許您的用戶決定是否要播放 gif 的 Web 組件!讓我們開始吧。
一些很可愛的測試數(shù)據(jù)
這里用的gif是小駱駝和貓的這種可愛互動:

哇,太可愛了!我可以看一天這個
構(gòu)建 Web 組件
對于這個 Web 組件,我們需要一些東西:
- 畫布(“縮略圖”所在的位置)
- 一張圖片(實(shí)際的 gif)
- 標(biāo)有“gif”的標(biāo)簽
- 一些造型
讓我們這樣做:
const noAutoplayGifTemplate = document.createElement('template')
noAutoplayGifTemplate.innerHTML = `
<style>
.no-autoplay-gif {
--size: 30px;
cursor: pointer;
position: relative;
}
.no-autoplay-gif .gif-label {
border: 2px solid #000;
background-color: #fff;
border-radius: 100%;
width: var(--size);
height: var(--size);
text-align: center;
font: bold calc(var(--size) * 0.4)/var(--size) sans-serif;
position: absolute;
top: calc(50% - var(--size) / 2);
left: calc(50% - var(--size) / 2);
}
.no-autoplay-gif .hidden {
display: none;
}
</style>
<div class="no-autoplay-gif">
<canvas />
<span class="gif-label" aria-hidden="true">GIF</span>
<img class="hidden">
</div>接下來,我們將創(chuàng)建一個派生自 HTMLElement 的類。 此類稍后將包含播放/停止切換行為。
class NoAutoplayGif extends HTMLElement {
constructor() {
super()
// 在此處添加設(shè)置
}
loadImage() {
// 在此處添加渲染
}
static get observedAttributes() {
return ['src', 'alt'];
}
attributeChangedCallback(name, oldVal, newVal) {
if (oldVal !== newVal || oldVal === null) {
this.loadImage()
}
}
}這里還有一些樣板:一個空的渲染函數(shù),它將加載圖像并顯示縮略圖,以及一個構(gòu)造函數(shù)和一些特定于 Web 組件的方法。
好的,這已經(jīng)是很多代碼了。讓我解釋。
該loadImage函數(shù)不會自動調(diào)用,我們需要自己調(diào)用。該函數(shù)attributeChangedCallback讓我們定義當(dāng)任何指定屬性發(fā)生observedAttributes變化時會發(fā)生什么。在這種情況下:加載圖像并顯示它。瀏覽器大致做的是這樣的:
- 遇到 web 組件
- 調(diào)用它的構(gòu)造函數(shù)(調(diào)用
constructor()) - 將其屬性一一設(shè)置為 DOM 中的設(shè)置(因此,
src="llama.gif"調(diào)用.setAttribute('src', 'llama.gif') attributeChangedCallback對每個更改的屬性執(zhí)行
簽入構(gòu)造函數(shù)時,這些屬性一開始是空的,稍后才會填充。如果我們需要一個或多個屬性來實(shí)際進(jìn)行渲染,那么如果我們 知道 這些屬性不存在,那么調(diào)用該loadImage函數(shù)是沒有意義的。所以我們不在構(gòu)造函數(shù)中調(diào)用它,但只有在有可能存在屬性時才調(diào)用它。**
為了完成樣板化,讓我們將這個類定義為我們的自定義 Web 組件:
class NoAutoplayGif extends HTMLElement {
// ...
}
window.customElements.define('no-autoplay-gif', NoAutoplayGif)我們現(xiàn)在可以像這樣使用這個組件:
<no-autoplay-gif src="..." alt="Llama and cat" />
邏輯
有趣的來了。我們需要添加noAutoplayGifTemplate作為組件的shadow DOM。src這已經(jīng)可以渲染 DOM,但是如果沒有andalt屬性,我們?nèi)匀徊荒茏龊芏嗍虑?。因此我們只?shadow DOM 中收集一些我們稍后需要的元素,并且已經(jīng)附加了一個單擊偵聽器來切換啟動/停止模式。
class NoAutoplayGif extends HTMLElement {
constructor() {
super()
// 添加 shadow DOM
this._shadowRoot = this.attachShadow({ mode: 'open' })
// 從上面添加模板
this._shadowRoot.appendChild(
noAutoplayGifTemplate.content.cloneNode(true)
)
// 我們稍后會需要這些
this.canvas = this._shadowRoot.querySelector('canvas')
this.img = this._shadowRoot.querySelector('img')
this.label = this._shadowRoot.querySelector('.gif-label')
this.container = this._shadowRoot.querySelector('.no-autoplay-gif')
// 使整個東西可點(diǎn)擊
this._shadowRoot.querySelector('.no-autoplay-gif').addEventListener('click', () => {
this.toggleImage()
})
}
// ...
}為了不遇到未定義的方法錯誤,我們還添加了這三個方法:
class NoAutoplayGif extends HTMLElement {
// ...
toggleImage(force = undefined) {
this.img.classList.toggle('hidden', force)
// We need to check for undefined values, as JS does a distinction here.
// We cannot simply negate a given force value (i.e. hiding one thing and unhiding another)
// as an undefined value would actually toggle the img, but
// always hide the other two, because !undefined == true
this.canvas.classList.toggle('hidden', force !== undefined ? !force : undefined)
this.label.classList.toggle('hidden', force !== undefined ? !force : undefined)
}
start() {
this.toggleImage(false)
}
stop() {
this.toggleImage(true)
}
// ...
}start/stop 方法允許我們強(qiáng)制啟動或強(qiáng)制停止 gif。理論上,我們現(xiàn)在可以這樣做:
const gif = document.querySelector('no-autoplay-gif')
gif.start()
gif.stop()
gif.toggleImage()最后,我們可以添加圖片加載部分。讓我們先做一些驗(yàn)證:
class NoAutoplayGif extends HTMLElement {
// ...
loadImage() {
const src = this.getAttribute('src')
const alt = this.getAttribute('alt')
if (!src) {
console.warn('A source gif must be given')
return
}
if (!src.endsWith('.gif')) {
console.warn('Provided src is not a .gif')
return
}
// More stuff
}
// ...
}最后一步,我們可以加載圖像,設(shè)置一些寬度和高度并使用畫布:
class NoAutoplayGif extends HTMLElement {
// ...
loadImage() {
// Validation
this.img.onload = event => {
const width = event.currentTarget.width
const height = event.currentTarget.height
// Set width and height of the entire thing
this.canvas.setAttribute('width', width)
this.canvas.setAttribute('height', height)
this.container.setAttribute('style', `
width: ${width}px;
height: ${height}px;
`)
// "Draws" the gif onto a canvas, i.e. the first
// frame, making it look like a thumbnail.
this.canvas.getContext('2d').drawImage(this.img, 0, 0)
}
// Trigger the loading
this.img.src = src
this.img.alt = alt
}
// ...
}我們完成了!
結(jié)果
演示地址:haiyong.site/gif

以上就是詳解JavaScript如何創(chuàng)建一個非自動播放的GIF網(wǎng)絡(luò)組件的詳細(xì)內(nèi)容,更多關(guān)于JavaScript播放GIF的資料請關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
微信小程序?qū)崿F(xiàn)卡片左右滑動效果的示例代碼
這篇文章主要介紹了微信小程序?qū)崿F(xiàn)卡片左右滑動效果的示例代碼,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2019-05-05
JavaScript中校驗(yàn)銀行卡號的實(shí)現(xiàn)代碼
本文通過案例給大家介紹了js中校驗(yàn)銀行卡號的代碼,代碼小編測試過,可行。代碼簡單易懂,非常不錯,具有參考借鑒價值,需要的朋友參考下吧2016-12-12
微信小程序button標(biāo)簽open-type屬性原理解析
這篇文章主要介紹了微信小程序button標(biāo)簽open-type屬性原理解析,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下2020-01-01
詳解使用JWT實(shí)現(xiàn)單點(diǎn)登錄(完全跨域方案)
這篇文章主要介紹了詳解使用JWT實(shí)現(xiàn)單點(diǎn)登錄(完全跨域方案),文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2019-08-08
一文詳解preact的高性能狀態(tài)管理Signals
這篇文章主要介紹了一文詳解preact的高性能狀態(tài)管理Signals,文章圍繞主題展開詳細(xì)的內(nèi)容介紹,具有一定的參考價值,感興趣的朋友可以參考一下2022-09-09
JavaScript函數(shù)之call、apply以及bind方法案例詳解
這篇文章主要介紹了JavaScript函數(shù)之call、apply以及bind方法案例詳解,本篇文章通過簡要的案例,講解了該項(xiàng)技術(shù)的了解與使用,以下就是詳細(xì)內(nèi)容,需要的朋友可以參考下2021-08-08
微信小程序報錯: thirdScriptError的錯誤問題
這篇文章主要介紹了微信小程序報錯: thirdScriptError,本文給大家分享解決方法,對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下2020-06-06

