Vuejs + Materializecss选择字段

时间:2015-11-14 01:17:49

标签: vue.js materialize

我的模板中有这个代码:

<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>

根据Materialisecss文档,我调用$('select').material_select();将默认选择字段转换为可爱的字段。它的作用是什么 - 它用<select><option>替换<ul><li>标签。 因此,我无法在ViewModel js文件中访问 item.size 的值。我甚至试图听一下选项字段的点击并调用optionClicked方法(这应该只是提醒一条消息),试图听取selectChaned。什么都没有。

如何在ViewModel中获取选项值?

P.S。仅供参考:我只对选择字段有疑问。例如,输入字段工作正常:

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

在ViewModel中,我可以访问item.name

10 个答案:

答案 0 :(得分:11)

似乎Materialise不会发送任何事件,所以我找不到一个优雅的解决方案。但似乎以下V​​uejs指令+ 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中 - bind&lt; select&gt;使用v-select而不是v-model。

答案 1 :(得分:7)

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 :(得分: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() {
            	
                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 {
    	selected: '',
	    options:[
	        {value:"v1",text:'description 1'},
	        {value:"v2",text:'description 2'},
	        {value:"v3",text:'description 3'},
	        {value:"v4",text:'description 4'},
	        {value:"v5",text:'description 5'},
	    ]
	  }
	}
});
      
new Vue({
  el: '#exemple2',
  data:function() {
    return{
    	selected: null,
	    options:[
	        {value:"v1",text:'description 1'},
	        {value:"v2",text:'description 2'},
	        {value:"v3",text:'description 3'},
	        {value:"v4",text:'description 4'},
	        {value:"v5",text:'description 5'},
	    ]
	}
  },
  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>

答案 3 :(得分:2)

最佳答案很好,但对Vue 2不起作用。

这是一个有效的更新(可能仍然有点hacky)。我将jQuery挂钩移动到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>

答案 4 :(得分:1)

您可以通过简单的技巧在Vue + Materializecss中进行动态选择

$('#select').val(1).material_select(); // Set value and reinitialize materializecss select

mounted () {
   $("#select").change(function(){
            this.update_result.category = $("#select").val();
        }.bind(this)); // To set the user selected value to the data property 
   update_result.
}

如果您使用meterializecss beta版本,则用于初始化选择的函数名称将有所不同。

答案 5 :(得分:0)

我有类似的问题。这里的问题是,只有在Vue应用程序的DOM准备就绪后才需要发出$('select').material_select();。因此,您可以为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,然后在html文件中包含materialize.js后跟Vue.js。

答案 6 :(得分: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>

答案 7 :(得分:0)

v- VueJs2.4 上述答案都不是针对多个选择元素的。我通过遍历select元素选项来实现它。这不是一个正确的方法和一种黑客,但有效。

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/vue@2.4.4/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>

答案 8 :(得分: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>

答案 9 :(得分:0)

我做了一些简单得多的事情,只是在安装好的情况下:

....
mounted() {
  $(this.$el)
    .find(".mdb-select")
    .material_select();

  const self = this;
  $(this.$el).on("change", function(e) {
    self.$emit('input', this.inputValue);
  });
},
.....