uniapp开发微信小程序底部地区选择弹框

个人项目地址: SubTopH前端开发个人站

(自己开发的前端功能和UI组件,一些有趣的小功能,感兴趣的伙伴可以访问,欢迎提出更好的想法,私信沟通,网站属于静态页面)

SubTopH前端开发个人站https://subtop.gitee.io/subtoph.github.io/#/home

以上 👆 是个人前端项目,欢迎提出您的建议😊

实现效果

功能介绍:

  1. 支持默认值直接显示滚动定位
  2. 选择上一次后,下一级重置请选择
  3. 选中样式可自定义
  4. 点击确认可校验省市县时候全部选择

 直接上代码模板部分(利用uniapp中的picker-view进一步封装)

<template>
  <view>
    <view
      class="tui-actionsheet-class tui-actionsheet"
      :class="[show ? 'tui-actionsheet-show' : '']"
    >
      <view class="regional-selection">
        <view class="selection-top">
          <text class="top-title">请选择地址区域</text>
          <image
            src="/static/image/bar-close.png"
            class="close-img"
            @tap="handleClickMask"
          />
        </view>
        <view class="selection-title">
          <text>省份</text>
          <text>城市</text>
          <text>区县</text>
        </view>
        <!-- 区域滚动选择 -->
        <picker-view
          class="picker-view"
          indicator-style="height:40px"
          mask-style="background-image: linear-gradient(to top, #ffffffcc,#fff, #fff)"
          @change="bindPickerChange"
          :value="value"
        >
          <!-- 省 -->
          <picker-view-column>
            <view
              class="item"
              :class="{ active: activeProvince === index }"
              v-for="(item, index) in provinces"
              :key="item.key"
              >{{ item.label }}</view
            >
          </picker-view-column>
          <!-- 市 -->
          <picker-view-column>
            <view
              class="item"
              :class="{ active: activeCity === index }"
              v-for="(item, index) in citys"
              :key="item.key"
              >{{ item.label }}</view
            >
          </picker-view-column>
          <!-- 县 -->
          <picker-view-column>
            <view
              class="item"
              :class="{ active: activeCounty === index }"
              v-for="(item, index) in countys"
              :key="item.key"
              >{{ item.label }}</view
            >
          </picker-view-column>
        </picker-view>
        <button type="default" class="confirm-btn" @click="confirmSelect">
          确认
        </button>
      </view>
    </view>
    <!-- 遮罩层 -->
    <view
      class="tui-actionsheet-mask"
      :class="[show ? 'tui-mask-show' : '']"
      @tap="handleClickMask"
    ></view>
  </view>
</template>

javaScript部分代码

<script>
import { reactive, toRefs, onBeforeMount, onMounted, nextTick } from "vue";
import { different } from "@/utils/common.js";
import {
  getEconomize,
  getMarket,
  getCounty,
} from "@/api/modules/common.api.js";   
// 以上省市县的接口,可根据开发实际情况前端写死或者后端请求数据
export default {
  name: "tuiActionsheet",
  props: {
    //点击遮罩 是否可关闭
    maskClosable: {
      type: Boolean,
      default: true,
    },
    //显示操作菜单
    show: {
      type: Boolean,
      default: false,
    },
    // 初始化显示的地区
    currentAddress: {
      type: Array,
    },
  },
  setup(props, ctx) {
    watch(
      () => props.show,
      (val) => {
        if (val) {
          data.provinces = [{ key: "0", label: "请选择" }];
          data.citys = [{ key: "1", label: "请选择" }];
          data.countys = [{ key: "2", label: "请选择" }];
          data.inCurrentAddress = props.currentAddress;
          inGetEconomize();
        }
      }
    );

    const data = reactive({
      inCurrentAddress: [],
      value: [0, 0, 0],
      provinces: [{ key: "0", label: "请选择" }],
      citys: [{ key: "1", label: "请选择" }],
      allCitys: [], //保存已请求的数据
      countys: [{ key: "2", label: "请选择" }],
      allCountys: [],
      activeProvince: 0,
      activeCity: 0,
      activeCounty: 0,
    });
    onBeforeMount(() => {});
    onMounted(() => {});
    // 获取省
    const inGetEconomize = () => {
      // 获取省数据
      getEconomize({ data: {} }).then((res) => {
        if (res.code) return;
        data.provinces.push(...res.data);
        dataHandle("provinces", 0);
      });
    };
    // 获取市
    const inGetCitys = (code) => {
      getMarket({ data: { marketCode: code } }).then((res) => {
        if (res.code) return;
        data.citys.push(...res.data);
        dataHandle("citys", 1);
      });
    };
    // 获取县
    const inGetCountys = (code) => {
      getCounty({ data: { countyCode: code } }).then((res) => {
        if (res.code) return;
        data.countys.push(...res.data);
        dataHandle("countys", 2);
      });
    };
    const dataHandle = (attribute, col) => {
      // data[attribute].unshift();
      const echo = data.inCurrentAddress[col];
      let index = data[attribute].findIndex((item) => item.label === echo);
      index = index < 0 ? 0 : index;
      setActiveStyle(col, index);
      const key = data[attribute][index].key;
      if (col === 0) {
        inGetCitys(key); //获取市
      }
      if (col === 1) {
        inGetCountys(key); //获取县
      }
    };
    // 设置选中值和样式
    const setActiveStyle = (column, index) => {
      nextTick(() => {
        // 设置初始化选中
        data.value[column] = index;
        setActiveValue(data.value);
      });
    };
    // 滚动选择
    const bindPickerChange = (e) => {
      const changeIndex = different(data.value, e.detail.value);
      data.value = e.detail.value;
      setActiveValue(data.value);
      changeSelectHandle(changeIndex);
    };
    const changeSelectHandle = (index) => {
      if (index === 0) {
        data.citys = data.citys.splice(0, 1);
        inGetCitys(data.provinces[data.value[0]].key); //获取市
      }
      if (index === 1) {
        data.countys = data.countys.splice(0, 1);
        if (data.citys.length) {
          inGetCountys(data.citys[data.value[1]].key); //获取县
        }
      }
    };
    // 设置选中项的index控制选中样式
    const setActiveValue = (arr) => {
      data.activeProvince = arr[0];
      data.activeCity = arr[1];
      data.activeCounty = arr[2];
    };
    // 确认选择
    const confirmSelect = () => {
      const { provinces, citys, countys, value } = data;
      const index = value.indexOf(0);
      if (index !== -1) {
        let msg;
        switch (index) {
          case 1:
            msg = "请选择城市";
            break;
          case 2:
            msg = "请选择区县";
            break;
          default:
            msg = "请选择省份";
        }

        uni.showToast({
          icon: "none",
          title: msg,
        });
      } else {
        const confirmArr = [
          provinces[value[0]],
          citys[value[1]],
          countys[value[2]],
        ];
        ctx.emit("confirm", confirmArr);
        handleClickCancel();
      }
    };
    // 点击遮罩层
    const handleClickMask = () => {
      if (!props.maskClosable) return;
      handleClickCancel();
    };
    // 点击取消
    const handleClickCancel = () => {
      ctx.emit("chooseCancel");
    };
    return {
      confirmSelect,
      handleClickMask,
      handleClickCancel,
      bindPickerChange,
      ...toRefs(data),
    };
  },
};
</script>

different方法判断数组中某个值的改变下标

export const different = (arr1, arr2) => {
    let index
    for (let i = 0; i < arr1.length; i++) {
        if (arr1[i] !== arr2[i]) {
            index = i
        }
    }
    return index
}

css样式代码


<style scoped lang="less">
.tui-actionsheet {
  width: 100%;
  position: fixed;
  left: 0;
  right: 0;
  bottom: 0;
  z-index: 9999;
  visibility: hidden;
  transform: translate3d(0, 100%, 0);
  transform-origin: center;
  transition: all 0.3s ease-in-out;
  // background: #eaeaec;
  min-height: 100rpx;
}

.tui-actionsheet-show {
  transform: translate3d(0, 0, 0);
  visibility: visible;
}
.regional-selection {
  position: relative;
  text-align: center;
  height: 818rpx;
  background: #fff;
  border-radius: 32rpx 32rpx 2rpx 2rpx;
  overflow: hidden;
  .selection-top {
    height: 100rpx;
    line-height: 100rpx;
    position: absolute;
    top: 0;
    z-index: 9999;
    width: 100%;
    border-bottom: 1rpx solid #f4f6f9;
    .top-title {
      text-align: center;
      font-size: 30rpx;
      color: #262626;
      font-weight: 600;
    }
    .close-img {
      position: absolute;
      width: 50rpx;
      height: 50rpx;
      right: 24rpx;
      top: 25rpx;
    }
  }
  .selection-title {
    position: absolute;
    top: 100rpx;
    height: 100rpx;
    line-height: 100rpx;
    z-index: 9999;
    width: 100%;
    font-size: 30rpx;
    display: flex;
    color: #262626;
    justify-content: space-around;
  }
  .picker-view {
    width: 750rpx;
    height: 560rpx;
    margin-top: 20px;

    /deep/.uni-picker-view-content {
      padding: 0rpx 0 !important;
    }
    .item {
      height: 40px !important;
      line-height: 40px;
      text-align: center;
      font-size: 26rpx;
      color: #606266;
      font-weight: normal !important;
      &.active {
        color: #0080ff;
        font-size: 30rpx;
      }
    }
  }

  .confirm-btn {
    margin-top: 30rpx;
    height: 88rpx;
    width: 690rpx;
    font-size: 30rpx;
    border-radius: 16rpx;
    line-height: 88rpx;
    background: #0080ff;
    color: #fff;
    &::after {
      border: none;
    }
  }
}

.tui-actionsheet-mask {
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  bottom: 0;
  background: rgba(0, 0, 0, 0.6);
  z-index: 9996;
  transition: all 0.3s ease-in-out;
  opacity: 0;
  visibility: hidden;
}

.tui-mask-show {
  opacity: 1;
  visibility: visible;
}
</style>

效果预览

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值