我們曾經經常會遇到需要選擇省市區的需求,我們可能是找一個插件來實現,但是有了vue之后,我們自己完全可以簡單的實現這個效果,并封裝為獨立的.vue組件,便于日后使用
我們今天來實現一個 利用vuejs開發的 省市區三聯動的組件 CitySelect.vue組件
首先來看一下最終的效果(沒有寫太多的樣式...)

組件所需要的省市區的JSON數據(已經封裝為commonjs模塊了): provinces.js
這個數據中有這樣幾個字段:
code: 當前省市區的編碼
sheng: 當前所在的省
name: 省市區的名字
level: 級別,省 level = 1, 市 level=2, 區/縣城 level = 3
di: 縣,市級別的區分
如何使用?
這里采用了 v-model暴露接口, 所以我們下拉選擇的值,你只需要在 v-model綁定的屬性中去拿即可
我們使用的字段是 cityInfo用于接收組件的數據, 組件為了返回足夠的數據, 它是一個對象
使用代碼示例 :
App.vue
<template> <div id="app"> <h5>vue 省市區三聯動 demo</h5> <city-select v-model="cityInfo"></city-select> <h6>v-model的值是 <code>{{ cityInfo }}</code></h6> <h6>從v-model得知,你選擇了 <i>{{ cityName }}</i></h6> </div></template><script> import CitySelect from './components/CitySelect.vue' export default { data() { return { cityInfo: '', } }, components: { CitySelect }, computed: { cityName() { const names = []; this.cityInfo.province && names.push(this.cityInfo.province.name + ' ') this.cityInfo.city && names.push(this.cityInfo.city.name + ' ') this.cityInfo.block && names.push(this.cityInfo.block.name + ' ') return names.join('') } } }</script><style lang="stylus"> h6 padding 10px border 1px dotted h6 i color #f00 border 1px dotted #ccc</style>cityName是我們需要展示的數據,作為一個計算屬性而存在,因為這個值是不斷變化的,從cityInfo中抽取出來的數據
下面我們來看一下組件的實現代碼
CitySelect.vue
<template> <div class="city-select"> <select v-model="selectedProvince" name="province"> <option v-for="(item, index) in provinces" v-if="item.level === 1" :value="item"> {{ item.name }} </option> </select> <select v-model="selectedCity" name="city"> <option v-for="(item, index) in cities" :value="item"> {{ item.name }} </option> </select> <select v-model="selectedBlock" name="block"> <option v-for="(item, index) in blocks" :value="item"> {{ item.name }} </option> </select> </div></template><script>/** * 省 市 區/縣城 三聯動選擇器*/import provinces from './provinces.js'import Vue from 'vue'export default { name: 'app', created() { // 數據初始化,默認選中北京市,默認選中第一個;北京市數據為總數據的前18個 let beijing = this.provinces.slice(0, 19) this.cities = beijing.filter(item => { if (item.level === 2) { return true } }) this.selectedCity = this.cities[0] this.blocks = beijing.filter(item => { if (item.level === 3) { return true } }) this.selectedBlock = this.blocks[0] }, watch: { selectedProvince(newVal, oldVal) { // 港澳臺數據只有一級,特殊處理 if (newVal.sheng === '71' || newVal.sheng === '81' || newVal.sheng === '82') { this.cities = [newVal] this.blocks = [newVal] } else { this.cities = this.provinces.filter(item => { if (item.level === 2 && item.sheng && newVal.sheng === item.sheng) { return true } }) } var _this = this // 此時在渲染DOM,渲染結束之后再選中第一個 Vue.nextTick(() => { _this.selectedCity = _this.cities[0] _this.$emit('input', _this.info) }) }, selectedBlock() { var _this = this Vue.nextTick(() => { _this.$emit('input', _this.info) }) }, selectedCity(newVal) { // 選擇了一個市,要選擇區了 di是城市的代表,sheng if (newVal.sheng === '71' || newVal.sheng === '81' || newVal.sheng === '82') { this.blocks = [newVal] this.cities = [newVal] } else { this.blocks = this.provinces.filter(item => { if (item.level === 3 && item.sheng && item.sheng == newVal.sheng && item.di === newVal.di && item.name !== '市轄區') { return true } }) } var _this = this Vue.nextTick(() => { _this.selectedBlock = _this.blocks[0] // 觸發與 v-model相關的 input事件 _this.$emit('input', _this.info) }) } }, computed: { info() { return { province: this.selectedProvince, city: this.selectedCity, block: this.selectedBlock } } }, data() { return { selectedProvince: provinces[0], selectedCity: 0, selectedBlock: 0, cities: 0, provinces, blocks: 0 } }}</script><style lang="stylus" scoped> .city-select select outline 0</style>組件關鍵點說明:
HTML模板采用三個 select下拉控件,分別具有v-model由于綁定選擇的數據,使用v-for遍歷省市區數據
data中的數據,分別是選中的省市區的值(對象形式); 以及當前這個省的城市,這個城市的區,見名知意
在create鉤子函數中我們進行了數據的初始化,默認我們顯示北京相關的信息,改變v-model對應的屬性值
實現三聯動的重點:
我們使用watch監測當前省市區的改變(v-model中綁定的數據),一旦省 有變化,就需要拉取這個省相關的數據,并且默認選中第一條數據; 市,區的變化類似。
在這里我們采用了 ES5中的filter來進行數據的過濾,我們只要把數據過濾出來了,vue自動幫我們重新渲染,所以我們只需要把重點放在數據的篩選上就可以了
v-model接口的暴露:
要將數據綁定到v-model所綁定的屬性上,需要通過觸發 input事件,參見 v-model的實現原理這篇文章
Vue.nextTick(() => { _this.$emit('input', _this.info) })也就是這行代碼實現了組件內部數據暴露的效果: v-model所綁定的cityInfo拿到了組件內部的值
這里的 nextTick類似于setTimeout實現的效果,可以在執行完其他任務(例如渲染DOM)之后再執行相應的回調,我們使用它,可以保證我們的下一步操作是在DOM渲染完畢之后再執行的,保證邏輯的正確性
以上就是本文的全部內容,希望本文的內容對大家的學習或者工作能帶來一定的幫助,同時也希望多多支持武林網!
新聞熱點
疑難解答