zoukankan      html  css  js  c++  java
  • vue2组件之select2调用

    目前,项目中使用了纯前端的静态项目+RESTFul接口的模式。为了更好的对数据进行操作,前端使用了vue2的mvvm功能,但是由于不是单页面应用,所以,并没有涉及到其它的如vue-route等功能,也未使用webpack等编译功能,所以,也没有使用.vue文件功能。这时候,如果用到控件,则多数从原jquery的组件中选择。

    select下拉搜索选择

    这次的需求调研与设计是原来做winform开发的同事,由于用惯了devexpress这个控件库,所以,对于searchlookupeditor这个控件情有独钟,所以,在设计的时候,许多地方都用到。

    最初实现

    最初,我使用了select2绑定select标签,设定其change事件 ,在事件中修改对应的vue的data值,同时,在vue中设定watch``data中被绑定的属性,属性值发生变化,则修改对应的dom的val,然后再触发select2的change事件。当然,这种对应关系,我在select标签上放了一个data-vuep来保存其与vue属性的对应关系,并放在全局的select2vuedom2vue中。

    //mounted中的部分代码
    					    select2vue = {};
    					$("select").each(function (index, item) {
    						var s2 = $(item).select2({
    							language: "zh-CN",  //设置 提示语言
    							 "100%", //设置下拉框的宽度
    							theme: "classic",
    							placeholder: "请选择"
    						}).on("change", function (e) {
    							console.log(e);
    							var v = $(e.target).val();
    							var p = $(e.target).attr("data-vuep");
    							eval("vue_cust_busi." + p + "='" + v + "';");
    							//$(e.target).find("option").attr("selected",false);
    							//$(e.target).find("option[value='"+v+"']").attr("selected",true);
    						});
    
    						var p = $(item).attr("data-vuep");
    						select2vue[p] = s2;
    						dom2vue[p] = item;
    					});
    					setTimeout(function(){
    						vue_cust_busi.editor.ID_CUST="3";
    						vue_cust_busi.editor.NAME_CUST="*有限责任公司";
    						console.log("修改");
    					},10,null);
    
    
    //watch中的部分代码
    					"temp.P1": function (val) {
    						fire(arguments.callee.name.toString(), val);
    
    					},
    //通用函数
    
    		function fire(p, val) {
    			$(dom2vue[p]).val(val);
    			select2vue[p].trigger("change");
    		}
    
    //html
    
    												<select data-vuep="editor.P1" class="form-control "> 
    														<option value="" ></option>    
    														<option v-for="yearOpt in yearOpts" v-bind:value="yearOpt">{{yearOpt}}</option> 
    												</select>
    

    为什么要用一个data-vuep来将数据与vue的属性关联呢,因为我发现,select2初始化了这个select标签之后,修改这个标签的值无法触发修改vue对应的v-model的属性。所以,只能用这个方法。
    最终形成的结果是:

    select2到vue.editor.P1:

    1. select2被选择某一项,触发其change事件。
    2. select2的change事件修改vue.editor.P1的值。
    3. vue.editor.P1的值被修改,触发watch,watch又引发select2的change事件,但是,select2内部监控到选择和之前的一致,所以,不再执行change事件的委托。

    上面这种流程一定程度是实现了数据的双向绑定,但是,非常复杂。在后续的使用中发现,在mounted中无法为select2默认值,必须在mounted中调用setTimeout生成一个定时执行的事件来执行数据绑定操作,才会触发上述流程,达到设定触始值的效果。

    使用vue指令

    经过一番挣扎,觉得上面这种方式还是不行。

    上述方案不好的原因如下:

    1. vue事件中的代码操作了dom,这样,在生命周期上可能会出现问题,特别是后来使用了setTimeout之后,生命周期变得更加不可控制。
    2. 每增加一个select组件,都需要增加 html标签、watch,而且,html 标签和watch既不是传统的写法,也不是vue的写法,而是发明了一种新的东西,这破坏了开发体验。
    3. 维护性比较差,当想删除一个select的时候,必须要去watch里面去找与html中data-vuep相等的属性监控方法,并将其删除掉。
    4. 兼容性不好,本方案选择将页面所有的select全部用select2初始化了一次,使得不论是否需要的,都会被影响;其次,如果不统一初始化,那么又多出了在mounted中为每一个select写初始化代码的工作,同时,也要为每个select取一个id。

    为了解决这个问题,我又找到了最初看到的那个vue使用指令和select2的整合的例子。网上有好多,我不知道版权是谁的,姑且上我最先看到的那个吧。http://blog.csdn.net/amohan/article/details/58651100

    原文中的代码如下:

    <!DOCTYPE html>
    <html>
    <head>
        <title>vue select2 封装</title>
        <link href="https://cdnjs.cloudflare.com/ajax/libs/select2/4.0.3/css/select2.min.css" rel="stylesheet" />
        <script src="https://unpkg.com/vue/dist/vue.js"></script>
        <script src="https://cdn.bootcss.com/jquery/2.2.4/jquery.js"></script>
        <script src="https://cdnjs.cloudflare.com/ajax/libs/select2/4.0.3/js/select2.min.js"></script>
        <style type="text/css">
            .content{
                text-align: center;
                padding:50px;
            }
            .content *{
                text-align: left;
            }
            .select{
                 350px;
            }
        </style>
    </head>
    <body>
        <div class="content" id="vue-example">
            <select class="select" v-select2='options' v-model="selectValue"></select>
            <br/>
            <span>结果:{{ selectValue }}</span>
        </div>
    </body>
    <script type="text/javascript">
        Vue.directive('select2', {
          inserted: function (el, binding, vnode) {
             let options = binding.value || {};
     
            $(el).select2(options).on("select2:select", (e) => {
              // v-model looks for
              //  - an event named "change"
              //  - a value with property path "$event.target.value"
                  el.dispatchEvent(new Event('change', { target: e.target })); //说好的双向绑定,竟然不安套路
            });
          },
          update: function(el, binding, vnode) {
            $(el).trigger("change");
          }
        });
     
        var vueApp = new Vue({
          el: "#vue-example",
          data: {
            selectValue: '你还没有选值',
            options: {
                data: [
                        { id: 0, text: 'enhancement' },
                    { id: 1, text: 'bug' },
                    { id: 2, text: 'duplicate' },
                    { id: 3, text: 'invalid' },
                    { id: 4, text: 'wontfix' }
                ]
            }
          }
        });
    </script>
    </html>
    

    作者也说了,对vue2.x的双向绑定机制不了解,希望路过的大神帮帮忙。
    我不是vue2的大神,甚至连新手都不算,只能说是初学者。我对代码进行了调整,当然,也是操作了dom,但是由于封装在指令里面了,使用人员不需要再次操作,不涉及到开发人员操作dom的情况,我还是可以接受的。

    
    		Vue.directive('select2', {
    			inserted: function (el, binding, vnode) {
    				let options = binding.value || {};
    
    				$(el).select2(options).on("select2:select", (e) => {
    					// v-model looks for
    					//  - an event named "change"
    					//  - a value with property path "$event.target.value"
    					el.dispatchEvent(new Event('change', { target: e.target })); //说好的双向绑定,竟然不安套路
    					console.log("fire change in insert");
    				});
    			},
    			update: function (el, binding, vnode) {
    				for (var i = 0; i < vnode.data.directives.length; i++) {
    					if (vnode.data.directives[i].name == "model") {
    						$(el).val(vnode.data.directives[i].value);
    						console.log("new value in update:"+vnode.data.directives[i].value);
    					}
    				}
    				$(el).trigger("change");
    				console.log("fire change in update");
    			}
    		});
    
    //html代码
    
    <select v-select2="" v-model="editor.P1" required="required" class="form-control ">
      <option value=""></option>
      <option v-for="item in codes" v-bind:value="item.NAME">{{item.NAME}}</option>
    </select>
    
    

    经过好几天的研究,终于我发现在作者原来的代码的update中,加入修改el的val值,然后再触发select2change事件,就可以了。而在使用方面,只需要给加一个v-select2即可,v-model以及option的配置都依照vue2的推荐方式,原封不动。之所以加了一个空的option是因为如果不加,默认select2是选择第一个选项的,但是,由于未知原因,与vue.editor.P1并不同步。

  • 相关阅读:
    A B
    hdu 4656 Evaluation [任意模数fft trick]
    bzoj 3451: Tyvj1953 Normal [fft 点分治 期望]
    bzoj 3509: [CodeChef] COUNTARI] [分块 生成函数]
    hdu 5730 Shell Necklace [分治fft | 多项式求逆]
    hdu 4609 3-idiots [fft 生成函数 计数]
    UVA 12633 Super Rooks on Chessboard [fft 生成函数]
    Codeforces Round #410 (Div. 2)
    形式幂级数 [学习笔记]
    Python 字符串前面加u,r,b,f的含义
  • 原文地址:https://www.cnblogs.com/ensleep/p/vue-select2.html
Copyright © 2011-2022 走看看