<!DOCTYPE html>
<html>

  <head>
    <link data-require="select2@*" data-semver="4.0.0" rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/select2/4.0.0/css/select2.css" />
    <script src="https://unpkg.com/jquery@3.1.1"></script>
    <script src="https://unpkg.com/select2@4.0.3"></script>
    <script src="https://unpkg.com/vue@latest/dist/vue.js"></script>
    <link rel="stylesheet" href="style.css" />
    <script src="script.js"></script>
  </head>

  <body>
    <div id="el"></div>

<!-- using string template here to work around HTML <option> placement restriction -->
<script type="text/x-template" id="demo-template">
  <div>
    <p>Selected: {{ selected }}</p>
    <select2 :options="options" v-model="selected" :url="url">
      <option disabled value="0">Select one</option>
    </select2>
    <div v-for="urlItem in urls">
      <label><input type="radio" v-model="url" :value="urlItem" /> {{urlItem}}</label>
    </div>
  </div>
</script>

<script type="text/x-template" id="select2-template">
  <select>
    <slot></slot>
  </select>
</script>

  </body>

</html>
document.addEventListener('DOMContentLoaded', function() {
  Vue.component('select2', {
    props: ['options', 'value', 'url'],
    template: '#select2-template',
    data: function() {
      return {
        ajaxOptions: {
          url: this.url,
          dataType: 'json',
          delay: 250,
          tags: true,
          data: function(params) {
            return {
              term: params.term, // search term
              page: params.page
            };
          },
          processResults: function(data, params) {
            params.page = params.page || 1;
            return {
              results: data,
              pagination: {
                more: (params.page * 30) < data.total_count
              }
            };
          },
          cache: true
        }
      };
    },
    mounted: function() {
      var vm = this
      $(this.$el)
        // init select2
        .select2({
          placeholder: "Click to see options",
          ajax: this.ajaxOptions
        })
        .val(this.value)
        .trigger('change')
        // emit event on change.
        .on('change', function() {
          vm.$emit('input', this.value)
        })
    },
    watch: {
      value: function(value) {
        // update value
        $(this.$el).val(value).trigger('change');
      },
      options: function(options) {
        // update options
        $(this.$el).empty().select2({
          data: options
        })
      },
      url: function(value) {
        this.ajaxOptions.url = this.url;
        $(this.$el).select2({
          ajax: this.ajaxOptions
        });
      }
    },
    destroyed: function() {
      $(this.$el).off().select2('destroy')
    }
  })

  const urls = ['data1.json', 'data2.json'];
  var vm = new Vue({
    el: '#el',
    template: '#demo-template',
    data: {
      selected: 2,
      options: [{
        id: 1,
        text: 'Hello'
      }, {
        id: 2,
        text: 'World'
      }],
      url: urls[0],
      urls: urls
    },
    mounted: function() {
      console.log('mounted el');
    }
  });
});
html,
body {
  font: 13px/18px sans-serif;
}

select {
  min-width: 300px;
}
[{"id":1,"text":"explicabo"},{"id":2,"text":"repudiandae"},{"id":3,"text":"expedita"},{"id":4,"text":"beatae"}]
[{"id":5,"text":"comedi"},{"id":6,"text":"laverunt"},{"id":7,"text":"purgandum"},{"id":8,"text":"facilius"}]