用户画像 - 人群包圈选

页面布局
根据用户获取到相应标签分类列表,比如一级有通用,汽车,房产等,不同的用户拥有不用的一级分类,通过点击不同的分类,筛选不同的二级分类和标签,标签有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) {
                    // 如果当前值选择是全选,删除一个值,则需要把全选置灰,同时需要修改当前选择的值
                    ...
                }
                // 重置当前选择的值
                ...
                // 将选择的值删除完了,则全选也可以选择了
                ...
            },

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

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

推荐阅读更多精彩内容