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",  //設置 提示語言
							width: "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{
            width: 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並不同步。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM