Vue

by Kristian Jabilles

HTML

<div id="app">
  <div class="slider">

    <!-- <a :href="`#slide-${item.slug}`" v-for="(item, index) in slides" :key="index">{{index}}</a> -->

    <br />
    <br />
    <div class="slides">
      <div :id="`slide-${index}`" v-for="(item, index) in slides" :key="index">
        {{item.label}}
      </div>
    </div>
    <br />
     <div class="controls">
      <button @click="prev">prev</button>
      <button @click="next">next</button>
    </div>
  </div>
</div>

CSS

* {
  box-sizing: border-box;
}

/* Don't need button navigation */
@supports (scroll-snap-type) {
  .slider > a {
    display: none;
  }
}


body {
  display: flex;
  align-items: center;
  justify-content: center;
  background: #eee;
  font-family: 'Ropa Sans', sans-serif;
}

.slider {
  width: 900px;
  text-align: center;
  overflow: auto;
  position: relative;
}

::-webkit-scrollbar {
  display: none;
}

.slides {
  display: flex;
  
  overflow-x: auto;
  scroll-snap-type: x mandatory;
  scroll-behavior: smooth;
  -webkit-overflow-scrolling: touch;
  
  /*
  scroll-snap-points-x: repeat(300px);
  scroll-snap-type: mandatory;
  */
}
.slides::-webkit-scrollbar {
  width: 10px;
  height: 10px;
}
.slides::-webkit-scrollbar-thumb {
  background: black;
  border-radius: 10px;
}
.slides::-webkit-scrollbar-track {
  background: transparent;
}
.slides > div {
  scroll-snap-align: start;
  flex-shrink: 0;
  width: auto;
  height: 30px;
  margin-right: 8px;
  border-radius: 3px;
  background: #ccc;
  transform-origin: center center;
  transform: scale(1);
  transition: transform 0.5s;
  position: relative;
  padding: 0 8px;
  
  display: flex;
  justify-content: center;
  align-items: center;
  font-size: 12px;
}


.slider > a {
  display: inline-flex;
  width: 1.5rem;
  height: 1.5rem;
  background: white;
  text-decoration: none;
  align-items: center;
  justify-content: center;
  border-radius: 50%;
  margin: 0 0 0.5rem 0;
  position: relative;
}
.slider > a:active {
  top: 1px;
}
.slider > a:focus {
  background: #000;
}

Vue

new Vue({
  el: "#app",
  data: {
    slides: [
      {
        label: 'All Exclusive Credit Cards',
        slug: 'all-exclusive'
      },
      {
        label: 'Air Miles',
        slug: 'air-miles'
      },
      {
        label: 'Cashback',
        slug: 'cashback'
      },
      {
        label: 'Petrol',
        slug: 'petrol'
      },
      {
        label: 'Dining',
        slug: 'dining'
      },
      {
        label: 'Shopping',
        slug: 'shopping'
      },
      {
        label: 'Overseas Spending',
        slug: 'overseas-spending'
      },
      {
        label: 'Grocery',
        slug: 'grocery'
      },
      {
        label: 'Overseas Shopping',
        slug: 'overseas-shopping'
      },
      {
        label: 'No Anual Fee',
        slug: 'no-annual-fee'
      },
      {
        label: 'Rewards',
        slug: 'rewards'
      },
      {
        label: 'Promotions',
        slug: 'promotions'
      },
    ],
    position: 0
  },
  methods: {
    next() {
    	this.position = this.position + 1;
      
      const sliderWrapper = document.querySelector('.slides');
      const nextSlide = document.querySelector(`#slide-${this.position}`);
      
      if(nextSlide) {
        sliderWrapper.scrollLeft = nextSlide.offsetLeft;
      }
    },
    prev() {
    	this.position = this.position - 1;
      
      const sliderWrapper = document.querySelector('.slides');
      const previousSlide = document.querySelector(`#slide-${this.position}`);
      
      if(previousSlide) {
	      sliderWrapper.scrollLeft = previousSlide.offsetLeft;
      }
    }
  }
})