<div class="slideshow">
  <div class="slideshow__container js-slideshow">
    <img
      v-for="slide, index in slides"
      :key="slide.id"
      :src="slide.url"
      :alt="slide.title"
      :class="{ active: isActive(index) }"
      @mouseover="stopRotation"
      @mouseout="startRotation"
    />
  </div>
  <p>Images from <a href="https://www.unsplash.com/" target="_blank">unsplash</a></p>
</div>
/* Base styling ----- */
body {
  display: flex;
  align-items: center;
  justify-content: center;
  
  margin: 0;
  padding: 0;
  width: 100vw;
  height: 100vh;
  
  font-family: 'Lato', sans-serif;
  
  color: #34495e;
  background-color: salmon;
}

p {
  margin: 1rem 0 0;
  
  font-size: 18px;
  line-height: 1;
}

a {
  padding-bottom: 2px;
  border-bottom: 1px solid;
  
  color: inherit;
  
  text-decoration: none;
}

/* Slideshow styling ----- */
.slideshow__container {
  overflow: hidden;
  position: relative;
  
  padding-top: calc(9 / 16 * 100%);
  
  min-width: 400px;
  width: 50vw;
  height: 0;
  
  background-color: rgba(0, 0, 0, 0.5);
  box-shadow: 0px 0px 10px 0px rgba(0,0,0,0.75);
}

img {
  display: block;
  
  position: absolute;
  top: 0;
  left: 0;
  
  width: 100%;
  height: 100%;
  
  object-fit: cover;
  
  opacity: 0;
  transition: opacity 1s;
}

img:hover {
  cursor: pointer;
}

.active {
  opacity: 1;
}
new Vue({
  el: '.js-slideshow',
  data: {
    current: 0,
    slides: [],
    speed: 3000,
    timer: null
  },
  methods: {
    startRotation: function () {
      this.timer = setInterval(this.next, this.speed);
    },
    stopRotation: function () {
      clearTimeout(this.timer);
      this.timer = null;
    },
    next: function () {
      var current = this.current;
      var next = current + 1;

      if (next > this.slides.length - 1) {
        next = 0;
      }
      this.current = next;
      this.setActive(this.current);
    },
    prev: function () {
      var current = this.current;
      var prev = current - 1;

      if (prev < 0) {
        prev = this.slides.length -1;
      }

      this.current = prev;
      this.setActive(this.current);
    },
    isActive: function (slide) {
      return this.current === slide;
    },
    setActive: function (slide) {
      this.current = slide;
    },
  },
  created: function () {
    axios.get('https://s3-us-west-2.amazonaws.com/s.cdpn.io/4723/slides.json')
    .then(function (response) {
      this.slides = response.data.slides
    }.bind(this))
    .catch(function (error) {
      console.log(error);
    });
  },
  mounted: function () {
    this.startRotation();
  }
});

External CSS

  1. https://fonts.googleapis.com/css?family=Lato:700

External JavaScript

  1. https://unpkg.com/axios/dist/axios.min.js
  2. https://unpkg.com/[email protected]/dist/vue.min.js