<div id="app">
  <nav>
    <ul>
      <li v-for="(item, index) in menuItems"
          :key="`item-${index}`"
          class="menu-item"
          :class="{
           'selected':item.selected,
           'dimmed':item.dimmed
          }"
          @mouseover="selectItem(index)"
          @mouseleave="selectItem(-1)">
          
          <span class="char"
              v-for="(char, charIndex) in item.chars"
              :key="`char-${charIndex}`" 
              :ref="`char-${index}-${charIndex}`">{{char}}</span> 
          <span class="arrow">➔</span>
      </li>
    </ul>
  </nav>
<!--   <p>
    selectedItem: {{ selectedItem }}
  </p>   -->
</div>
body {
  background-color: #F1F0E9;
}

.menu-item {
  font-size: 5em;
  list-style: none;
  text-transform: uppercase;
  font-family: sans-serif;
  text-align: center;
  cursor: pointer;
  transition: margin-left 0.5s  ease-out, opacity 0.5s  ease-out;
}

.selected {
  margin-left: -90px;
}

.menu-item > .arrow {
  opacity: 0;
  transition: opacity 0.7s ease-out;
}

.selected > .arrow {
  opacity: 1;
}

.dimmed {
  opacity: 0.3;
}

.char {
  display: inline-block;
  min-width: 0.3em;
}
// reference https://dribbble.com/shots/6109210-Chez-Studio-Menu-Hover-Animation

const itemsList = [
  'About',
  'Works',
  'News/Blog',
  'spark'
]

const LEFT = -1
const RIGHT = 1

new Vue({
  el: '#app',
  data: {
    selectedItem: -1
  },
  methods: {
    selectItem(id) {
      this.selectedItem = id;
      
      this.menuItems.forEach((item, index) => {
        const direction = item.selected ? LEFT : RIGHT;
        this.animateChars(index, item.label.length, direction);
      })
    },
    animateChars (id, charLength, direction) {
      for(let c=0;c < charLength; c++){
        const refId = `char-${id}-${c}`;
        const char = this.$refs[refId];
        TweenMax.killTweensOf(char);
        TweenMax.to(char, 0.5, {scaleX: direction});
      }
    }
  },
  computed: {
    menuItems () {
      return itemsList.map((item, index) => {
        const isSelected = this.selectedItem === index;
        const otherButtonIsSelected = this.selectedItem !== -1
        return {
          label: item,
          selected: isSelected,
          dimmed: !isSelected && otherButtonIsSelected,
          chars: item.split('')
        }
      })
    }
  }
})

External CSS

This Pen doesn't use any external CSS resources.

External JavaScript

  1. https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17-beta.0/vue.js
  2. https://cdnjs.cloudflare.com/ajax/libs/gsap/latest/TweenMax.min.js