來源:
功能:起運港 與 目的港 來源於一張表,兩個欄位爲多對多關係,即1個起運港可以對應多個目的港,1個目的港也可以對應多個起運港。兩個欄位下拉選項互爲限制條件。
難點:select2組件change事件要能與父級(即Vue)通信,並更新 起運港/目的港 拉下選項。vue不允許子組件更新父組價傳入的對象,即只允許數據單向流入(要用$emit。測試可傳v-model的input的value,傳遞其他父級傳入的對象提示不允許重寫父級變量)。
方案:vue通過v-mode將選中的值傳入select組件的props對象中,select中監聽input change事件,將選中的值通過$emit傳回父組件,在父級別(即vue)監聽(watch)選中的值,如果有變更,就去更新對方的下拉選項訪問(例如:監聽起運港,如果選了1,就去更新目的港綁定的下拉選項)
實現:
slect2組件定義:
Vue.component('select2', { props: ['value'], template: ` <select class="selector select2bs4" v-bind:name="name" > <slot></slot> </select> `, mounted: function () { var vm = this; $(this.$el) // init select2 .select2({ data: this.options }) .val(this.value) .trigger('change') // emit event on change. .on('change', function () { debugger; vm.$emit('input', this.value) }) }, watch: { value: function (value) { // update value $(this.$el) .val(value) .trigger('change'); }, options: function (options) { // update options $(this.$el).empty().select2({ data: options }) }, pods: function(pods){ this.pods=pods; } }, destroyed: function () { $(this.$el).off().select2('destroy') } })
html中使用select2組件:
<div class="form-row align-items-center" id ="app">
<div class="input-group col-md-5 col-sm-5">
<div class="input-group-prepend">
<label class="input-group-text" for="inputGroupSelect01">起運港</label>
</div>
<select2 :options="pols" v-model="targetPol" name="pol" id="poFrom">
<!-- <option selected>請選擇</option> -->
<option v-bind:value="item" v-for="item in pols">{{item}}
</select2>
</div>
<div class="input-group col-md-5 col-sm-5">
<div class="input-group-prepend">
<label class="input-group-text" for="inputGroupSelect01">目的港</label>
</div>
<select2 :options="pods" v-model="targetPod" name="pod" id="poTo">
<!-- <option selected>請選擇</option> -->
<option v-bind:value="item" v-for="item in pods">{{item}}
</select2>
</div>
<div class="input-group col-md-1 col-sm-1">
<div class="input-group-prepend">
<span v-on:click="clearSearch()" class="fas fa-redo" title="重置"></span>
</div>
</div>
<div class="input-group col-md-1 col-sm-1">
<div class="input-group-prepend">
<input type="button" v-on:click="search()" class="btn btn-primary " value="查詢"></input>
</div>
</div>
</div>
<script>
$(function () {
//Initialize Select2 Elements
$('.select2bs4').select2({
theme: 'bootstrap4'
})
})
</script>
vue實現:
var app = new Vue({ el: '#app', //template: '#demo-template', data: { pos: [ { "from": "1", "to": "11" }, { "from": "1", "to": "12" }, { "from": "1", "to": "13" }, { "from": "1", "to": "14" }, { "from": "101", "to": "14" }, { "from": "102", "to": "13" } , { "from": "2", "to": "21" }, { "from": "2", "to": "22" } , { "from": "3", "to": "31" }, { "from": "3", "to": "32" }, { "from": "3", "to": "33" } , { "from": "4", "to": "41" } ], pols: [], pods: [], showPOL: true, showPOD: true, targetPol: -1, targetPod: -1 }, mounted: function () { //1,載入時實現 var polsSet = new Set() var podsSet = new Set() for (var item in this.pos) { polsSet.add(this.pos[item].from); podsSet.add(this.pos[item].to); } this.pols = Array.from(polsSet); this.pods = Array.from(podsSet); }, watch: { //監聽起運港,更新目的港 targetPol: function (val) { var podsSet = new Set() this.pos.forEach(function (item, index) { if (item.from == val) { podsSet.add(item.to); } }) $("#poTo").empty();//先清空所有數據,否則帶出的下拉值會有重複復 $('#poTo').select2({ data:Array.from(podsSet), theme: 'bootstrap4' }); }, //監聽目的港,更新起運港 targetPod: function (val) { var poddSet = new Set() this.pos.forEach(function (item, index) { if (item.to == val) { poddSet.add(item.from); } }) $("#poFrom").empty();//先清空所有數據,否則帶出的下拉值會有重複復 $('#poFrom').select2({ data:Array.from(poddSet), theme: 'bootstrap4' }); } }, methods: { search: function (obj, evt) { }, clearSearch: function (obj, evt) { debugger; //重新載入起始港與目的港 $("#poFrom").empty();//先清空所有數據,否則帶出的下拉值會有重複復 $('#poFrom').select2({ data:this.pols, theme: 'bootstrap4' }); $("#poTo").empty();//先清空所有數據,否則帶出的下拉值會有重複復 $('#poTo').select2({ data:this.pods, theme: 'bootstrap4' }); } } });