又双叒一个uniapp组件

最近有一个选择地址的需求,就写了一个省市区联动选择器。

选择日期使用的picker,就照着它简单的整了一个,使用网络请求城市数据,还用到了vuex组件数据共享。

本来自己整了一个底部弹窗,又在插件市场看到了更好的底部弹窗 :LuPopupWrapper--弹窗容器, 所以就用了这个。

依然发布到了插件市场:http://ext.dcloud.net.cn/plugin?id=708

看一下效果吧

具体实现

css就不贴出来了,下载可以看到。

第一、底部弹出框

<view class="popup-layout-wrap" :class="popuplayoutClass" >
        <view class="popup-layout-content" :class="popupContentClass" :style="[{height:height}]">
            <slot>
            </slot>
        </view>
        <view v-if="maskShow" class="popup-layout-mask" @tap="close(maskClick)"></view>
</view>

 这里的底部弹出框用了插件市场的,简单的看一下布局。

slot插槽用于填充弹出框的内容。

最主要的就是弹出和关闭。属性就一个height,控制弹出的高度,其他的暂时不需要。

第二、上下滑动选择城市信息

分析一波:头部两个按钮,取消和确定。头部下面是选择的城市信息展示。再往下就是最重要的选择操作区。

     选择操作区分成三列,三列分别显示省市区,并且可滑动。当点击选择后,变为红色。

html代码

        <view class="link-address-wrap">
                <view class="link-adress-content">
                    <view class="head-wrap">
                        <text class="cancel" @click="btn_cancel">取消</text>
                        <text class="confirm" @click="btn_confirm">确认</text>
                    </view>
                    <view class="head-selected">
                        <text class="selected-txt">已选择:{{selected_address}}</text>
                    </view>
                    <view class="operation-wrap">
                        <view class="operation-container">
                            <view class="operation-content">
                                <scroll-view
                                    scroll-y="true"
                                    class="province"
                                    show-scrollbar="false">
                                    <view 
                                        :class="{'province-txt':index!==province_current,'province-txt-click':index===province_current}"  
                                        @click="province_txt_click(items.id)" 
                                        v-model="items.id" 
                                        v-for="(items , index) of linkAddress_province"
                                        >
                                            {{items.name}}
                                            <view class="pic" v-show="index===province_current">
                                                <image src="../../static/xuan-linkAddress/yes.png"></image>
                                            </view>
                                    </view>
                                </scroll-view>
                            </view>
                            <view class="operation-content">
                                <scroll-view
                                    scroll-y="true"
                                    class="province"
                                    show-scrollbar="false">
                                    <view 
                                        :class="{'province-txt':index!==city_current,'province-txt-click':index===city_current}"  
                                        @click="city_txt_click(items.id)" 
                                        v-model="items.id" 
                                        v-for="(items , index) of linkAddress_city"
                                        >
                                            {{items.name}}
                                            <view class="pic" v-show="index===city_current">
                                                <image src="../../static/xuan-linkAddress/yes.png"></image>
                                            </view>
                                    </view>
                                </scroll-view>
                            </view>
                            <view class="operation-content">
                                <scroll-view
                                    scroll-y="true"
                                    class="province"
                                    show-scrollbar="false">
                                    <view 
                                        :class="{'province-txt':index!==district_current,'province-txt-click':index===district_current}"  
                                        @click="district_txt_click(items.id)" 
                                        v-model="items.id" 
                                        v-for="(items , index) of linkAddress_district"
                                        >
                                            {{items.name}}
                                            <view class="pic" v-show="index===district_current">
                                                <image src="../../static/xuan-linkAddress/yes.png"></image>
                                            </view>
                                    </view>
                                </scroll-view>
                            </view>
                        </view>
                    </view>
                </view>
            </view>    

 其他的都不用说了,重要的是循环这里。

分为 未点击样式和点击样式。通过点击元素的index和id匹配来切换状态。

需要定义的变量

        data(){
            return{
                /*省市区选择计数*/
                province_current:null,
                city_current:null,
                district_current:null,
                
                /*省市区循环数据*/
                linkAddress_province: [],
                linkAddress_city: [],
                linkAddress_district: [],
                
                /*请求提交的*/
                submission:{
                    province:'',//
                    city:'',//
                    county:'',//
                    town:''//
                },
                /*用户选择的地址*/
                user_address:{
                    province:'',//
                    city:'',//
                    district:''//
                },
                selected_address:''
            };
        },        

弹窗显示的时候,去请求省的数据。点击省后请求对应省份的市。

js代码 只展示点击省的操作,其他的差不多

            //省点击选择
            province_txt_click(target){
                //区数据值为空
                this.linkAddress_district= [];
                //市、区的选择计数置为null
                this.city_current=null;
                this.district_current=null;
                
                let province;
                //得到点击的数据,改变样式
                for (let i = 0; i < this.linkAddress_province.length; i++) {
                    if (this.linkAddress_province[i].id === target) {
                        this.province_current = i;
                        province=this.linkAddress_province[i].name;
                        break;
                    }
                }
                //用户选择
                this.user_address={
                    province:province,
                    city:'',
                    district:''
                }
                //请求提交的数据先置为空
                this.submission={
                    province:'',
                    city:'',
                    county:'',
                    town:''
                };
                //再赋值
                this.submission.province=target;
                this.selected_address=this.user_address.province;
                //请求市数据
                linkAddress_p.get_linkAddress(this,"city",this.submission,(revert)=>{
                    
                });
            },                

 第三、网络请求

看官方文档的网络请求后封装一下

//网络请求
export default class Request{
    /*
    *paramete 拼接参数
    * data 参数值
    * method 请求方式
    */
    http(paramete,data,method){
        //根地址
        let BASE_API="http://admin.farmereasy.com";
        return new Promise((resolve,reject)=>{
            uni.request({
                url:`${BASE_API}${paramete}`,
                data:data,
                method:method,
                success:(res)=>{
                    resolve(res);
                },
                fail:(res)=>{
                    resolve(0);
                }
            })
        });
    }
}

 

import Request from "@/static/xuan-linkAddress/request.js"
//创建Request对象
let request=new Request();

export default{
    //data 参数值
    get_linkAddress_api:function(data){
        console.log(data);
        return request.http('/api/address/area',data,'GET');
    }
}

通过传入不同标签赋给不同的变量。

import api from '@/components/xuan-linkAddress/api.js';

export default {
    /*
    *_this:全局this
    * data:数据(参数)
    * callback:回掉页面
    */
    get_linkAddress: function(_this,tag,data,callback) {
        //请求
        api.get_linkAddress_api(data).then((res) => {
            let revert=res.data.data;
            console.log(revert)
            if(res.data.code==1){
                if(tag==="province"){    
                    console.log("province")
                    _this.linkAddress_province=revert;
                    callback(true);//回掉
                }
                if(tag==="city"){
                    console.log("city")
                    _this.linkAddress_city=revert;
                    callback(true);//回掉
                }
                if(tag==="district"){
                    console.log("district")
                    _this.linkAddress_district=revert;
                    callback(true);//回掉
                }
            }
        });
    }
}

组件就完成了,在具体的页面使用

<!-- html-->
   <!-- 用于弹出底部框-->
    <button class="popup-btn" @tap="popup_bottom()">请选择</button>
    <!-- 选择组件 -->
    <linkAddress
            ref="linkAddress"
            :height="height"
            @confirmCallback="confirmCallback()"
        >
    </linkAddress>


  <!-- js-->
  import linkAddress from '../../components/xuan-linkAddress/xuan-linkAddress.vue'
  components:{
        linkAddress
  },
  methods: {
        <!-- 点击弹出-->
        popup_bottom: function() {
            this.height = '550rpx';
            //显示
            this.show_popup();          
        },
        <!-- 显示弹窗-->
        show_popup: function() {
            this.$refs.linkAddress.show();
        },
        <!-- 回掉-->
        confirmCallback: function() {
                 //从vuex中取到用户选择的数据
            //let ads=this.$store.state.user_address;
            //this.address=ads.province+ads.city+ads.district;
        }   
  }

最后:很简单的一个组件,刚刚开始,希望大家多多包涵,共同学习。

GitHub地址:https://github.com/steffenx/uniapp_linkaddress