欧美三级国产三级日韩三级_亚洲熟妇丰满大屁股熟妇_欧美亚洲成人一区二区三区_国产精品久久久久久模特

小程序picker地區(qū)級(jí)聯(lián)選擇的問題及解決方案 - 新聞資訊 - 云南小程序開發(fā)|云南軟件開發(fā)|云南網(wǎng)站建設(shè)-昆明葵宇信息科技有限公司

159-8711-8523

云南網(wǎng)建設(shè)/小程序開發(fā)/軟件開發(fā)

知識(shí)

不管是網(wǎng)站,軟件還是小程序,都要直接或間接能為您產(chǎn)生價(jià)值,我們?cè)谧非笃湟曈X表現(xiàn)的同時(shí),更側(cè)重于功能的便捷,營(yíng)銷的便利,運(yùn)營(yíng)的高效,讓網(wǎng)站成為營(yíng)銷工具,讓軟件能切實(shí)提升企業(yè)內(nèi)部管理水平和效率。優(yōu)秀的程序?yàn)楹笃谏?jí)提供便捷的支持!

您當(dāng)前位置>首頁(yè) » 新聞資訊 » 小程序相關(guān) >

小程序picker地區(qū)級(jí)聯(lián)選擇的問題及解決方案

發(fā)表時(shí)間:2021-4-30

發(fā)布人:葵宇科技

瀏覽次數(shù):108

一、造輪子的原因

1.1 數(shù)據(jù)要自定義

微信官方的picker的region模式使用的是標(biāo)準(zhǔn)的國(guó)家行政區(qū)域數(shù)據(jù),而我們的場(chǎng)景有一些自設(shè)的區(qū)域要加入;也不可以自定久選擇級(jí)數(shù),只能選到縣/區(qū)級(jí)。

1.2 picker的兼容性并不好。

uni-app的picker組件,在小程序模式是使用各自的picker,H5則是uni-app自的picker組件。所以在各平臺(tái)中還是有差異的,在我們測(cè)試中微信的picker的mulitSelector模式,在列級(jí)聯(lián)滑動(dòng)中如果出現(xiàn)兩次列數(shù)組值length不一致時(shí),后綁定的選定索引時(shí)會(huì)無效,會(huì)自動(dòng)致為0,且后續(xù)觸發(fā)的change事件則仍是綁定索引,而在H5時(shí)不會(huì)。

1.3 picker是不適合異步加載數(shù)據(jù)

級(jí)聯(lián)就是要簡(jiǎn)便的控制后續(xù)列的變化,如1.2所示,綁定索引bug。而如果數(shù)據(jù)是異步加載,則更難于控制加載狀態(tài),特別是滑動(dòng)過快網(wǎng)絡(luò)不佳時(shí),很容易出現(xiàn)數(shù)據(jù)混亂。

1.4 picker作級(jí)聯(lián),不如京東級(jí)聯(lián)模式的體驗(yàn)好效率高。

如圖所示

二、上代碼

使用的了tui-drawer 、tui-loadmore等tui-xxx為uni-app第三方組件,具本使用參考官方文檔,或使用別的組件替代。regionApi為行政區(qū)域節(jié)點(diǎn)異步加載封裝,可根自己數(shù)據(jù)自行封裝。

<!--
* 行政區(qū)域選擇器
*
* @alphaiar
* 20210408 created.
 -->

<template>
    <view class="region-picker">
        <input v-if="!visibleInputer" placeholder-class="placeholder" :placeholder="placeholder" :value="https://www.wxapp-union.com/selectorPath"
            disabled @tap="onPopupToggle" />
        <view v-else  @tap="onPopupToggle">
            <slot name="inputer"></slot>
        </view>

        <view v-if="errorMessage" class="messager">{{errorMessage}}</view>
        <tui-drawer :visible="visibled" mode="bottom" @close="onPopupToggle">
            <view class="header">
                <text class="cancel" @tap="onPopupToggle">取消</text>
                <text class="confirm" @tap="onConfirm">確認(rèn)</text>
            </view>
            <view class="tab-wrapper">
                <template v-for="(lab,idx) in labels">
                    <label v-if="idx!==labelIndex" :key="idx" @tap="onLabelChange({index:idx})">
                        {{lab}}
                    </label>
                    <template v-else>
                        <label class="active">
                            {{lab}}
                        </label>
                        <iconfont class="indicator" name="arrow-down" />
                    </template>
                </template>
            </view>
            <tui-loadmore v-if="loading" :index="3" type="primary" text="加載中..." />
            <view v-else class="region-view">
                <template v-for="(n,idx) in regions">
                    <label v-if="idx !== selectorIndexs[labelIndex]" @tap="onSelector(idx)" :key="idx">{{n}}</label>
                    <label v-else :key="idx">
                        <span class="selected">{{n}}</span>
                    </label>
                </template>
            </view>
            <view v-if="errorTips" class="error-tips">
                {{errorTips}}
            </view>
        </tui-drawer>
    </view>
</template>

<script>
    import utils from "../utils/utils.js";
    import regionApi from "../apis/region.js";

    export default {
        name: 'regionPicker',
        props: {
            /**
             * 選擇器區(qū)級(jí)
             * 0-省
             * 1-地市
             * 2-縣區(qū)
             * 3-鄉(xiāng)鎮(zhèn)
             */
            selectorLevel: {
                type: Number,
                default: 1,
                validator(val) {
                    return [0, 1, 2, 3].some(x => x === val);
                }
            },
            /**
             * 當(dāng)前選擇值
             */
            value: {
                type: Array,
                default: null
            },
            /**
             * 沒有值時(shí)的占位符
             */
            placeholder: {
                type: String,
                default: '請(qǐng)選擇地區(qū)'
            },
            /**
             * 表單驗(yàn)證錯(cuò)誤提示消息
             */
            errorMessage: {
                type: String,
                default: null
            },
            /**
             * 啟用自定義輸入框
             */
            visibleInputer: {
                type: Boolean,
                default: false
            }
        },
        watch: {
            selectorLevel(val) {
                this.$emit('input', null);
                this.initialize();
            },
            value(val) {
                this.initialize();
            }
        },
        data() {

            return {
                visibled: false,
                loading: false,
                labels: ['請(qǐng)選擇'],
                labelIndex: 0,
                regions: [],
                selectorIndexs: [],
                selectorNodes: [],
                errorTips: null
            };
        },
        computed: {
            selectorPath() {
                let nodes = this.selectorNodes;

                if (!nodes || nodes.length < 1)
                    return null;

                let paths = nodes.map(x => x.name);
                let path = paths.join(' / ');

                return path;
            }
        },
        mounted() {
            const self = this;
            regionApi.getNodes({
                params: {
                    endCategory: 1
                },
                loading: false,
                onLoading(ld) {
                    self.loading = ld;
                },
                showError: true,
                callback(fkb) {

                    if (!fkb.success)
                        return;

                    let nodes = fkb.result;
                    self.__rawRegions = nodes;

                    if (!self.value || self.value.length < 1)
                        self.bindViews(nodes);
                    else
                        self.initialize();
                }
            });

        },
        methods: {
            /**
             * 初始化選擇器
             */
            initialize() {

                //初始化數(shù)據(jù)沒有執(zhí)行完成
                if (!this.__rawRegions)
                    return;

                this.labels = ['請(qǐng)選擇'];
                this.labelIndex = 0;
                this.selectorIndexs = [];
                this.selectorNodes = [];
                this.bindViews(this.__rawRegions);

                //設(shè)定初始值
                let values = this.value;
                if (!values || values.length < 1)
                    return;

                const self = this;
                let prevs = this.__rawRegions;
                let setValue = https://www.wxapp-union.com/function(idx) {
                    let nd = values[idx];
                    let about = false;
                    let exists = prevs.some((x, i) => {
                        if (nd.name !== x.name && nd.code !== x.code)
                            return false;

                        prevs = x.children || prevs;

                        //如果還有下級(jí),但又未加載子節(jié)點(diǎn),則先加載再來設(shè)定
                        if (!x.children && idx + 1 < values.length) {
                            self.getNextRegions(x, () => {
                                setValue(idx);
                            });
                            about = true;
                            return true;
                        }

                        self.selectorNodes.push({
                            category: x.category,
                            code: x.code,
                            name: x.name
                        });
                        self.onSelector(i);
                        return true;
                    });

                    if (about)
                        return;

                    if (exists && idx + 1 < values.length)
                        setValue(idx + 1);
                };

                setValue(0);
            },
            /**
             * 將待選節(jié)點(diǎn)綁定至待選視圖
             * 
             * @param {Array} nodes 要綁定的原始節(jié)點(diǎn)
             */
            bindViews(nodes) {
                this.regions = nodes.map(x => x.name);
            },
            /**
             * 獲取下級(jí)節(jié)點(diǎn)
             * 
             * @param {Object} prevNode 上級(jí)選中的節(jié)點(diǎn)
             * @param {function} cb 加載完成后回調(diào)
             */
            getNextRegions(prevNode, cb) {
                const self = this;
                regionApi.getChildren({
                    params: {
                        category: prevNode.category + 1,
                        prevCode: prevNode.code
                    },
                    loading: false,
                    onLoading(ld) {
                        self.loading = ld;
                    },
                    showError: true,
                    callback(fkb) {
                        if (!fkb.success)
                            return;

                        prevNode.children = fkb.result;
                        if (!cb)
                            self.bindViews(fkb.result);
                        else
                            cb();
                    }
                });
            },
            /**
             * 獲取指定列選擇的節(jié)點(diǎn)
             * 
             * @param {Object} level 地區(qū)級(jí)別0-3
             */
            getSelectorNode(level) {
                let prevs = this.__rawRegions;

                for (let i = 0; i < level; i++) {

                    let sidx = this.selectorIndexs[i];
                    if (!sidx)
                        return null;

                    prevs = prevs[sidx].children;
                    if (!prevs)
                        return null;
                }

                let cval = this.selectorIndexs[level];
                let node = prevs[cval];

                return node;
            },
            /**
             * 切下至下一級(jí)區(qū)域選擇
             * 
             * @param {Object} current 當(dāng)前選中級(jí)別0-3
             */
            moveNextLevel(current) {
                let node = this.getSelectorNode(current);
                if (node == null)
                    return;

                if (node.children)
                    this.bindViews(node.children);
                else
                    this.getNextRegions(node);
            },
            onPopupToggle(e) {
                this.visibled = !this.visibled;
            },
            onConfirm(e) {
                if (this.selectorLevel + 1 > this.selectorIndexs.length) {
                    this.errorTips ='*請(qǐng)將地區(qū)選擇完整。';
                    return;
                }

                let nodes = [];
                for (let i = 0; i < this.selectorIndexs.length; i++) {
                    let node = this.getSelectorNode(i);
                    nodes.push({
                        category: node.category,
                        code: node.code,
                        name: node.name
                    });
                }

                this.selectorNodes = nodes;
                this.onPopupToggle();

                this.$emit('input', nodes);
                this.$emit('change', nodes);
            },
            onLabelChange(e) {
                //加載中,禁止切換
                if (this.loading)
                    return;

                let idx = e.index;
                this.labelIndex = idx;
                if (idx > 0)
                    this.moveNextLevel(idx - 1);
                else
                    this.bindViews(this.__rawRegions);
            },
            onSelector(idx) {

                this.errorTips = null;
                let labIdx = this.labelIndex;

                //由于uni 對(duì)于數(shù)組的值監(jiān)聽不完善,只有復(fù)制數(shù)組更新才生效
                let labs = utils.clone(this.labels);
                labs[labIdx] = this.regions[idx];
                this.labels = labs;

                //原因上同
                let idexs = utils.clone(this.selectorIndexs);
                if (idexs.length <= labIdx)
                    idexs.push(idx);
                else
                    idexs[labIdx] = idx;
                this.selectorIndexs = idexs;

                //有下級(jí),全清空
                if (labIdx >= this.selectorLevel)
                    return;

                this.selectorIndexs.splice(labIdx + 1, 4); //最大只有4級(jí)
                this.labels.splice(labIdx + 1, 4); //最大只有4級(jí)

                this.labels.push('請(qǐng)選擇');
                this.labelIndex = labIdx + 1;
                this.moveNextLevel(labIdx);
            }
        }
    }
</script>

<style lang="scss">
    .region-picker {

        .header {
            width: 100%;
            box-sizing: border-box;
            margin: 7.2463rpx 0;
            line-height: $uni-font-size-base+ 7.2463rpx;

            .cancel {
                padding: 0 18.1159rpx;
                float: left;
                //color: $uni-text-color-grey;
            }

            .confirm {
                padding: 0 18.1159rpx;
                float: right;
                color: $uni-color-primary;
            }

            text:hover {
                background-color: $uni-bg-color-hover;
            }
        }

        .tab-wrapper {
            width: 100%;
            margin-bottom: 28.9855rpx;
            display: flex;
            justify-content: center;
            box-sizing: border-box;

            label {
                margin: 7.2463rpx 28.9855rpx;
                padding: 7.2463rpx 0;
                color: $uni-text-color;
                border-bottom: solid 3.6231rpx transparent;
            }

            .active {
                color: $uni-color-primary;
                border-color: $uni-color-primary;
            }

            .indicator {
                margin-left: -10px;
                margin-top: 6px;
                color: $uni-color-primary;
            }
        }

        .region-view {
            width: 100%;
            display: flex;
            flex-wrap: wrap;
            padding: 7.2463rpx 14.4927rpx 28.9855rpx 14.4927rpx;
            box-sizing: border-box;

            label {
                margin: 7.2463rpx 0;
                width: 33%;
                text-align: center;
                color: $uni-text-color-grey;
                text-overflow: ellipsis;
                overflow: hidden;
            }

            .selected {
                padding: 3.6231rpx 14.4927rpx;
                background-color: $uni-color-light-primary;
                color: #FFF;
                border-radius: 10.8695rpx;
            }
        }

        .error-tips {
            width: 100%;
            height: auto;
            padding-bottom: 21.7391rpx;
            text-align: center;
            color: $uni-color-error;
            font-size: $uni-font-size-sm;
        }
    }
</style>

行政區(qū)化節(jié)點(diǎn)數(shù)據(jù),來源國(guó)家統(tǒng)計(jì)局,到縣區(qū)級(jí)。

https://files.cnblogs.com/fil...

最終效果

相關(guān)案例查看更多