来源:
功能:起运港 与 目的港 来源于一张表,两个栏位为多对多关系,即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' }); } } });