weex 实现仿ios 三级联动地址选择器

来源:互联网 发布:java api1.8中文版 编辑:程序博客网 时间:2024/06/01 10:35

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          }

好了,到这里就已经完成这个简单组件了

资源下载地址

原创粉丝点击