微信小程序省市区选择插件

因为微信小程序自带的区域选择插件,不支持通过code(地区编号)回显,回返的code和其他一些通用区域选择插件(如:element UI)的也有些区别,所以封装了一个自定义插件。

附带代码详细仓库地址:微信小程序省市区选择插件

用的是小程序字典的picker (mode="multiSelector")来进行封装:

先给出调用方式:

<picker-region bindchange="regionChange" />

<picker-region bindchange="regionChange" placeholder="请选择所在区域" />

<picker-region bindchange="regionChange" placeholder="请选择所在区域" value="{{value}}" />


具体实现如下:

<!-- wxml -->

    <view class="picker-txt">

        <text class="text" wx:if="{{label}}"> {{ label }} </text>

        <text class="ccc" wx:else> {{ placeholder }}</text>

    </view>

</picker>

// js 实现逻辑

const {

    RegionData

} = require('./region-data');

Component({

    properties: {

        placeholder: {

            type: String,

            value: '请选择',

        },

        value: {

            type: Array,

            value: [],

            observer(v) {

                if (v && v.length) {

                    this.setLabel();

                }

            }

        }

    },

    list: [],

    data: {

        label: '',

        range: [],

        pickerValue: [],

    },

    methods: {

        getItem(data) {

            return {

                label: data.label,

                value: data.value

            };

        },

        setList(list) {

            return list.map((v) => this.getItem(v));

        },

        getByCode(list = [], value) {

            let index = list.findIndex(item => item.value === value);

            return [index, list[index] || {}];

        },

        /**

         * 将省市区联级数据处理成展开显示的列表

         * @param list  需要处理的数组, {label: "北京市", value: "11", children: [...]}

         * @param keys  需要获取到的展开项下标集合 [0,1,n],对应 picker 的 model:value 绑定的值

         */

        openChildren(list, keys) {

            let result = [];

            const handle = (arr, keys) => {

                let newarr = arr.map((v, index) => {

                    if (keys && keys.length) {

                        let [currentKey, ...nextKey] = keys;

                        if (currentKey === index && Array.isArray(v.children)) {

                            handle(v.children, nextKey);

                        }

                    }

                    return this.getItem(v);

                });

                result.push(newarr);

            }

            handle(list, keys);

            return result.reverse();

        },

        // 确认选择

        onChange(e) {

            let [r1, r2, r3] = this.data.range;

            const [v1, v2, v3] = e.detail.value;

            const selected = [r1[v1], r2[v2], r3[v3]];

            const values = selected.map(v => v.value);

            const label = selected.map(v => v.label).join('-');

            this.setData({

                label

            });

            this.triggerEvent("change", {

                value: values,

                label

            });

        },

        // 切换选项

        columnChange(e) {

            const {

                column,

                value

            } = e.detail;

            this.setColumn(column, value);

        },

        // 设置列表数据

        setColumn(column, value) {

            let list = this.list;

            if (!list || list.length === 0) return;

            let [r1, r2, r3] = this.data.range;

            if (column === 0) {

                // 切换第一列,修改第二第三列数据项

                r2 = this.setList(list[value].children);

                r3 = this.setList(list[value].children[0].children);

                // 修改第一列选中值,在切换第二列的时候用到

                this.setData({

                    pickerValue: [value, 0, 0]

                });

            } else if (column === 1) {

                // 切换第二列,修改第三列数据项

                const [v1] = this.data.pickerValue;

                r3 = this.setList(list[v1].children[value].children);

                this.setData({

                    pickerValue: [v1, value, 0]

                });

            }

            this.setData({

                range: [r1, r2, r3]

            });

        },

        setLabel() {

            // 设置回显的默认值

            let list = this.list;

            if (list && list.length) {

                const [v1, v2, v3] = this.data.value; // 回显的省市区对应的value,来自父组件传入

                const [s1, {

                    label: t1,

                    children: l1

                }] = this.getByCode(list, v1);

                const [s2, {

                    label: t2,

                    children: l2

                }] = this.getByCode(l1, v2);

                const [s3, {

                    label: t3

                }] = this.getByCode(l2, v3);

                // 回显的省市区名称,本控件展示的内容(xx省-xx市-xx区)

                const label = [t1, t2, t3].filter(v => v).join('-');

                // 回显的省市区下标,小程序piker控件的值([1,2,n])

                const pickerValue = [s1, s2, s3];

                const range = this.openChildren(list, [s1, s2, s3]);;

                if (label.length) {

                    this.setData({

                        label,

                        range,

                        pickerValue

                    });

                }

            } else {

                this.getRange();

                this.setLabel();

            }

        },

        initRange() {

            if (!this.data.value.length) {

                // 没有默认值,取第一条作为初始化省市区数据列

                const range = this.openChildren(this.list, [0, 0, 0]);

                this.setData({

                    range

                });

            }

        },

        // 获取全国省市区列表原始数据

        async getRange() {

            this.list = RegionData();

        },

    },

    attached: function () {

        // 在组件实例进入页面节点树时执行

        this.getRange();

        if (!this.data.value.length) {

            this.initRange();

        }

    },

})

// json数据格式,可根据需求自行定义

module.exports = {

RegionData: function () {

return [{

"value": "11",

"label": "北京市",

"children": [{

"value": "1101",

"label": "市辖区",

"children": [{

"value": "110101",

"label": "东城区"

},

......

实现的效果

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容