index.js 4.91 KB
import { VantComponent } from '../common/component';
import { addUnit } from '../common/utils';
let ARRAY = [];
VantComponent({
    field: true,
    relation: {
        name: 'dropdown-item',
        type: 'descendant',
        linked(target) {
            this.children = this.children || [];
            // 透传 props 给 dropdown-item
            const { overlay, duration, activeColor, closeOnClickOverlay, direction } = this.data;
            this.updateChildData(target, {
                overlay,
                duration,
                activeColor,
                closeOnClickOverlay,
                direction,
                childIndex: this.children.length
            });
            this.children.push(target);
            // 收集 dropdown-item 的 data 挂在 data 上
            target &&
                this.setData({
                    itemListData: this.data.itemListData.concat([target.data])
                });
        },
        unlinked(target) {
            this.children = this.children.filter((child) => child !== target);
        }
    },
    props: {
        activeColor: String,
        overlay: {
            type: Boolean,
            value: true
        },
        zIndex: {
            type: Number,
            value: 10
        },
        duration: {
            type: Number,
            value: 200
        },
        direction: {
            type: String,
            value: 'down'
        },
        closeOnClickOverlay: {
            type: Boolean,
            value: true
        },
        closeOnClickOutside: {
            type: Boolean,
            value: true
        }
    },
    data: {
        itemListData: []
    },
    created() {
        ARRAY.push(this);
    },
    destroyed() {
        ARRAY = ARRAY.filter(item => item !== this);
    },
    methods: {
        updateChildData(childItem, newData, needRefreshList = false) {
            childItem.setData(newData);
            if (needRefreshList) {
                // dropdown-item data 更新,涉及到 title 的展示,触发模板更新
                this.setData({ itemListData: this.data.itemListData });
            }
        },
        toggleItem(active) {
            this.children.forEach((item, index) => {
                const { showPopup } = item.data;
                if (index === active) {
                    this.toggleChildItem(item);
                }
                else if (showPopup) {
                    this.toggleChildItem(item, false, { immediate: true });
                }
            });
        },
        toggleChildItem(childItem, show, options = {}) {
            const { showPopup, duration } = childItem.data;
            if (show === undefined)
                show = !showPopup;
            if (show === showPopup) {
                return;
            }
            const newChildData = { transition: !options.immediate, showPopup: show };
            if (!show) {
                const time = options.immediate ? 0 : duration;
                this.updateChildData(childItem, Object.assign({}, newChildData), true);
                setTimeout(() => {
                    this.updateChildData(childItem, { showWrapper: false }, true);
                }, time);
                return;
            }
            this.getChildWrapperStyle().then((wrapperStyle = '') => {
                this.updateChildData(childItem, Object.assign(Object.assign({}, newChildData), { wrapperStyle, showWrapper: true }), true);
            });
        },
        close() {
            this.children.forEach((item) => {
                this.toggleChildItem(item, false, { immediate: true });
            });
        },
        getChildWrapperStyle() {
            const { windowHeight } = wx.getSystemInfoSync();
            const { zIndex, direction } = this.data;
            let offset = 0;
            return this.getRect('.van-dropdown-menu').then(rect => {
                const { top = 0, bottom = 0 } = rect;
                if (direction === 'down') {
                    offset = bottom;
                }
                else {
                    offset = windowHeight - top;
                }
                let wrapperStyle = `z-index: ${zIndex};`;
                if (direction === 'down') {
                    wrapperStyle += `top: ${addUnit(offset)};`;
                }
                else {
                    wrapperStyle += `bottom: ${addUnit(offset)};`;
                }
                return Promise.resolve(wrapperStyle);
            });
        },
        onTitleTap(event) {
            // item ---> dropdown-item
            const { item, index } = event.currentTarget.dataset;
            if (!item.disabled) {
                // menuItem ---> dropdown-menu
                ARRAY.forEach(menuItem => {
                    if (menuItem && menuItem.data.closeOnClickOutside && menuItem !== this) {
                        menuItem.close();
                    }
                });
                this.toggleItem(index);
            }
        }
    }
});