用户画像 - 人群包圈选

页面布局
根据用户获取到相应标签分类列表,比如一级有通用,汽车,房产等,不同的用户拥有不用的一级分类,通过点击不同的分类,筛选不同的二级分类和标签,标签有8种类型:单值枚举,多值枚举,层级,日期,数值,人群包,规则等,将不同类型标签添加到集合中,集合之间可以做并集和差集运算,集合中的元素不为空,就可以用集合创建人群包。
标签筛选器类型
这里主要说一下层级筛选器的交互逻辑(所谓层级就是通过前一层的数据去取下一层的数据)- 产品需求:

  1. 前几层的select选择框是单选,最后一层select选择框是多选,最后一层选择后,要带着前几层选择的值和最后一层选择的值,以单个标签的形式显示到下面的div中,最后一层的select框和div框中的每一个标签相互联动
  2. 若前几层select框的值经过几次改动后,又选择回来之前选择的值,最后一层select框要回显之前选择的值,同时下面的div框也要显示出相应的单值标签

数据处理方法:

  1. 因为层级的层数和每一层里面的数据要通过两个接口获取,这里使用两个数组处理数据,用一个数组记录层级数(用于渲染select),修改层级数组中的level字段,使其从0开始,去生成对应select下option内容的数组
let temp_data: Array<CascadeItem> = [];
    const last_data = [
        {
            level: res.data.length + 1,
            description: '请选择',
        },
    ];
    temp_data = res.data.concat(last_data);
    // 这里修改level的值,是为了循环出的select和option的值能够一一对上
    temp_data.forEach((i, idx) => {
        i.level = idx;
    });
    store.filter_level_list = cloneDeep(temp_data); 
    store.filter_level_list.forEach(async (item, index) => {
        // 这里循环层级是为了给每个select,匹配相应的option,设置每个option的初始值,清空上一次的值
        store.filter_level_values[item.level] = [];
        // 设置当前select选中的值
        if (index === store.filter_level_list.length - 1) {
            store.filter_current_value[item.level] = [];
        } else {
            store.filter_current_value[item.level] = '';
        }
        // 为了打开弹窗时,获取到第一个下拉框的option
        if (index === 0) {
            ...
        }
    });

2.最后一层select是多选框,有全选的功能,在change函数中要特殊处理,同时要记录前面几层选择的值,以便显示到下面的内容展示框中
层级筛选器
                // 如果是最后一层(全选或非全选)
                if (idx === length - 1) {
                    store.filter_current_value[idx] = option.map((i: any) => {
                        return i.value;
                    });
                    if (option.length > 0) {
                        option.forEach((i: any) => {
                            // 处理全选
                            if (i.value === '全选') {
                                ...
                            } else {
                                // 处理不选择全选的情况
                                store.filter_level_values[idx].forEach(
                                    (item) => {
                                        if (item.value_name === '全选') {
                                            item.is_disabled = true;
                                        }
                                    },
                                );
                                ...
                            }
                        });
                    } else if (option.length === 0) {
                        ...
                    }
                } else {
                    // 非最后一层(层级筛选)
                    store.filter_current_value[idx] = option.value;

                    const pre_filter_name_arr: any = [];
                    Array(length)
                        .fill(0)
                        .forEach((_, i) => {
                            if (
                                store.filter_current_value[i] !== '' &&
                                typeof store.filter_current_value[i] ===
                                    'string'
                            )
                                pre_filter_name_arr.push(
                                    store.filter_current_value[i],
                                );
                        });
                    // 记录前几层选择的值
                    store.pre_filter_name = pre_filter_name_arr.join('/') + '/';

                    const new_temp = cloneDeep(store.filter_current_value);
                    // 改变选择的值,清空数据
                    for (let i = 0; i < length; i++) {
                        if (is_clean_data) {
                            store.filter_level_values[i] = [];
                            if (i === length - 1) {
                                new_temp[i] = [];
                            } else {
                                new_temp[i] = '';
                            }
                        } else if (i === idx) {
                            is_clean_data = true;
                        }
                    }
                    store.filter_current_value = new_temp;
                    ...
                }

3.select多选框删除已选择的值时,保持div框中内容联动一致,这里用了select的onDeselect方法,它的参数是删除的值,通过它的参数处理div中单值标签数组,保证内容一致,同时删除div中单值标签,也要保证select框的数据是正确的,使用tag的onClose事件

            // select多选时,取消选中时,触发函数
            async handleLevelFilterSelectDeChange(value: any) {
                const length = store.filter_level_list.length;
                store.de_select_option_value = value;
                store.show_filter_content_list = store.show_filter_content_list.filter(
                    (item) => item.value !== value,
                );
                if (value === '全选') {
                    ...
                }
            },
            // 点击展示标签的删除时,上下联动效果
            handleTagClose(data_value: ShowFilterValue) {
                const length = store.filter_level_list.length;
                // 删除已经选中的值
                store.show_filter_content_list.forEach((i, idx) => {
                    if (i.value === data_value.value) {
                        store.show_filter_content_list.splice(idx, 1);
                    }
                });
                // 最后一个select当前选择的值
                let last_select_values = store.filter_current_value[length - 1];
                // 检验当前删除的值,是否在列表中
                const temp_arr = store.filter_level_values[length - 1].filter(
                    (item) => {
                        return item.value_name === data_value.value;
                    },
                );
                // 如果删除的值在列表中
                if (temp_arr.length > 0) {
                    // 如果当前值选择是全选,删除一个值,则需要把全选置灰,同时需要修改当前选择的值
                    ...
                }
                // 重置当前选择的值
                ...
                // 将选择的值删除完了,则全选也可以选择了
                ...
            },

上面主要说了层级筛选器数据交互的处理方法,对于与后端交互数据封装就不在这里啰嗦啦!

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 218,451评论 6 506
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 93,172评论 3 394
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 164,782评论 0 354
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,709评论 1 294
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,733评论 6 392
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,578评论 1 305
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,320评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,241评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,686评论 1 314
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,878评论 3 336
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,992评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,715评论 5 346
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,336评论 3 330
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,912评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,040评论 1 270
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,173评论 3 370
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,947评论 2 355

推荐阅读更多精彩内容