1. 程式人生 > >weex 實現仿ios 三級聯動地址選擇器

weex 實現仿ios 三級聯動地址選擇器

playground效果圖

這裡要實現一個weex 的 一個自定義的三級聯動元件,這裡囉嗦一句為什麼使用 vue 去自定義,一般使用weex的情況下,native也是支援原生擴充套件的,而且相對 android 和ios 各種第三方的元件選擇很多不少還很成熟,為什麼不直接使用呢。

這裡我使用weex的原則是能夠使用vue解決的問題一定不拋給native,原因如下,第一,使用vue 寫的ui能夠更好的保證android ios 的介面的統一性。第二,維護修改只需要維護一個地方,成本相對低很多,我們可能會遇到過這樣的情況,今天說好了我們是顏色是xxx等等,還沒有到下午,產品就要求換成另一個顏色,或者大小,如果是兩份 native的,就需要修改兩個地方了,相對就會麻煩很多,尤其是遇到更大的變動的時候,所以原則上,不到萬不得已,不適用native 的自定義元件

好了,下面說一下這個元件的實現,基於很多前端入手或者剛剛入門的同學基礎比較薄弱,所以會從最基礎的一步一步說明

第一: 資料,資料本來呢一般都是從伺服器獲取的省市區資訊(為什麼從伺服器去拿,因為這個地址一般是作為收貨地址等等的,伺服器需要做一些繫結等等的操作),這邊我們主要寫的是元件,所以資料就使用本地資料了
資料準備

引入資料

稍微解釋一下資料 ,省份列表就是一個 Array,裡面放了所有省份資訊
城市資料則是一個map,每一個省會對應n個市 通過省份的 recordid 去獲得的 value value則是一個市的 Array,區也是一樣,是一個map,拿市的id可以獲取到市下面的所有的區資訊

第二:UI
控制元件的ui,當顯示這個控制元件的時候有一層遮罩,遮罩上層顯示有三個並排的list 對應省市區的list,選擇完成之後點選確定,獲取到選擇的結果

<template>
  <div class="stories-view" append="tree" :style="{height:`${totalheight}px`}">
      <div class="list-mask" :style="{height:`${totalheight-80}px`}"  @click="unselectedaddress"></div>
<text class="addbutton basebutton" @click="selectedaddress" >確定</text> <div class="select-item" > <list class="listitem"> <cell v-for="(item, index) in proviceList" append="tree" @click="selectprovince(index)"> <text class="cityitem" :style="{color:(index === selectindex)?'#00BBE4':'gray'}">
{{item.name}} </text> </cell> </list> <list class="listitem"> <cell v-for="(item ,index) in cityList" append="tree" @click="selectcity(index)"> <text class="cityitem" :style="{color:(index === selectcityindex)?'#00BBE4':'gray'}"> {{item.name}} </text> </cell> </list> <list class="listitem"> <cell v-for="(item, index) in disList" append="tree" @click="selectdist(index)"> <text class="cityitem" :style="{color:(index === selectdisindex)?'#00BBE4':'gray'}"> {{item.name}} </text> </cell> </list> </div> </div> </template> <style> .stories-view { min-height:250px; overflow-y:auto; } .list-mask{ position: absolute; top: 0; left: 0; width: 750px; z-index: 10; background-color: black; opacity: 0.65; } .select-item{ flex-direction: row; flex-wrap: nowrap; position: absolute; background-color: white; align-items: center; justify-content: center center; bottom: 80px; height: 600px; width: 750px; z-index:101; opacity: 1; } .listitem{ max-height: 500px; margin-top: 20px; margin-bottom: 20px; width: 250px; max-height: 500px; flex-grow:1; } .cityitem{ color: gray; text-align: center; padding-top: 10px; padding-bottom: 10px; font-size: 32px; } .addbutton{ bottom: 0px; width:750px; padding-top: 18px; text-align: center; } .basebutton{ color:white; background-color: #00BBE4; position: absolute; font-size:32px; height:80px; } </style> <script> export default { props: { proviceList: { type: Array, required: true }, cityListMap: { type: Object, required: true }, disListMap: { type: Object, required: true } }, data() { return{ selectindex:0, selectcityindex:0, selectdisindex:0, cityList:[],//當前市列表 disList:[], // 當前區列表 selectedprovince:{}, selectedcity:{}, selecteddist:{}, } }, methods: { selectedaddress(){ // this.isselectaddress = false //關閉選擇框 this.selectplace = proviceList[this.selectindex].name+' '+ this.cityList[this.selectcityindex].name +' ' + this.disList[this.selectdisindex].name this.$emit('haveselectedaddress',this.selectplace); }, unselectedaddress(){ this.$emit('haveselectedaddress',''); }, selectprovince(index){ this.selectedprovince = this.proviceList[index] //顯示 市和區 this.cityList = this.cityListMap[this.proviceList[index].recordId] this.disList = this.disListMap[this.cityList[0].recordId] this.selectindex = index; }, selectcity(index){ this.selectedcity = this.cityList[index] //顯示區 this.disList = this.disListMap[this.cityList[index].recordId] this.selectcityindex = index }, selectdist(index){ this.selecteddist = this.disList[index] this.selectdisindex = index } }, computed: { totalheight(){ const height = 750/weex.config.env.deviceWidth*weex.config.env.deviceHeight console.error('height:'+height) return height } }, created(){ this.cityList = cityListMap[proviceList[this.selectindex].recordId] this.disList = disListMap[this.cityList[this.selectcityindex].recordId] } } </script>

上面是這個 控制元件的程式碼了,vue寫的少,格式不好莫要賤笑

第三:使用

<template>
  <div >
    <text class="title" @click="update" >{{date}}</text>
      <selectvue class="list-mask" v-if="isselectaddress" :proviceList="proviceList" :cityListMap="cityListMap" :disListMap="disListMap"  @haveselectedaddress="selectedaddress"></selectvue>
  </div>

</template>

<style>
  .title { font-size: 48px; }
  .list-mask{
    position: absolute;
    top: 0;
    left: 0;
    width: 750px;
    z-index: 10;
    background-color: black;
    opacity: 0.65;
  }  
</style>

<script>
  import selectvue from './compent/select_address.vue'

  export default {
    components:{selectvue},
    methods: {
      update(e) {
        this.isselectaddress = true
      },

      selectedaddress(evtValue){
        this.isselectaddress = false
        if(evtValue === ''){
          return
        }
        this.date = evtValue    
      }
    },
    data(){
      return{
        proviceList:[],
        cityListMap:{},
        disListMap:{},
        isselectaddress: false,
        date:'點選選擇地址'
      }
    },
    mounted(){
      this.proviceList = global.proviceList
      this.cityListMap = global.cityListMap
      this.disListMap = global.disListMap            
    }
  }
</script>

這裡是使用這個元件,有一點很重要,元件的位置 position: absolute;
一定要是absolute
剩下的就是 v-if 控制一下顯示了

tips
為了在playground 上面顯示,元件的高度需要減掉 180

  <div class="stories-view" append="tree" :style="{height:`${totalheight-180}px`}">

因為高度是有一個標題欄是原生的,需要把裝置的高度減去原生這部分的高度,否則顯示會不全,放到專案裡面使用就沒有問題了

元件的幾個小知識點
一個是傳值,通過 props

    props: {
      proviceList: {
        type: Array,
        required: true
      },
      cityListMap: {
        type: Object,
        required: true
      },
      disListMap: {
        type: Object,
        required: true
      }
    },   

當然這個可以用一個object,自己去優化啦
傳值的時候參考引用的介面

然後就是元件給頁面返回值,點選確定之後,需要把獲取到的省市區資訊返回給頁面來顯示,這裡有一個 $emit 提交,然後在父vue裡面監聽得到一下

      <selectvue class="list-mask" v-if="isselectaddress" :proviceList="proviceList" :cityListMap="cityListMap" :disListMap="disListMap"  @haveselectedaddress="selectedaddress"></selectvue>

selectedaddress 方法實現

      selectedaddress(evtValue){
        this.isselectaddress = false
        if(evtValue === ''){
          return
        }
        this.date = evtValue    
      }

好了,到這裡就已經完成這個簡單元件了