【问题标题】:Vuejs + Materializecss select fieldVuejs + Materializecss 选择字段
【发布时间】:2015-11-14 01:17:49
【问题描述】:

我的模板中有这段代码:

<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(); 将默认选择字段转换为可爱的东西。它还能做什么 - 它用&lt;ul&gt; 和&lt;li&gt; 替换&lt;select&gt; 和&lt;option&gt; 标签。 因此,我无法在 ViewModel js 文件中访问 item.size 的值。我什至尝试侦听单击选项字段并调用 optionClicked 方法(然后应该简单地提醒一条消息),尝试侦听 selectChaned。什么都没有。

如何在 ViewModel 中获取选项值?

附言仅供参考:我只有选择字段有问题。例如输入字段可以正常工作:

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

在 ViewModel 中我可以访问 item.name

【问题讨论】:

  • 能举个jsfiddle、jsbin等的例子吗?

标签: vue.js materialize


【解决方案1】:

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-select 而不是 v-model 绑定

【讨论】:

  • this 引用指向bind、update 和unbind 方法中的window。难以设置值。你用的是最新版的vue吗?
  • @EnmanuelRivera 不,这是用以前的 Vue 版本完成的,而不是当前版本
【解决方案2】:

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');
    }
});

【讨论】:

    【解决方案3】:

    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>

    【讨论】:

    • 请在代码旁边添加一些解释。不欢迎纯代码回答。
    【解决方案4】:

    最佳答案很好,但不适用于 Vue 2。

    这是一个有效的更新(可能还是有点老套)。我将 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>
    

    【讨论】:

    • 遗憾的是,除非我通过 v-html 加载选项,否则这不起作用,循环通过它们不会重新初始化选择。有什么想法吗?
    【解决方案5】:

    您可以通过简单的 hack 使 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 版本,则用于初始化选择的函数名称会有所不同。

    【讨论】:

      【解决方案6】:

      我遇到了类似的问题。这里要注意的是,只有在 Vue 应用程序的 DOM 准备好之后,您才需要发出 $('select').material_select();。因此,您可以在 Vue 应用程序中添加一个 ready 方法,并在您的 ready 方法中包含 $('select').material_select();。

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

      只要确保在您的 html 文件中首先包含 Jquery,然后是 materialize.js,然后是 Vue.js。

      【讨论】:

      • 您好,感谢您的关注。不幸的是,这不是我想要的。我在页面上渲染物化选择字段没有问题。问题是“如何获得选定的选项值”。正确的答案是“使用自定义指令”。现在我刚刚切换到“浏览器默认”选择字段类。当我有更多时间时,我将尝试构建一个指令来处理物化选择。
      【解决方案7】:

      我想包含一个我为我的项目构建的自定义 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>
      

      【讨论】:

      • 所以你根据我的回答做了一个回答并自己接受了? :-)
      • @DenisMysenko 你真的认为这是基于你的回答吗?你没有看到差异吗?即使您的答案很接近,它对我也不起作用。我花了很多时间检查许多不同的示例,最终使官方 vue select2 文档中的代码工作。这就是为什么我发布了一个新答案,不仅提供了一些随机复制粘贴,还提供了工作小提琴和 html 部分。是否有意义?对我来说是的,在 stackoverflow 中搜索答案时,我更喜欢那些有实例的。
      • 这不是“随机复制粘贴”,而是一段工作代码。不,没有区别-指令是相同的。我真的不介意,在这里看到这种行为很奇怪;)
      • 不,它不是一段工作代码。想展示一个工作吗?附加小提琴、jsbin 或任何你使用的东西。所有的 vue select2 实现看起来都非常相似,几乎相同,并且将其中一个称为您的实现只是自私。是的,确实存在差异,我相信您可以找到它们。
      • Desprit,您询问应该如何使用 Vue.js 实现 MaterializeCSS 选择输入元素。 @Denis Mysenko 然后给你一个工作指令(我刚刚测试过它,至少它对我来说很好用)。然后你继续用“select2”复选框的代码回答你的问题。总而言之,我的观点是,您没有将最相关的答案标记为正确答案,而是回答了另一个问题(“如何为 select2 复选框编写 Vue.js 指令?”)并将您的答案标记为正确的一个。我希望你明白为什么 Denis Mysenko 觉得这有点奇怪。 :)
      【解决方案8】:

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

      【讨论】:

        【解决方案9】:

        我发现的可能解决方案是使用输入,并将其附加到下拉内容。即使在动态创建下拉菜单时,它也能很好地与 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>
        

        【讨论】:

          【解决方案10】:

          我做了一些更简单的事情,只是在挂载上:

          ....
          mounted() {
            $(this.$el)
              .find(".mdb-select")
              .material_select();
          
            const self = this;
            $(this.$el).on("change", function(e) {
              self.$emit('input', this.inputValue);
            });
          },
          .....
          

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2018-04-12
            • 2023-03-15
            • 1970-01-01
            • 1970-01-01
            • 2016-06-27
            • 2020-11-23
            相关资源
            最近更新 更多