发布于 2026-01-06 1 阅读
0

启动和停止一只羊驼!如何创建一个非自动播放的 GIF 网页组件🎞️🛑🔥

启动和停止一只羊驼!如何创建一个非自动播放的 GIF 网页组件🎞️🛑🔥

自动播放功能很烦人。动态内容会分散用户的注意力。一篇充斥着大量自动播放GIF的列表文章看起来会非常杂乱——幸好GIF没有声音,对吧?

今天,我将向您展示如何创建一个网页组件,让用户可以选择是否播放GIF动画!让我们开始吧。

一些非常可爱的测试数据

我打开一个热门搜索引擎,搜索“示例gif”,结果却令人失望。我本来希望能找到一些现成的gif素材,结果却只找到一个超级可爱的小羊驼和小猫互动的视频

一只羊驼和一只猫在玩耍

哇,太可爱了!我可以看一整天。等等——我真的可以!我真幸运!

构建 Web 组件

所以,对于这个网页组件,我们需要一些东西:

  • 画布(将在此处显示“缩略图”)
  • 图片(实际的gif动画)
  • 标签上写着“gif”
  • 一些造型

我们就这么做吧:

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>`
Enter fullscreen mode Exit fullscreen mode

接下来,我们将创建一个继承自 的类HTMLElement。这个类稍后将包含播放/停止切换行为。

class NoAutoplayGif extends HTMLElement {
  constructor() {
    super()

    // Add setup here
  }

  loadImage() {
    // Add rendering here
  }

  static get observedAttributes() {
    return ['src', 'alt'];
  }

  attributeChangedCallback(name, oldVal, newVal) {
    if (oldVal !== newVal || oldVal === null) {
      this.loadImage()
    }
  }
}
Enter fullscreen mode Exit fullscreen mode

这里还有一些样板代码:一个空的渲染函数,用于加载图像并显示缩略图,以及一个构造函数和一些特定于 Web 组件的方法。

好了,代码已经很多了。让我解释一下。

loadImage函数不会自动调用,我们需要手动调用。该函数attributeChangedCallback允许我们定义当任何指定属性发生observedAttributes变化时会发生什么。在本例中:加载并显示图像。浏览器大致执行的操作如下:

  • 遭遇 Web 组件
  • 调用其构造函数(调用constructor()
  • 按照 DOM 中的设置逐一设置其属性(即src="llama.gif"调用) 。.setAttribute('src', 'llama.gif')
  • attributeChangedCallback对每个已更改的属性执行此操作

在构造函数中进行检查时,这些属性最初为空,之后才会填充。如果我们需要一个或多个属性来进行实际渲染,loadImage而我们知道这些属性不存在,那么调用该函数就没有意义了。因此,我们不会在构造函数中调用该函数,而只在有可能存在该属性时才调用它。

为了完成样板代码的编写,让我们将此类定义为我们的自定义 Web 组件:

class NoAutoplayGif extends HTMLElement {
  // ...
}

window.customElements.define('no-autoplay-gif', NoAutoplayGif)
Enter fullscreen mode Exit fullscreen mode

现在我们可以像这样使用这个组件:

<no-autoplay-gif 
  src="..." 
  alt="Llama and cat" 
/>
Enter fullscreen mode Exit fullscreen mode

开局不错!

逻辑

现在到了有趣的部分。我们需要将noAutoplayGifTemplate组件添加到 Shadow DOM 中。这已经可以渲染 DOM,但如果没有 `<div>`src和 `<style>`alt属性,我们仍然无法进行太多操作。因此,我们只从 Shadow DOM 中收集一些稍后会用到的元素,并预先添加一个点击监听器来切换启动/停止模式。

class NoAutoplayGif extends HTMLElement {
  constructor() {
    super()

    // Attach the shadow DOM
    this._shadowRoot = this.attachShadow({ mode: 'open' })

    // Add the template from above
    this._shadowRoot.appendChild(
      noAutoplayGifTemplate.content.cloneNode(true)
    )

    // We'll need these later on.
    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')

    // Make the entire thing clickable
    this._shadowRoot.querySelector('.no-autoplay-gif').addEventListener('click', () => {
      this.toggleImage()
    })
  }

  // ...
}
Enter fullscreen mode Exit fullscreen mode

为了避免出现未定义方法错误,我们还添加了以下三种方法:

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)
  }
  // ...
}
Enter fullscreen mode Exit fullscreen mode

启动/停止方法允许我们强制启动或强制停止 GIF 动画。理论上,我们现在可以这样做:

const gif = document.querySelector('no-autoplay-gif')
gif.start()
gif.stop()
gif.toggleImage()
Enter fullscreen mode Exit fullscreen mode

整洁的!

最后,我们可以添加图片加载部分。首先让我们做一些验证:

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
  }
  // ...
}
Enter fullscreen mode Exit fullscreen mode

最后一步,我们可以加载图像,设置宽度和高度,然后就可以使用画布了:

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
  }
  // ...
}
Enter fullscreen mode Exit fullscreen mode

好了,我们完成了!

结果

好的!


希望您喜欢这篇文章,就像我喜欢写这篇文章一样!如果喜欢,请点个赞❤️🦄 !我会在空闲时间写一些科技文章,偶尔也喜欢喝杯咖啡。

如果你想支持我的工作, 可以请我喝杯咖啡 或者 在推特上关注我🐦 你也可以直接通过PayPal支持我!

给我买杯咖啡按钮

文章来源:https://dev.to/thormeier/autoplay-begone-how-to-create-a-non-autoplay-gif-web-component-hbf