2015-11-14 3 views
7

У меня есть этот код в моем шаблоне:Vuejs + Materializecss поле выбора

<div class="input-field col s6"> 
    <select v-on:change="selectChaned" v-model="item.size"> 
     <option value="" disabled selected>Choose your option</option> 
     <option v-on:click="optionClicked" v-for="size in case_sizes" v-bind:value="{{ size }}">{{ size }}</option> 
    </select> 
    <label for="size">Size</label> 
</div> 

Согласно Materializecss документации, которую я называю $('select').material_select(); для преобразования по умолчанию выберите поле в нечто милашка. Что он также делает - он заменяет <select> и <option> тегами с <ul> и <li>. В результате я не могу получить доступ к значению item.size в моем файле ViewModel js. Я даже пытался прослушать щелчок на поле опций и вызвать метод optionClicked (который должен просто предупредить сообщение тогда), попытался прослушать selectChaned. Ничего.

Как я могу получить значение параметра в ViewModel?

p.s. просто для информации: у меня только проблема с полем выбора. Поле ввода, например, работает отлично:

<input placeholder="" name="name" type="text" class="validate" v-model="item.name"> 

В ViewModel я могу получить доступ к item.name

+0

вы можете привести пример в jsfiddle, jsbin и т.д.? –

ответ

11

Кажется, что Materialize не отправляет никаких событий, поэтому я не мог найти элегантное решение. Но это, кажется, что следующий Vuejs директива + Jquery обходной путь работает:

Vue.directive("select", { 
    "twoWay": true, 

    "bind": function() { 
     $(this.el).material_select(); 

     var self = this; 

     $(this.el).on('change', function() { 
      self.set($(self.el).val()); 
     }); 
    }, 

    update: function (newValue, oldValue) { 
     $(this.el).val(newValue); 
    }, 

    "unbind": function() { 
     $(this.el).material_select('destroy'); 
    } 
}); 

, а затем в вашем HTML - привязка < выберите> с помощью v-выбрать вместо у-модели.

+2

Ссылка 'this' указывает на' window' в методах 'bind',' update' и 'unbind'. Не удается установить значение. Используете ли вы последнюю версию vue? –

+2

@ EnmanuelRivera нет, это было сделано с предыдущей версией Vue, а не с текущим –

0

У меня была аналогичная проблема. Ловушка здесь, вам нужно выдать $('select').material_select(); только после того, как DOM вашего приложения Vue будет готов. Таким образом, вы можете добавить готовый метод к вашему Vue-приложению и включить $('select').material_select(); в свой готовый метод.

var vm = new Vue({ 
data: function() { 
    locations: ["Clayton", "Mt Meigs", "Birmingham", "Helena", "Albertville", "Albertville", "Grant"] 
}, 
ready: function() { 
    $('select').material_select(); 
}}); 

Просто убедитесь, что вы включили Jquery, а затем materialize.js затем Vue.js в вашем HTML файле.

+0

Привет и спасибо за внимание. К сожалению, это не то, что я искал. У меня не было проблем с предоставлением материализовать поле выбора на странице. Вопрос состоял в том, «как получить выбранное значение параметра». Правильный ответ - «использовать специальную директиву». На данный момент я просто переключился на класс поля «браузер-по умолчанию». Когда я получу больше времени, я постараюсь создать директиву для обработки материализуемых выборок. – Desprit

0

Я хочу включить рабочую скрипту пользовательской директивы select2, которую я построил для своего проекта. Он также поддерживает несколько выбирает: fiddle

data: function() { 
    return { 
     names: [ 
     {id: 1, value: 'Alice'}, 
     {id: 1, value: 'Bob'}, 
     {id: 1, value: 'Simona'} 
    ], 
     myStudents: { 
     names: ['Alice', 'Bob'], 
    } 
    } 
}, 

directives: { 
    'select': { 
    twoWay: true, 
    params: ['options'], 
    bind: function() { 
     var self = this 
     $(this.el).select2().on('change', function() { 
     self.set($(self.el).val()) 
     }) 
    }, 
    update: function (value) { 
     $(this.el).val(value).trigger('change') 
    }, 
    }, 
}, 

<select multiple v-select="myStudents.names" name="names" v-model="myStudents.names"> 
    <option v-for="name in names" value="{{ name.value }}">{{ name.value }}</option> 
</select> 
+1

Итак, вы ответили на мой ответ и приняли его сами? :-) –

+0

@DenisMysenko Вы действительно думаете, что это основано на вашем ответе? И вы не видите различий? Даже если ваш ответ был близок, это не сработало для меня. Я провел много времени, проверяя множество разных примеров, чтобы, наконец, сделать код из официальных vue select2 docs. Вот почему я опубликовал новый ответ, в котором содержится не просто случайная копия, но также рабочая часть скрипта и html. Имеет ли это смысл? Хорошо для меня да, при поиске stackoverflow для ответа, я предпочитаю те, у которых есть живой пример. – Desprit

+0

это не «случайная копия-вставка», это рабочий фрагмент кода. и нет, нет никаких различий - директива такая же. Я не против, на самом деле, просто странно видеть такое поведение здесь;) –

6

Vue.js 2,0

Шаблон:

<div v-text="selected"></div> 
<material-select v-bind="selected = selected || options[0].value" v-model="selected"> 
    <option v-for="option in options" :value="option.value" v-text="option.name"></option> 
</material-select> 

Компонент:

"use strict"; 

Vue.component("material-select", { 
    template: '<select><slot></slot></select>', 
    props: ['value'], 
    watch: { 
     value: function (value) { 

      this.relaod(value); 
     } 
    }, 
    methods:{ 
     relaod : function (value) { 

      var select = $(this.$el); 

      select.val(value || this.value); 
      select.material_select('destroy'); 
      select.material_select(); 
     } 
    }, 
    mounted: function() { 

     var vm = this; 
     var select = $(this.$el); 

     select 
      .val(this.value) 
      .on('change', function() { 

       vm.$emit('input', this.value); 
      }); 

     select.material_select(); 
    }, 
    updated: function() { 

     this.relaod(); 
    }, 
    destroyed: function() { 

     $(this.$el).material_select('destroy'); 
    } 
}); 
2

Vue.directive('material-select', { 
 
     bind:function(el,binding,vnode){ 
 
      $(function() { 
 
       $(el).material_select(); 
 

 
      }); 
 
      var arg = binding.arg; 
 
      if(!arg)arg="change"; 
 
      arg = "on"+arg; 
 
      el[arg]=function() { 
 
      \t 
 
       if (binding.expression) { 
 
        if (binding.expression in vnode.context.$data) { 
 
         vnode.context.$data[binding.expression] = el.value; 
 

 
        } else if (vnode.context[binding.expression] && 
 
          vnode.context[binding.expression].length <= 1) { 
 
          vnode.context[binding.expression](el.value); 
 

 
        } else { 
 
         throw new Error('Directive v-' + binding.name + " can not take more than 1 argument"); 
 
        } 
 
        
 

 
       } 
 
       else { 
 
        throw new Error('Directive v-' + binding.name + " must take value"); 
 
       } 
 
      } 
 

 
     }, 
 
     unbind:function(el) { 
 
      $(el).material_select('destroy'); 
 
     } 
 
}); 
 

 

 
new Vue({ 
 
    el: '#exemple1', 
 
    data:function(){ 
 
    return { 
 
    \t selected: '', 
 
\t  options:[ 
 
\t   {value:"v1",text:'description 1'}, 
 
\t   {value:"v2",text:'description 2'}, 
 
\t   {value:"v3",text:'description 3'}, 
 
\t   {value:"v4",text:'description 4'}, 
 
\t   {value:"v5",text:'description 5'}, 
 
\t  ] 
 
\t } 
 
\t } 
 
}); 
 
     
 
new Vue({ 
 
    el: '#exemple2', 
 
    data:function() { 
 
    return{ 
 
    \t selected: null, 
 
\t  options:[ 
 
\t   {value:"v1",text:'description 1'}, 
 
\t   {value:"v2",text:'description 2'}, 
 
\t   {value:"v3",text:'description 3'}, 
 
\t   {value:"v4",text:'description 4'}, 
 
\t   {value:"v5",text:'description 5'}, 
 
\t  ] 
 
\t } 
 
    }, 
 
    methods:{ 
 
    change:function(value){ 
 
     this.selected = value; 
 
     alert(value); 
 
    } 
 
    } 
 
});
<link href="https://cdnjs.cloudflare.com/ajax/libs/materialize/0.98.0/css/materialize.min.css" rel="stylesheet"/> 
 
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script> 
 
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.1.10/vue.js"></script> 
 
<script src="https://cdnjs.cloudflare.com/ajax/libs/materialize/0.98.0/js/materialize.min.js"></script> 
 
<h4>vue js materialize</h4> 
 
<h5>Exemple1</h5> 
 
<div id="exemple1"> 
 
    <select v-material-select:change="selected" class="blue-text"> 
 
     <option value="" disabled selected ><slot>Defaut message</slot></option> 
 
     <option v-for="option in options" :value="option.value">{{ option.text}}</option> 
 
    </select> 
 
</div> 
 

 
<h5>Exemple2</h5> 
 
<div id="exemple2"> 
 
    <select v-material-select:change="change" class="blue-text"> 
 
     <option disabled selected ><slot>Choisir Votre Abonnement</slot></option> 
 
     <option v-for="option in options" :value="option.value">{{ option.text}}</option> 
 
    </select> 
 
</div>

+2

Пожалуйста, добавьте некоторые пояснения рядом с кодом. Код только ответы не приветствуются. – Alexei

2

Верхний ответ был хороший, но не работает в Vue 2.

Вот обновление, которое работает (вероятно, еще немного Hacky). Я переместил jQuery-hook в update(), так как функция bind называется слишком ранней для материализации.

Vue.directive("select", { 
    "twoWay": true, 

    update: function(el, binding, vnode) { 
     if(!vnode.elm.dataset.vueSelectReady) { 

      $(el).on('change', function() { 
       vnode.context.$set(vnode.context, binding.expression, el.value); 
      }); 

      $(el).material_select(); 
      vnode.elm.dataset.vueSelectReady = true 
     } 
    }, 

    unbind: function(el, binding, vnode) { 
     $(el).material_select('destroy'); 
    } 
}); 

HTML:

<select v-select=selected> 
    <option value="" disabled selected>Choose your option</option> 
    <option :value="item" v-for='item in items'>{{ item }}</option> 
    <label>Materialize Select</label> 
</select> 
+0

, к сожалению, это не сработает, если я не загружу параметры через v-html, прокручивая их, не будет повторно инициализировать выбор. Есть идеи? –

0

в- VueJs2.4 Ни один из вышеуказанных ответов не были для множественного выбора элемента. Я получил его, перейдя по параметрам выбора. Это не правильный подход, а хак, но работает.

Plunker

<h4>vue js materialize select</h4> 
     <div class="row" id="app" style="padding-bottom:2em;"> 
     <div class="input-field col s12 m8"> 
      <select multiple v-material-select:change="selected"> 
       <option value="AngularJs">AngularJs</option> 
       <option value="Bootstrap3">Bootstrap3</option> 
       <option value="Bootstrap4">Bootstrap4</option> 
       <option value="SCSS">SCSS</option> 
       <option value="Ionic">Ionic</option> 
       <option value="Angular2">Angular2</option> 
       <option value="Angular4">Angular4</option> 
       <option value="React">React</option> 
       <option value="React Native">React Native</option> 
       <option value="Html5">Html5</option> 
       <option value="CSS3">CSS3</option> 
       <option value="UI/UX">UI/UX</option> 
       </select> 
      <label>Technologies Used</label> 
     </div> 
     <h2>Your selected options</h2> 
     <p>{{$data.selected}}</p> 
     </div> 

     <script src="https://cdnjs.cloudflare.com/ajax/libs/materialize/0.100.2/js/materialize.min.js"></script> 
     <script src="https://unpkg.com/[email protected]/dist/vue.js"></script> 
     <script> Vue.directive("material-select", { 
    bind: function(el, binding, vnode) { 
     $(function() { 
     $(el).material_select(); 
     }); 
     var arg = binding.arg; 
     if (!arg) arg = "change"; 
     arg = "on" + arg; 
     el[arg] = function() { 
     vnode.context.$data.selected = []; 
     for (let i = 0; i < 12; i++) { 
      if (el[i].selected === true) { 
      vnode.context.$data.selected.push(el[i].value); 
      } 
     } 
     }; 
    }, 
    unbind: function(el) { 
     $(el).material_select("destroy"); 
    } 
    }); 
      var app = new Vue({el: "#app",data: { selected: []}, 
    ready: function() { 
      $("select").material_select(); }});</script> 
0

Возможное решение, которое я нашел, чтобы использовать вход, и прикрепить его к содержимому списка. Он отлично работает с vue, даже когда вы динамически создаете раскрывающийся список. И его реактивность, что вам не нужно выделять какое-либо другое событие для привязки значений.

Codepen: https://codepen.io/aaha/project/editor/DGJNLE

<style> 
    input{ 
     cursor: pointer; 
    } 
    .caret{ 
     float:right; 
     position: relative; 
     cursor: pointer; 
     top:-50px; 
    } 
    ul{ 
     width: 100%; 
    } 
</style> 
<script> 
    Vue.component('paper-dropdown', { 
      template: '<div> \ 
          <div class="input-field">\ 
          <input type="text" class="dropdown-button" v-bind:data-activates="_id"\ 
           v-bind:value="value"> \ 
          <label>{{label}}</label> \ 
          </div> \ 
          <i class="material-icons caret">arrow_drop_down</i>\ 
          <ul v-bind:id="_id" class="dropdown-content"> \ 
          <li v-for="item in options" v-on:click="setselected"><a v-bind:value="item">{{item}}</a></li> \ 
          </ul>\ 
         </div>', 
       watch: { 
        value: function(){ 
         Materialize.updateTextFields(); 
        } 
       }, 
       computed:{ 
        _id: function(){ 
         if(this.id != null) return this.id; 
         return Math.random().toString(36).substr(2); 
        } 
       }, 
       props: { 
        label:{ 
         type: [String, Number], 
         default: '' 
        }, 
        options:{ 
         type: Array, 
         default: [] 
        }, 
        placeholder:{ 
         type: String, 
         default: 'Choose your option' 
        }, 
        value:{ 
         type: String, 
         default: '' 
        }, 
        id:{ 
         type: String, 
         default: 'me' 
        } 
       }, 
       methods:{ 
        setselected: function(e){ 
         this.$emit('input', e.target.getAttribute("value"));     
        } 
       }, 
       mounted: function(){ 
        $('.dropdown-button').dropdown({ 
         inDuration: 300, 
         outDuration: 225, 
         constrainWidth: false, // Does not change width of dropdown to that of the activator 
         hover: false, // Activate on hover 
         gutter: 0, // Spacing from edge 
         belowOrigin: false, // Displays dropdown below the button 
         alignment: 'left', // Displays dropdown with edge aligned to the left of button 
         stopPropagation: false // Stops event propagation 
        } 
        ); 
       } 
      }); 
    </script> 
Смежные вопросы