1. 需求描述:
区域三级列表, 有添加,编辑,删除功能。
- 选择父级分类,其下子类全部选中,当前分类后加标志显示全字样
- 取消选中子类,其父类分类后标志显示选中数量
- 若子类全部选中,除当前父类标志是全字外,显示页面只显示当前父类
- 清除则清空选中结果
- 后台提交数据传参说明:
- 如果子类全部选择,只传父类
code
- 如果子类没有全部选择,传父类
code
+子类code
- 如果子类全部选择,只传父类
示例:
- 选择数据
- 河北省下:
1.石家庄市子类全部选中,
2.唐山市子类选择桥西区、长安区
页面显示:
- 河北 石家庄
- 河北 唐山市 桥西区
- 河北 唐山市 长安区- 山西省:(假设山西省下只有大同市和太原市)
1. 太原市子类全部选中
2. 大同市子类全部选中
页面显示:
- 山西省
- 传输参数
data: [ {one: ‘130000’, two: '130100'}, {one: ‘130000’, two: '130200', three: '130201'}, {one: ‘130000’, two: '130200', three: '130202'}, {one: ‘140000’} ]
2. 效果图:
3. 代码
- 主页面:
show.wxml
中
<!-- 选择地区 -->
<view class="recycle-container">
<view class="title">
选择地区
<view class="option-btn" bind:tap="toEditArea" wx:if="{{areaList.length}}">
<view class="option-icon">+</view>
<text class="option-text">去编辑</text>
</view>
</view>
<view class="explain">选择您的地区</view>
<view class='msgHint-content max-height'>
<view class="msgHint-content-item" wx:for="{{areaList}}" wx:key="id">
<view class="account-content">{{item.zone_name}}</view>
<text
class="option-text"
data-_id="{{item.id}}"
bind:tap="delArea"
>删除</text>
</view>
</view>
<!-- 去添加 -->
<view wx:if="{{!areaList.length}}" class="plus-container" bind:tap="addArea">
<view class="plus-content">+</view>
<view class="plus-text">去添加</view>
</view>
<!-- 操作 -->
<view class="msgHint-content" wx:else>
</view>
</view>
- 添加区域页面
area.wxml
<!-- 内容区 -->
<view class="area-container">
<!-- 省 -->
<scroll-view
class="white-container scroll-container"
scroll-y="{{true}}"
enhanced="{{true}}"
show-scrollbar="{{false}}"
>
<view
wx:for="{{areaList}}"
wx:key="index"
data-idx="{{index}}"
class="scroll-item {{ index === provinceCurrentIdx ? 'left-container': ''}} {{ item.is_choice ? 'scroll-item-active': ''}}"
bind:tap="provinceClick"
>
{{ item.name }}
<view class="item-sign" wx:if="{{item.signName}}">
{{item.signName}}
</view>
</view>
</scroll-view>
<!-- 市 -->
<scroll-view
class="white-container scroll-container"
scroll-y="{{true}}"
enhanced="{{true}}"
show-scrollbar="{{false}}"
>
<view
wx:for="{{cityList}}"
wx:key="index"
data-idx="{{index}}"
class="scroll-item {{ index === cityCurrentIdx ? 'left-container': ''}} {{item.is_choice ? 'scroll-item-active' : ''}}"
bind:tap="cityClick"
>
{{ item.name }}
<view class="item-sign" wx:if="{{item.signName}}">
{{item.signName}}
</view>
</view>
</scroll-view>
<!-- 区县 -->
<scroll-view
class="white-container scroll-container"
scroll-y="{{true}}"
enhanced="{{true}}"
show-scrollbar="{{false}}"
>
<view
wx:for="{{townList}}"
wx:key="index"
data-idx="{{index}}"
class="scroll-item {{ item.is_choice ? 'scroll-item-active': ''}}"
bind:tap="townClick"
>
{{ item.name }}
</view>
</scroll-view>
</view>
<!-- 底部 -->
<view class="footer">
<view class="options-container">
<button class="cancel-btn" bind:tap="cancel">清除</button>
<button class="sure-btn" type="primary" bind:tap="sure">确定</button>
</view>
</view>
- 区域操作页面:
area.js
:
const app = getApp()
const {throttle} = require('../../../utils/throttle')
Page({
/**
* 页面的初始数据
*/
data: {
// 省数据
areaList: [],
// 省当前选中索引值
provinceCurrentIdx: 0,
// 市数据
cityList: [],
// 市当前选中索引值
cityCurrentIdx: 0,
// 区县数据
townList: [],
},
// 清除
cancel(){
const {areaList, cityList, townList} = this.data
areaList.map(one => {
one.isSelect = 0
one.signName = ''
if(!one.children || !one.children.length) return
one.children.map(two => {
two.isSelect = 0
two.signName = ''
if(!two.children || !two.children.length) return
two.children.map(three => {
three.isSelect = 0
})
})
})
cityList.map(item=> {item.isSelect = 0; item.signName = ''})
townList.map(item=> item.isSelect = 0)
this.setData({
areaList,
cityList,
townList
})
},
// 注册节流事件
throttle(){},
// 点击确定,调取节流
sure(){
this.throttle()
},
// 保存
save(){
const selectArea = this.data.areaList.filter(item => item.isSelect)
if(!selectArea.length){
return wx.showToast({
title: '请选择地区',
icon: 'none'
})
}
// 处理参数并返回结果
const params =this.getParams(selectArea)
// todo 可注释请求,查看结果
wx.request({
url: "",
header: {},
data: {
data: params
},
method: 'POST',
success: function(res) {
}
})
},
getParams(arr){
const params = []
arr.map(one => {
// 若省无子集
if(!one.children || !one.children.length){
return params.push({one: one.code})
}
const twoAreas = one.children.filter(item => item.isSelect)
const isAll = twoAreas.every(two => (two.signName+'').localeCompare('全') === 0)
if((twoAreas.length === one.children.length) && isAll){
return params.push({one: one.code})
}
twoAreas.map(two => {
// 选中的市若无子集
if(!two.children || !two.children.length){
return params.push({one: one.code, two: two.code})
}
const threeAreas = two.children.filter(item => item.isSelect)
if(threeAreas.length === two.children.length){
return params.push({one: one.code, two: two.code})
}
// 区县集
threeAreas.map(three => {
params.push({one: one.code, two: two.code, three: three.code})
})
})
})
return JSON.stringify(params)
},
/**
* 生命周期函数--监听页面加载
*/
onLoad(options) {
this.throttle = throttle(this.save, 2000)
},
onShow() {
this.getArea()
},
// 获取地区
getArea(){
const _this = this
// todo 可注释请求,只做虚拟数据操作
// _this.valuation(datalist)
// _this.initShow(datalist)
wx.request({
url: "",
header: {},
data: {},
method: 'POST',
success: function(res) {
if (res.statusCode == 200) {
if(res.data.code == 200){
const arr = [...数据]
const datalist = arr.map(item => {
item.signName = ''
return item
})
// 回显地区
_this.valuation(datalist)
_this.initShow(datalist)
} else {
wx.showToast({
title: res.data.msg,
icon: 'none'
})
}
}
}
})
},
// 地区回显
valuation(datalist){
const selectList = datalist.filter(item=> item.isSelect)
if(!selectList.length){
return
}
selectList.map(one=>{
if(!one.children || !one.children.length){
one.signName = '全'
return
}
const selectTwo = one.children.filter(two => two.isSelect)
one.signName = selectTwo.length === one.children.length
? '全'
: selectTwo.length
one.children.map(two => {
if(!two.children || !two.children.length){
two.signName = '全'
return
}
const selectThree = two.children.filter(three => three.isSelect)
two.signName = selectThree.length === two.children.length
? '全'
: selectThree.length
})
})
},
// 定位点击省市区并初始加载
initShow(datalist){
const provinceCurrentIdx = datalist.findIndex(item => item.isSelect)
if(provinceCurrentIdx === -1){
return this.setData({
areaList: datalist
})
}
if(!datalist[provinceCurrentIdx].children && !datalist[provinceCurrentIdx].children.length){
return this.setData({
areaList: datalist,
provinceCurrentIdx
})
}
const cityList = datalist[provinceCurrentIdx].children
const cityCurrentIdx = cityList.findIndex(item => item.isSelect)
if(cityCurrentIdx === -1){
return this.setData({
areaList: datalist,
provinceCurrentIdx,
cityList
})
}
if(!cityList[cityCurrentIdx].children && !cityList[cityCurrentIdx].children.length){
return this.setData({
areaList: datalist,
provinceCurrentIdx,
cityList,
cityCurrentIdx
})
}
const townList = cityList[cityCurrentIdx].children
this.setData({
areaList: datalist,
provinceCurrentIdx,
cityList,
cityCurrentIdx,
townList
})
},
// 点击省
provinceClick(e){
const { idx } = e.target.dataset
const { areaList, provinceCurrentIdx } = this.data
// 切换省,则默认选中
if(provinceCurrentIdx == idx){
areaList[idx].isSelect = areaList[idx].isSelect ? 0 : 1
this.setChioce(areaList[idx])
this.setSign(areaList[idx])
} else {
if(!areaList[idx].isSelect){
areaList[idx].isSelect = 1
this.setChioce(areaList[idx])
this.setSign(areaList[idx])
}
}
this.setData({
areaList: areaList,
provinceCurrentIdx: idx,
cityList: [],
cityCurrentIdx: 0,
townList: [],
})
this.getChildArea(1)
this.getChildArea(2)
},
// 点击市
cityClick(e){
const { idx } = e.target.dataset
const { areaList, cityList, cityCurrentIdx } = this.data
if(cityCurrentIdx == idx){
cityList[idx].isSelect = cityList[idx].isSelect ? 0 : 1
this.setChioce(cityList[idx])
this.setParentChioce(cityList[idx])
this.setSign(cityList[idx])
} else {
if(!cityList[idx].isSelect){
cityList[idx].isSelect = 1
this.setChioce(cityList[idx])
this.setParentChioce(cityList[idx])
this.setSign(cityList[idx])
}
}
this.setData({
areaList: areaList,
cityList: cityList,
cityCurrentIdx: idx,
townList: [],
})
this.getChildArea(2)
},
// 找下一级的地区
getChildArea(level){
const { areaList, provinceCurrentIdx, cityList, cityCurrentIdx } = this.data
switch (level){
case 1:
if(areaList[provinceCurrentIdx].children){
this.setData({
cityList: areaList[provinceCurrentIdx].children
})
}
break;
case 2:
if(cityList[cityCurrentIdx] && cityList[cityCurrentIdx].children){
this.setData({
townList: cityList[cityCurrentIdx].children
})
}
break;
}
},
// 切换--当前项子项选中与取消选中
setChioce(data){
if(!data.children) return
data.children.forEach(item => {
item.isSelect = data.isSelect
this.setChioce(item)
})
},
// 设置父元素选中
setParentChioce(){
let { areaList, provinceCurrentIdx, cityList } = this.data
areaList[provinceCurrentIdx].isSelect = 1
// 设置市选中状态及角标
const len = cityList.filter(item => item.isSelect).length
if(!len){
areaList[provinceCurrentIdx].isSelect = 0
}
},
// 设置元素角标
setSign(data){
let { areaList, provinceCurrentIdx, cityList } = this.data
// 设置当前元素角标提示
if(data.isSelect){
data.signName = '全'
} else {
data.signName = ''
}
// 关联其父角标提示
if(data.parentId){
const len = areaList[provinceCurrentIdx].children.filter(item => item.isSelect).length
if(cityList.length === len){
areaList[provinceCurrentIdx].signName = '全'
} else {
areaList[provinceCurrentIdx].signName = len
}
}
// 关联其子角标提示
if(data.children){
data.children.forEach(item => {
item.signName = data.isSelect ? '全' : ''
})
}
},
// 点击区县
townClick(e){
let { areaList, provinceCurrentIdx, cityList, cityCurrentIdx, townList } = this.data
const { idx } = e.target.dataset
townList[idx].isSelect = townList[idx].isSelect ? 0 : 1
cityList[cityCurrentIdx].isSelect = 1
areaList[provinceCurrentIdx].isSelect = 1
// 设置市选中状态及角标
const len = townList.filter(item => item.isSelect).length
if(!len){
cityList[cityCurrentIdx].isSelect = 0
}
if(cityList[cityCurrentIdx].children.length === len){
cityList[cityCurrentIdx].signName = '全'
} else {
cityList[cityCurrentIdx].signName = len
}
// 设置省选中状态及角标
const lenP = areaList[provinceCurrentIdx].children.filter(item => item.isSelect).length
if(!lenP){
areaList[provinceCurrentIdx].isSelect = 0
}
if(cityList.length === lenP){
areaList[provinceCurrentIdx].signName = '全'
} else {
areaList[provinceCurrentIdx].signName = lenP
}
this.setData({
areaList: areaList,
cityList: cityList,
townList: townList
})
},
})
- 当然还加了一个节流操作:
// throttle.js
function throttle(func, limit) {
let lastFunc;
let lastRan;
return function() {
const context = this;
const args = arguments;
if (!lastRan) {
func.apply(context, args);
lastRan = Date.now();
} else {
clearTimeout(lastFunc);
lastFunc = setTimeout(function() {
if ((Date.now() - lastRan) >= limit) {
func.apply(context, args);
lastRan = Date.now();
}
}, limit - (Date.now() - lastRan));
}
};
}
module.exports = {
throttle
}
- 您可以拿测试数据测试:
code
:唯一值isSelect
:表示选中,回显时记得更改,0表示未选择,1表示选择parentId
:父级code
值parentName
: 父级name
值children
: 子集
{
"data": [
{
"code": "110000",
"isSelect": 0,
"name":"北京",
"children": [
{
"code": "110100",
"isSelect": 0,
"name": "北京",
"parentId": "110000",
"parentName": "北京",
"children": [
{
"code": "110101",
"isSelect": 0,
"name": "东城区",
"parentId": "110100",
"parentName": "北京"
},
{
"code": "110102",
"isSelect": 0,
"name": "西城区",
"parentId": "110100",
"parentName": "北京"
},
{
"code": "110103",
"isSelect": 0,
"name": "朝阳区",
"parentId": "110100",
"parentName": "北京"
}
],
}
]
},
{
"code": "130000",
"isSelect": 0,
"name":"河北",
"children": [
{
"code": "130100",
"isSelect": 0,
"name": "石家庄市",
"parentId": "130000",
"parentName": "河北",
"children": [
{
"code": "130101",
"isSelect": 0,
"name": "桥西区",
"parentId": "130100",
"parentName": "石家庄市"
},
{
"code": "130102",
"isSelect": 0,
"name": "长安区",
"parentId": "130100",
"parentName": "石家庄市"
},
{
"code": "130103",
"isSelect": 0,
"name": "新华区",
"parentId": "130100",
"parentName": "石家庄市"
}
],
},
{
"code": "130200",
"isSelect": 0,
"name": "唐山市",
"parentId": "130000",
"parentName": "河北",
"children": [
{
"code": "130201",
"isSelect": 0,
"name": "桥西区",
"parentId": "130200",
"parentName": "唐山市"
},
{
"code": "130202",
"isSelect": 0,
"name": "长安区",
"parentId": "130200",
"parentName": "唐山市"
},
{
"code": "130203",
"isSelect": 0,
"name": "新华区",
"parentId": "130200",
"parentName": "唐山市"
}
],
}
]
},
{
"code": "140000",
"isSelect": 0,
"name":"山西",
"children": [
{
"code": "140100",
"isSelect": 0,
"name": "太原市",
"parentId": "140000",
"parentName": "山西",
"children": [
{
"code": "140101",
"isSelect": 0,
"name": "小店区",
"parentId": "140100",
"parentName": "太原市"
},
{
"code": "140102",
"isSelect": 0,
"name": "迎泽区",
"parentId": "140100",
"parentName": "太原市"
},
{
"code": "140103",
"isSelect": 0,
"name": "万柏林区",
"parentId": "140100",
"parentName": "太原市"
},
{
"code": "140104",
"isSelect": 0,
"name": "尖草坪区",
"parentId": "140100",
"parentName": "太原市"
},
{
"code": "140105",
"isSelect": 0,
"name": "阳曲县",
"parentId": "140100",
"parentName": "太原市"
},
{
"code": "140106",
"isSelect": 0,
"name": "古交市",
"parentId": "140100",
"parentName": "太原市"
}
],
},
{
"code": "140200",
"isSelect": 0,
"name": "大同市",
"parentId": "140000",
"parentName": "山西",
"children": [
{
"code": "140201",
"isSelect": 0,
"name": "新荣区",
"parentId": "140200",
"parentName": "大同市"
},
{
"code": "140202",
"isSelect": 0,
"name": "平城区",
"parentId": "140200",
"parentName": "大同市"
},
{
"code": "140203",
"isSelect": 0,
"name": "云州区",
"parentId": "140200",
"parentName": "大同市"
},
]
}
]
}
]
}