收藏
评论

横向滑动筛选列表封装成自定义组件




// components/selectionSearch/selectionSearch.js

const {

    helper,

    va,

    webApi

} = global;

Component({

    /**

     * 组件的属性列表

     */

    properties: {

        searchSelections: Array,

        searchSelectionsMap: Object,

        useSelectedList: Boolean

    },


    /**

     * 组件的初始数据

     */

    data: {


    },

    attached() {

        helper.getComponentStorageData(this);

    },

    ready() {

        this.setSelectionPanelHeight();

        this.triggerEvent("ready", {

            component: this

        })

    },

    /**

     * 组件的方法列表

     */

    methods: {

        updateSearchSelections(searchSelections, searchSelectionsMap) {

            if (searchSelectionsMap) {

                this.storage.searchSelectionsMap = searchSelectionsMap;

            }

            this.setData({

                searchSelections: searchSelections,

                selectionMiniBarText: this.getSelectionsSelected(searchSelections).text

            });

            this.setSelectionPanelHeight();

        },

        onSelectionSelectedTagTap(e) {

            const data = e.currentTarget.dataset;

            const {

                cmpnt,

                cmpntData,

                cmpntStorage

            } = helper.getComponentStorageData(this);

            const searchSelections = cmpntData.searchSelections,

                searchSelectionsMap = cmpntStorage.searchSelectionsMap;

            const {

                value,

                subId,

                classify,

                groupIndex,

                selectionIndex,

                index

            } = data;

            const group = searchSelections[selectionIndex].group

            const selectionPath = `searchSelections[${selectionIndex}]`;

            const groupPath = `${selectionPath}.group`;

            const selectedListPath = `${selectionPath}.selectedList`;

            const selection = searchSelections[selectionIndex];

            let selectedList = selection.selectedList || (selection.selectedList = []);

            let updateData = {};

            for (let i = groupIndex; i < group.length; i++) {

                updateData[`${groupPath}[${i}].isHide`] = false;

            }

            selectedList.splice(groupIndex)

            updateData[selectedListPath] = selectedList;

            this.setData(updateData);

            this.setSelectionPanelHeight();

        },

        onSelectionTagTap(e) {

            const data = e.currentTarget.dataset;

            const {

                cmpnt,

                cmpntData,

                cmpntStorage

            } = helper.getComponentStorageData(this);

            const searchSelections = cmpntData.searchSelections,

                searchSelectionsMap = cmpntStorage.searchSelectionsMap;

            const {

                value,

                subId,

                classify,

                groupIndex,

                selectionIndex,

                index

            } = data;

            const selection = searchSelections[selectionIndex];

            const group = selection.group;

            const item = group[groupIndex];

            const prevSelectedIndex = item.selectedIndex

            item.selectedIndex = index;

            let selectedList = selection.selectedList || (selection.selectedList = []);

            let selected = selectedList[groupIndex];

            const updateData = {}

            const selectionPath = `searchSelections[${selectionIndex}]`;

            let afterSelectedIndex;

            const groupPath = `${selectionPath}.group`;

            const addSelected = function() {

                const selectedListPath = `${selectionPath}.selectedList`;

                const prevGroupIndex = groupIndex;

                for (let selected, item, tag, selectedIndex, i = 0; i <= prevGroupIndex; i++) {

                    item = group[i];

                    selectedIndex = item.selectedIndex || 0;

                    tag = item.tags[selectedIndex];

                    selected = selectedList[i];

                    if (!selected || tag.id !== selected.id || tag.value !== tag.value || selected.subId !== tag.subId || selected.classify !== item.classify) {

                        selectedList[i] = {

                            selectionIndex: selectionIndex,

                            groupIndex: i,

                            index: selectedIndex,

                            classify: item.classify,

                            value: tag.value,

                            text: tag.text,

                            subId: tag.subId

                        };

                        updateData[`${groupPath}[${i}].isHide`] = true;

                    }

                }

                afterSelectedIndex = groupIndex ? groupIndex + 1 : groupIndex;

                if (afterSelectedIndex < group.length) {

                    for (let i = afterSelectedIndex; i < group.length; i++) {

                        updateData[`${groupPath}[${i}].isHide`] = false;

                    }

                }

                selectedList.splice(afterSelectedIndex);

                updateData[`${selectedListPath}`] = selectedList;

            };

            if (prevSelectedIndex === index) {

                addSelected();

                this.setData(updateData);

                this.setSelectionPanelHeight();

                return

            }

            const selectedIndexPath = `${groupPath}[${groupIndex}].selectedIndex`;

            updateData[selectedIndexPath] = index;

            let nextGroupIndex = groupIndex;

            void

            function addSub(subId) {

                const sub = subId && searchSelectionsMap[subId];

                if (sub) {

                    sub.selectedIndex = null;

                    sub.isHide = false;

                    group[++nextGroupIndex] = sub;

                    const tags = sub.tags[0];

                    addSub(tags && tags.subId)

                }

            }(subId);

            if (group.length > ++nextGroupIndex) {

                group.splice(nextGroupIndex);

            }

            updateData[groupPath] = group;

            addSelected();

            this.setData(updateData);

            this.onSelectionChange(data);

        },

        onSelectionChange(data) {

            this.updateSelectionMiniBarText();

            this.setSelectionPanelHeight();

            this.triggerEvent("change", {

                component: this

            })

        },

        getSelectionsSelected(selections) {

            selections = selections || this.data.searchSelections;

            let selectionMiniBarTextArray = [];

            let selectedGroup = {};

            va.each(selections, selection => {

                va.each(selection.group, item => {

                    if (!item) {

                        return

                    }

                    let selectedIndex = item.selectedIndex || 0;

                    let tag = item.tags[selectedIndex];

                    if (!tag) {

                        return

                    }

                    let selectedList = selectedGroup[item.classify] || (selectedGroup[item.classify] = []);

                    selectedList.push(tag);

                    if (selectedIndex !== 0) {

                        selectionMiniBarTextArray.push(tag.text || tag.value);

                    }

                })

            });

            return {

                selectedGroup: selectedGroup,

                text: selectionMiniBarTextArray.join(" · ") || "筛选"

            }

        },

        updateSelectionMiniBarText() {

            this.setData({

                selectionMiniBarText: this.getSelectionsSelected().text

            })

        },

        setSelectionPanelHeight() {

            const cmpnt = this;

            cmpnt.createSelectorQuery().select('.selection-panel').boundingClientRect(function(rect) {

                const height = rect.height;

                if (cmpnt.data.selectionPanelHeight !== height) {

                    cmpnt.setData({

                        selectionPanelHeight: height

                    });

                }

            }).exec();

        },

        onPageScroll(e) {

            let data;

            if (this.data.selectionPanelHeight < e.scrollTop) {

                if (!this.data.selectionIsMini) {

                    data = {

                        selectionIsMini: this.data.selectionIsMini = true

                    };

                }

            } else if (this.data.selectionIsMini) {

                data = {

                    selectionIsMini: this.data.selectionIsMini = false

                };

            }

            if (this.data.selectionIsExpand && !this.data.selectionIsMini) {

                this.data.selectionIsExpand = (data = data || {}).selectionIsExpand = false;

            }

            if (data) {

                this.setData(data)

            }

        },

        onSelectionMiniBarTap() {

            this.setData({

                selectionIsExpand: !this.data.selectionIsExpand

            })

        }

    }

})


<!--components/selectionSearch/selectionSearch.wxml-->

<view class='selection-panel  {{selectionIsMini?"selection-mini-panel":""}} {{selectionIsExpand?"selection-expand-panel":""}}'>

    <view wx:for="{{searchSelections}}" wx:key="wx:key" wx:for-index="selectionIndex" class='selection-item {{item.group.length?"multi-tags-item":""}} '>

        <scroll-view scroll-x="true" class='selected-list selection-tags' wx:if="{{useSelectedList}}" hidden="{{!item.selectedList.length}}">

            <view wx:for="{{item.selectedList}}" wx:key="wx:key" wx:for-item="tag" wx:if="{{tag}}" catchtap='onSelectionSelectedTagTap' class="selection-tag selected" data-group-index="{{tag.groupIndex}}" data-selection-index="{{tag.selectionIndex}}" data-index="{{tag.index}}"

                data-sub-id="{{tag.subId||''}}" data-classify="{{tag.classify}}" data-value="{{tag.value}}">{{tag.text||tag.value}}

                <ico class="ic-expand_more" />

            </view>

        </scroll-view>

        <scroll-view scroll-x="true" wx:for="{{item.group}}" wx:key="wx:key" wx:for-index="groupIndex" wx:for-item="groupItem" hidden='{{useSelectedList&&groupItem.isHide}}' class='selection-tags {{groupItem.isSub?"sub-tags":""}}'>

            <view wx:for="{{groupItem.tags}}" wx:key="wx:key" wx:for-item="tag" wx:if="{{tag}}" catchtap='onSelectionTagTap' class="selection-tag {{(groupItem.selectedIndex||0) === index?'selected':''}}" data-group-index="{{groupIndex}}" data-selection-index="{{selectionIndex}}"

                data-index="{{index}}" data-sub-id="{{tag.subId||''}}" data-classify="{{item.classify}}" data-value="{{tag.value}}">{{tag.text||tag.value}}</view>

        </scroll-view>

    </view>

    <view class='selection-mini-bar' catchtap='onSelectionMiniBarTap'>

        <view class='text'>{{selectionMiniBarText}}</view>

        <ico class="{{selectionIsExpand?'ic-expand_less':'ic-expand_more'}}" />

    </view>

</view>

<view class='selection-panel-space-layout' style='height:{{selectionPanelHeight}}px'></view>


/* components/selectionSearch/selectionSearch.wxss */

@import "/fontIcons/icomoon.wxss";

.selection-panel{

    position: fixed;

    top: 0;

    left: 0;

    width: 100%;

    z-index: 6;

    background: #FFFFFF;

}

.selection-item{

    font-size: 14px;

    overflow: hidden;

}


.selection-tags{

    display: block;

    white-space: nowrap;

    overflow-x: auto;

    overflow-y: hidden;

    -webkit-overflow-scrolling: touch;

    border-bottom: 1px solid #EBEBEB;

    padding-bottom: 5px;

    height: 22px;

    padding: 5px;

}

.selection-tags::-webkit-scrollbar{

    display: none;

}

.selection-tags +.selection-tags{

    margin-left: 5px;

}

.selection-item .selection-tags:last-of-type{

    margin-left: 0;

    padding-left: 5px;

}

.selection-tag{

    padding: 0 10px;

    margin: 0 5px;

    display: inline-block;

}

.selection-tag.selected{

    background: red;

    border-radius: 50px;

    color: #FFFFFF;

}

.selection-mini-bar{

    text-align: center;

    padding: 0 5px;

    height: 30px;

    line-height: 30px;

    font-size: 12px;

    overflow: hidden;

    display: none;

}

.selection-mini-bar ico{

    width: 20px;

    vertical-align: top;

    line-height: 32px;

    font-size: 14px;

}

.selection-mini-bar .text{

    display: inline-block;

    white-space: nowrap;

    padding-right: 20px;

    margin-right: -20px;

    max-width: 100%;

    overflow-x: auto;

    overflow-y: hidden;

    -webkit-overflow-scrolling: touch;

}

.selection-mini-panel .selection-item{

    display: none;

}

.selection-mini-panel .selection-mini-bar,.selection-expand-panel .selection-item{

    display: block;

}

.selection-mini-panel{

    box-shadow:0 0 10px rgba(0,0,0,.25);

}

<!--pages/search/selectionSearch.json-->

{

    "component": true,

    "usingComponents": {

        "selectionSearch":"/components/selectionSearch/selectionSearch"

    }

}

<!--pages/search/selectionSearch.wxml-->

<import src="/templates/list.wxml" />

<selectionSearch class="selection-search"/>

<view catchtap='onBackOrGoPage' data-url="/pages/search/search" class='go-search btn-floating'>

    <ico class="ic-search4" />

</view>

<view class='main' style='height:1000px;'>

</view>

// pages/search/selectionSearch.js

const { helper, va, webApi } = global;

helper.Page({

    storage: {},

    onLoad(){

        const searchSelectionsMap={

            "s": {

                classify: "s",

                tags: [

                    { id: "tag0", value: "tag0", subId: "" },

                    { id: "tag1", value: "tag1",subId:"sub1"},

                    { id: "tag2", value: "tag2", subId: "sub2" },

                    { id: "tag1", value: "tag1", subId: "sub1" },

                    { id: "tag2", value: "tag2", subId: "sub2" },

                    { id: "tag2", value: "tag2", subId: "sub2" },

                    { id: "tag2", value: "tag2", subId: "sub2" },

                    { id: "tag2", value: "tag2", subId: "sub2" },

                    { id: "tag2", value: "tag2", subId: "sub2" },

                ]

            },

            "sub1": {

                classify: "sub1",

                tags: [

                    { id: "tag1.1", value: "tag1.1", subId: "sub1.1"},

                    { id: "tag1.2", value: "tag1.2", subId: "sub1.2" }

                ]

            },

            "sub1.1": {

                classify: "sub1.1",

                tags: [

                    { id: "tag1.1.1", value: "tag1.1.1" },

                    { id: "tag1.1.2", value: "tag1.1.2" }

                ]

            },

            "sub1.2": {

                classify: "sub1.2",

                tags: [

                    { id: "tag1.2.1", value: "tag1.2.1" },

                    { id: "tag1.2.2", value: "tag1.2.2" }

                ]

            },

            "sub2": {

                classify: "sub2",

                tags: [

                    { id: "tag2.1", value: "tag2.1" },

                    { id: "tag2.2", value: "tag2.2" }

                ]

            },


        };

        const searchSelections=[

            {

                selectedList:[

                ],

                group:[

                    searchSelectionsMap["s"]

                ]

            }

        ];

        va.fnCall(this.selectComponent('.selection-search'), 'updateSearchSelections', searchSelections, searchSelectionsMap);

    },

    onPageScroll(e){

        va.fnCall(this.selectComponent('.selection-search'), 'onPageScroll',e);

    }

})

//helper.js

helper.getPageStorageData=function(page){

    return {

        page: page,

        pageStorage: page.storage || (page.storage = {}),

        pageData: page.data || (page.data = {}),

        queryParameters:page.options

    }

};

helper.getComponentStorageData = function (component){

    return {

        cmpnt: component,

        cmpntStorage: component.storage || (component.storage = {}),

        cmpntData: component.data || (component.data = {}),

        cmpntOptions: component.options

    }

}

let basePage;

helper.getBasePage = function() {

    return basePage ? basePage : basePage = require('./basePage.js');

}

helper.Page = function(...args) {

    args.unshift({}, this.getBasePage());

    const pageMember = Object.assign(...args)

    return [pageMember, Page(pageMember)];

}

//va.js

    va.fnCall=function(obj, funcName, ...args) {

        if (obj && va.isFunction(obj[funcName])) {

            return obj[funcName](...args);

        }

    };


最后一次编辑于  2018-09-03
赞 2
收藏