<div id="app"></div>
#app {
  padding: 10px;
}

.btn + .btn {
  margin-left: 10px;
}

.alert {
  margin-top: 10px;
}
const Component = Vue.extend({
  template: `
    <div id="app">
      <button 
        v-for="n in 3" 
        :key="n" 
        :class="['btn', 'btn-default', { active: index === n }]"
        @click="switchTab(n)"
      >
        Tab {{ n }}
      </button>
      <div class="alert alert-success" v-text="message"/>
    </div>
  `,
  data() {
    return {
      index: 0,
      message: 'Select a tab',
    };
  },

  methods: {
    switchTab(index) {
      this.index = index;
      this.message = 'Loading...';
      this.loadContent(index)
        .then(message => { this.message = message; });
    },

    loadContent(index) {
      return new Promise((resolve) => {
        setTimeout(() => resolve(`Message #${index}`), 1000);
      });
    },
  },
});

new Vue({
  el: '#app',
  render(h) {
    return h(Component);
  }
});

External CSS

  1. https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.3.7/css/bootstrap.min.css

External JavaScript

  1. https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.3/vue.min.js