20 changed files with 1202 additions and 632 deletions
			
			
		@ -1,197 +1,233 @@
					 | 
				
			||||
import { BLUE, WHITE } from '../common/color'; | 
				
			||||
import { VantComponent } from '../common/component'; | 
				
			||||
import { getSystemInfoSync } from '../common/utils'; | 
				
			||||
import { isObj } from '../common/validator'; | 
				
			||||
import { canIUseCanvas2d } from '../common/version'; | 
				
			||||
import { adaptor } from './canvas'; | 
				
			||||
import { | 
				
			||||
	BLUE, | 
				
			||||
	WHITE | 
				
			||||
} from '../common/color'; | 
				
			||||
import { | 
				
			||||
	VantComponent | 
				
			||||
} from '../common/component'; | 
				
			||||
import { | 
				
			||||
	getSystemInfoSync | 
				
			||||
} from '../common/utils'; | 
				
			||||
import { | 
				
			||||
	isObj | 
				
			||||
} from '../common/validator'; | 
				
			||||
import { | 
				
			||||
	canIUseCanvas2d | 
				
			||||
} from '../common/version'; | 
				
			||||
import { | 
				
			||||
	adaptor | 
				
			||||
} from './canvas'; | 
				
			||||
 | 
				
			||||
function format(rate) { | 
				
			||||
    return Math.min(Math.max(rate, 0), 100); | 
				
			||||
	return Math.min(Math.max(rate, 0), 100); | 
				
			||||
} | 
				
			||||
const PERIMETER = 2 * Math.PI; | 
				
			||||
const BEGIN_ANGLE = -Math.PI / 2; | 
				
			||||
const STEP = 1; | 
				
			||||
VantComponent({ | 
				
			||||
    props: { | 
				
			||||
        text: String, | 
				
			||||
        lineCap: { | 
				
			||||
            type: String, | 
				
			||||
            value: 'round', | 
				
			||||
        }, | 
				
			||||
        value: { | 
				
			||||
            type: Number, | 
				
			||||
            value: 0, | 
				
			||||
            observer: 'reRender', | 
				
			||||
        }, | 
				
			||||
        speed: { | 
				
			||||
            type: Number, | 
				
			||||
            value: 50, | 
				
			||||
        }, | 
				
			||||
        size: { | 
				
			||||
            type: Number, | 
				
			||||
            value: 100, | 
				
			||||
            observer() { | 
				
			||||
                this.drawCircle(this.currentValue); | 
				
			||||
            }, | 
				
			||||
        }, | 
				
			||||
        fill: String, | 
				
			||||
        layerColor: { | 
				
			||||
            type: String, | 
				
			||||
            value: WHITE, | 
				
			||||
        }, | 
				
			||||
        color: { | 
				
			||||
            type: null, | 
				
			||||
            value: BLUE, | 
				
			||||
            observer() { | 
				
			||||
                this.setHoverColor().then(() => { | 
				
			||||
                    this.drawCircle(this.currentValue); | 
				
			||||
                }); | 
				
			||||
            }, | 
				
			||||
        }, | 
				
			||||
        type: { | 
				
			||||
            type: String, | 
				
			||||
            value: '', | 
				
			||||
        }, | 
				
			||||
        strokeWidth: { | 
				
			||||
            type: Number, | 
				
			||||
            value: 4, | 
				
			||||
        }, | 
				
			||||
        clockwise: { | 
				
			||||
            type: Boolean, | 
				
			||||
            value: true, | 
				
			||||
        }, | 
				
			||||
    }, | 
				
			||||
    data: { | 
				
			||||
        hoverColor: BLUE, | 
				
			||||
    }, | 
				
			||||
    methods: { | 
				
			||||
        getContext() { | 
				
			||||
            const { type, size } = this.data; | 
				
			||||
            if (type === '' || !canIUseCanvas2d()) { | 
				
			||||
                const ctx = wx.createCanvasContext('van-circle', this); | 
				
			||||
                return Promise.resolve(ctx); | 
				
			||||
            } | 
				
			||||
            const dpr = getSystemInfoSync().pixelRatio; | 
				
			||||
            return new Promise((resolve) => { | 
				
			||||
                wx.createSelectorQuery() | 
				
			||||
                    .in(this) | 
				
			||||
                    .select('#van-circle') | 
				
			||||
                    .node() | 
				
			||||
                    .exec((res) => { | 
				
			||||
                    const canvas = res[0].node; | 
				
			||||
                    const ctx = canvas.getContext(type); | 
				
			||||
                    if (!this.inited) { | 
				
			||||
                        this.inited = true; | 
				
			||||
                        canvas.width = size * dpr; | 
				
			||||
                        canvas.height = size * dpr; | 
				
			||||
                        ctx.scale(dpr, dpr); | 
				
			||||
                    } | 
				
			||||
                    resolve(adaptor(ctx)); | 
				
			||||
                }); | 
				
			||||
            }); | 
				
			||||
        }, | 
				
			||||
        setHoverColor() { | 
				
			||||
            const { color, size } = this.data; | 
				
			||||
            if (isObj(color)) { | 
				
			||||
                return this.getContext().then((context) => { | 
				
			||||
                    if (!context) | 
				
			||||
                        return; | 
				
			||||
                    const LinearColor = context.createLinearGradient(size, 0, 0, 0); | 
				
			||||
                    Object.keys(color) | 
				
			||||
                        .sort((a, b) => parseFloat(a) - parseFloat(b)) | 
				
			||||
                        .map((key) => LinearColor.addColorStop(parseFloat(key) / 100, color[key])); | 
				
			||||
                    this.hoverColor = LinearColor; | 
				
			||||
                }); | 
				
			||||
            } | 
				
			||||
            this.hoverColor = color; | 
				
			||||
            return Promise.resolve(); | 
				
			||||
        }, | 
				
			||||
        presetCanvas(context, strokeStyle, beginAngle, endAngle, fill) { | 
				
			||||
            const { strokeWidth, lineCap, clockwise, size } = this.data; | 
				
			||||
            const position = size / 2; | 
				
			||||
            const radius = position - strokeWidth / 2; | 
				
			||||
            context.setStrokeStyle(strokeStyle); | 
				
			||||
            context.setLineWidth(strokeWidth); | 
				
			||||
            context.setLineCap(lineCap); | 
				
			||||
            context.beginPath(); | 
				
			||||
            context.arc(position, position, radius, beginAngle, endAngle, !clockwise); | 
				
			||||
            context.stroke(); | 
				
			||||
            if (fill) { | 
				
			||||
                context.setFillStyle(fill); | 
				
			||||
                context.fill(); | 
				
			||||
            } | 
				
			||||
        }, | 
				
			||||
        renderLayerCircle(context) { | 
				
			||||
            const { layerColor, fill } = this.data; | 
				
			||||
            this.presetCanvas(context, layerColor, 0, PERIMETER, fill); | 
				
			||||
        }, | 
				
			||||
        renderHoverCircle(context, formatValue) { | 
				
			||||
            const { clockwise } = this.data; | 
				
			||||
            // 结束角度
 | 
				
			||||
            const progress = PERIMETER * (formatValue / 100); | 
				
			||||
            const endAngle = clockwise | 
				
			||||
                ? BEGIN_ANGLE + progress | 
				
			||||
                : 3 * Math.PI - (BEGIN_ANGLE + progress); | 
				
			||||
            this.presetCanvas(context, this.hoverColor, BEGIN_ANGLE, endAngle); | 
				
			||||
        }, | 
				
			||||
        drawCircle(currentValue) { | 
				
			||||
            const { size } = this.data; | 
				
			||||
            this.getContext().then((context) => { | 
				
			||||
                if (!context) | 
				
			||||
                    return; | 
				
			||||
                context.clearRect(0, 0, size, size); | 
				
			||||
                this.renderLayerCircle(context); | 
				
			||||
                const formatValue = format(currentValue); | 
				
			||||
                if (formatValue !== 0) { | 
				
			||||
                    this.renderHoverCircle(context, formatValue); | 
				
			||||
                } | 
				
			||||
                context.draw(); | 
				
			||||
            }); | 
				
			||||
        }, | 
				
			||||
        reRender() { | 
				
			||||
            // tofector 动画暂时没有想到好的解决方案
 | 
				
			||||
            const { value, speed } = this.data; | 
				
			||||
            if (speed <= 0 || speed > 1000) { | 
				
			||||
                this.drawCircle(value); | 
				
			||||
                return; | 
				
			||||
            } | 
				
			||||
            this.clearMockInterval(); | 
				
			||||
            this.currentValue = this.currentValue || 0; | 
				
			||||
            const run = () => { | 
				
			||||
                this.interval = setTimeout(() => { | 
				
			||||
                    if (this.currentValue !== value) { | 
				
			||||
                        if (Math.abs(this.currentValue - value) < STEP) { | 
				
			||||
                            this.currentValue = value; | 
				
			||||
                        } | 
				
			||||
                        else if (this.currentValue < value) { | 
				
			||||
                            this.currentValue += STEP; | 
				
			||||
                        } | 
				
			||||
                        else { | 
				
			||||
                            this.currentValue -= STEP; | 
				
			||||
                        } | 
				
			||||
                        this.drawCircle(this.currentValue); | 
				
			||||
                        run(); | 
				
			||||
                    } | 
				
			||||
                    else { | 
				
			||||
                        this.clearMockInterval(); | 
				
			||||
                    } | 
				
			||||
                }, 1000 / speed); | 
				
			||||
            }; | 
				
			||||
            run(); | 
				
			||||
        }, | 
				
			||||
        clearMockInterval() { | 
				
			||||
            if (this.interval) { | 
				
			||||
                clearTimeout(this.interval); | 
				
			||||
                this.interval = null; | 
				
			||||
            } | 
				
			||||
        }, | 
				
			||||
    }, | 
				
			||||
    mounted() { | 
				
			||||
        this.currentValue = this.data.value; | 
				
			||||
        this.setHoverColor().then(() => { | 
				
			||||
            this.drawCircle(this.currentValue); | 
				
			||||
        }); | 
				
			||||
    }, | 
				
			||||
    destroyed() { | 
				
			||||
        this.clearMockInterval(); | 
				
			||||
    }, | 
				
			||||
}); | 
				
			||||
	props: { | 
				
			||||
		text: String, | 
				
			||||
		lineCap: { | 
				
			||||
			type: String, | 
				
			||||
			value: 'round', | 
				
			||||
		}, | 
				
			||||
		value: { | 
				
			||||
			type: Number, | 
				
			||||
			value: 0, | 
				
			||||
			observer: 'reRender', | 
				
			||||
		}, | 
				
			||||
		speed: { | 
				
			||||
			type: Number, | 
				
			||||
			value: 50, | 
				
			||||
		}, | 
				
			||||
		size: { | 
				
			||||
			type: Number, | 
				
			||||
			value: 100, | 
				
			||||
			observer() { | 
				
			||||
				this.drawCircle(this.currentValue); | 
				
			||||
			}, | 
				
			||||
		}, | 
				
			||||
		fill: String, | 
				
			||||
		layerColor: { | 
				
			||||
			type: String, | 
				
			||||
			value: WHITE, | 
				
			||||
		}, | 
				
			||||
		color: { | 
				
			||||
			type: null, | 
				
			||||
			value: BLUE, | 
				
			||||
			observer() { | 
				
			||||
				this.setHoverColor().then(() => { | 
				
			||||
					this.drawCircle(this.currentValue); | 
				
			||||
				}); | 
				
			||||
			}, | 
				
			||||
		}, | 
				
			||||
		type: { | 
				
			||||
			type: String, | 
				
			||||
			value: '', | 
				
			||||
		}, | 
				
			||||
		strokeWidth: { | 
				
			||||
			type: Number, | 
				
			||||
			value: 4, | 
				
			||||
		}, | 
				
			||||
		clockwise: { | 
				
			||||
			type: Boolean, | 
				
			||||
			value: true, | 
				
			||||
		}, | 
				
			||||
		canvasId: { | 
				
			||||
			type: String, | 
				
			||||
			value: '' | 
				
			||||
		} | 
				
			||||
	}, | 
				
			||||
	data: { | 
				
			||||
		hoverColor: BLUE, | 
				
			||||
	}, | 
				
			||||
	methods: { | 
				
			||||
		getContext() { | 
				
			||||
			const { | 
				
			||||
				type, | 
				
			||||
				size | 
				
			||||
			} = this.data; | 
				
			||||
			if (type === '' || !canIUseCanvas2d()) { | 
				
			||||
				const ctx = wx.createCanvasContext('van-circle', this); | 
				
			||||
				return Promise.resolve(ctx); | 
				
			||||
			} | 
				
			||||
			const dpr = getSystemInfoSync().pixelRatio; | 
				
			||||
			return new Promise((resolve) => { | 
				
			||||
				wx.createSelectorQuery() | 
				
			||||
					.in(this) | 
				
			||||
					.select('#van-circle') | 
				
			||||
					.node() | 
				
			||||
					.exec((res) => { | 
				
			||||
						const canvas = res[0].node; | 
				
			||||
						const ctx = canvas.getContext(type); | 
				
			||||
						if (!this.inited) { | 
				
			||||
							this.inited = true; | 
				
			||||
							canvas.width = size * dpr; | 
				
			||||
							canvas.height = size * dpr; | 
				
			||||
							ctx.scale(dpr, dpr); | 
				
			||||
						} | 
				
			||||
						resolve(adaptor(ctx)); | 
				
			||||
					}); | 
				
			||||
			}); | 
				
			||||
		}, | 
				
			||||
		setHoverColor() { | 
				
			||||
			const { | 
				
			||||
				color, | 
				
			||||
				size | 
				
			||||
			} = this.data; | 
				
			||||
			if (isObj(color)) { | 
				
			||||
				return this.getContext().then((context) => { | 
				
			||||
					if (!context) | 
				
			||||
						return; | 
				
			||||
					const LinearColor = context.createLinearGradient(size, 0, 0, 0); | 
				
			||||
					Object.keys(color) | 
				
			||||
						.sort((a, b) => parseFloat(a) - parseFloat(b)) | 
				
			||||
						.map((key) => LinearColor.addColorStop(parseFloat(key) / 100, color[key])); | 
				
			||||
					this.hoverColor = LinearColor; | 
				
			||||
				}); | 
				
			||||
			} | 
				
			||||
			this.hoverColor = color; | 
				
			||||
			return Promise.resolve(); | 
				
			||||
		}, | 
				
			||||
		presetCanvas(context, strokeStyle, beginAngle, endAngle, fill) { | 
				
			||||
			const { | 
				
			||||
				strokeWidth, | 
				
			||||
				lineCap, | 
				
			||||
				clockwise, | 
				
			||||
				size | 
				
			||||
			} = this.data; | 
				
			||||
			const position = size / 2; | 
				
			||||
			const radius = position - strokeWidth / 2; | 
				
			||||
			context.setStrokeStyle(strokeStyle); | 
				
			||||
			context.setLineWidth(strokeWidth); | 
				
			||||
			context.setLineCap(lineCap); | 
				
			||||
			context.beginPath(); | 
				
			||||
			context.arc(position, position, radius, beginAngle, endAngle, !clockwise); | 
				
			||||
			context.stroke(); | 
				
			||||
			if (fill) { | 
				
			||||
				context.setFillStyle(fill); | 
				
			||||
				context.fill(); | 
				
			||||
			} | 
				
			||||
		}, | 
				
			||||
		renderLayerCircle(context) { | 
				
			||||
			const { | 
				
			||||
				layerColor, | 
				
			||||
				fill | 
				
			||||
			} = this.data; | 
				
			||||
			this.presetCanvas(context, layerColor, 0, PERIMETER, fill); | 
				
			||||
		}, | 
				
			||||
		renderHoverCircle(context, formatValue) { | 
				
			||||
			const { | 
				
			||||
				clockwise | 
				
			||||
			} = this.data; | 
				
			||||
			// 结束角度
 | 
				
			||||
			const progress = PERIMETER * (formatValue / 100); | 
				
			||||
			const endAngle = clockwise ? | 
				
			||||
				BEGIN_ANGLE + progress : | 
				
			||||
				3 * Math.PI - (BEGIN_ANGLE + progress); | 
				
			||||
			this.presetCanvas(context, this.hoverColor, BEGIN_ANGLE, endAngle); | 
				
			||||
		}, | 
				
			||||
		drawCircle(currentValue) { | 
				
			||||
			const { | 
				
			||||
				size | 
				
			||||
			} = this.data; | 
				
			||||
			this.getContext().then((context) => { | 
				
			||||
				if (!context) | 
				
			||||
					return; | 
				
			||||
				context.clearRect(0, 0, size, size); | 
				
			||||
				this.renderLayerCircle(context); | 
				
			||||
				const formatValue = format(currentValue); | 
				
			||||
				if (formatValue !== 0) { | 
				
			||||
					this.renderHoverCircle(context, formatValue); | 
				
			||||
				} | 
				
			||||
				context.draw(); | 
				
			||||
			}); | 
				
			||||
		}, | 
				
			||||
		reRender() { | 
				
			||||
			// tofector 动画暂时没有想到好的解决方案
 | 
				
			||||
			const { | 
				
			||||
				value, | 
				
			||||
				speed | 
				
			||||
			} = this.data; | 
				
			||||
			if (speed <= 0 || speed > 1000) { | 
				
			||||
				this.drawCircle(value); | 
				
			||||
				return; | 
				
			||||
			} | 
				
			||||
			this.clearMockInterval(); | 
				
			||||
			this.currentValue = this.currentValue || 0; | 
				
			||||
			const run = () => { | 
				
			||||
				this.interval = setTimeout(() => { | 
				
			||||
					if (this.currentValue !== value) { | 
				
			||||
						if (Math.abs(this.currentValue - value) < STEP) { | 
				
			||||
							this.currentValue = value; | 
				
			||||
						} else if (this.currentValue < value) { | 
				
			||||
							this.currentValue += STEP; | 
				
			||||
						} else { | 
				
			||||
							this.currentValue -= STEP; | 
				
			||||
						} | 
				
			||||
						this.drawCircle(this.currentValue); | 
				
			||||
						run(); | 
				
			||||
					} else { | 
				
			||||
						this.clearMockInterval(); | 
				
			||||
					} | 
				
			||||
				}, 1000 / speed); | 
				
			||||
			}; | 
				
			||||
			run(); | 
				
			||||
		}, | 
				
			||||
		clearMockInterval() { | 
				
			||||
			if (this.interval) { | 
				
			||||
				clearTimeout(this.interval); | 
				
			||||
				this.interval = null; | 
				
			||||
			} | 
				
			||||
		}, | 
				
			||||
	}, | 
				
			||||
	mounted() { | 
				
			||||
		this.currentValue = this.data.value; | 
				
			||||
		this.setHoverColor().then(() => { | 
				
			||||
			this.drawCircle(this.currentValue); | 
				
			||||
		}); | 
				
			||||
	}, | 
				
			||||
	destroyed() { | 
				
			||||
		this.clearMockInterval(); | 
				
			||||
	}, | 
				
			||||
}); | 
				
			||||
@ -1 +1,16 @@
					 | 
				
			||||
@import '../common/index.wxss';.van-circle{display:inline-block;position:relative;text-align:center}.van-circle__text{color:var(--circle-text-color,#323233);left:0;position:absolute;top:50%;transform:translateY(-50%);width:100%} | 
				
			||||
@import '../common/index.wxss'; | 
				
			||||
 | 
				
			||||
.van-circle { | 
				
			||||
	display: inline-block; | 
				
			||||
	position: relative; | 
				
			||||
	text-align: center | 
				
			||||
} | 
				
			||||
 | 
				
			||||
.van-circle__text { | 
				
			||||
	color: var(--circle-text-color, #323233); | 
				
			||||
	left: 0; | 
				
			||||
	position: absolute; | 
				
			||||
	top: 50%; | 
				
			||||
	transform: translateY(-50%); | 
				
			||||
	width: 100% | 
				
			||||
} | 
				
			||||
@ -1,130 +1,157 @@
					 | 
				
			||||
import { useParent } from '../common/relation'; | 
				
			||||
import { VantComponent } from '../common/component'; | 
				
			||||
import { | 
				
			||||
	useParent | 
				
			||||
} from '../common/relation'; | 
				
			||||
import { | 
				
			||||
	VantComponent | 
				
			||||
} from '../common/component'; | 
				
			||||
VantComponent({ | 
				
			||||
    classes: ['item-title-class'], | 
				
			||||
    field: true, | 
				
			||||
    relation: useParent('dropdown-menu', function () { | 
				
			||||
        this.updateDataFromParent(); | 
				
			||||
    }), | 
				
			||||
    props: { | 
				
			||||
        value: { | 
				
			||||
            type: null, | 
				
			||||
            observer: 'rerender', | 
				
			||||
        }, | 
				
			||||
        title: { | 
				
			||||
            type: String, | 
				
			||||
            observer: 'rerender', | 
				
			||||
        }, | 
				
			||||
        disabled: Boolean, | 
				
			||||
        titleClass: { | 
				
			||||
            type: String, | 
				
			||||
            observer: 'rerender', | 
				
			||||
        }, | 
				
			||||
        options: { | 
				
			||||
            type: Array, | 
				
			||||
            value: [], | 
				
			||||
            observer: 'rerender', | 
				
			||||
        }, | 
				
			||||
        popupStyle: String, | 
				
			||||
        useBeforeToggle: { | 
				
			||||
            type: Boolean, | 
				
			||||
            value: false, | 
				
			||||
        }, | 
				
			||||
        rootPortal: { | 
				
			||||
            type: Boolean, | 
				
			||||
            value: false, | 
				
			||||
        }, | 
				
			||||
    }, | 
				
			||||
    data: { | 
				
			||||
        transition: true, | 
				
			||||
        showPopup: false, | 
				
			||||
        showWrapper: false, | 
				
			||||
        displayTitle: '', | 
				
			||||
        safeAreaTabBar: false, | 
				
			||||
    }, | 
				
			||||
    methods: { | 
				
			||||
        rerender() { | 
				
			||||
            wx.nextTick(() => { | 
				
			||||
                var _a; | 
				
			||||
                (_a = this.parent) === null || _a === void 0 ? void 0 : _a.updateItemListData(); | 
				
			||||
            }); | 
				
			||||
        }, | 
				
			||||
        updateDataFromParent() { | 
				
			||||
            if (this.parent) { | 
				
			||||
                const { overlay, duration, activeColor, closeOnClickOverlay, direction, safeAreaTabBar, } = this.parent.data; | 
				
			||||
                this.setData({ | 
				
			||||
                    overlay, | 
				
			||||
                    duration, | 
				
			||||
                    activeColor, | 
				
			||||
                    closeOnClickOverlay, | 
				
			||||
                    direction, | 
				
			||||
                    safeAreaTabBar, | 
				
			||||
                }); | 
				
			||||
            } | 
				
			||||
        }, | 
				
			||||
        onOpen() { | 
				
			||||
            this.$emit('open'); | 
				
			||||
        }, | 
				
			||||
        onOpened() { | 
				
			||||
            this.$emit('opened'); | 
				
			||||
        }, | 
				
			||||
        onClose() { | 
				
			||||
            this.$emit('close'); | 
				
			||||
        }, | 
				
			||||
        onClosed() { | 
				
			||||
            this.$emit('closed'); | 
				
			||||
            this.setData({ showWrapper: false }); | 
				
			||||
        }, | 
				
			||||
        onOptionTap(event) { | 
				
			||||
            const { option } = event.currentTarget.dataset; | 
				
			||||
            const { value } = option; | 
				
			||||
            const shouldEmitChange = this.data.value !== value; | 
				
			||||
            this.setData({ showPopup: false, value }); | 
				
			||||
            this.$emit('close'); | 
				
			||||
            this.rerender(); | 
				
			||||
            if (shouldEmitChange) { | 
				
			||||
                this.$emit('change', value); | 
				
			||||
            } | 
				
			||||
        }, | 
				
			||||
        toggle(show, options = {}) { | 
				
			||||
            const { showPopup } = this.data; | 
				
			||||
            if (typeof show !== 'boolean') { | 
				
			||||
                show = !showPopup; | 
				
			||||
            } | 
				
			||||
            if (show === showPopup) { | 
				
			||||
                return; | 
				
			||||
            } | 
				
			||||
            this.onBeforeToggle(show).then((status) => { | 
				
			||||
                var _a; | 
				
			||||
                if (!status) { | 
				
			||||
                    return; | 
				
			||||
                } | 
				
			||||
                this.setData({ | 
				
			||||
                    transition: !options.immediate, | 
				
			||||
                    showPopup: show, | 
				
			||||
                }); | 
				
			||||
                if (show) { | 
				
			||||
                    (_a = this.parent) === null || _a === void 0 ? void 0 : _a.getChildWrapperStyle().then((wrapperStyle) => { | 
				
			||||
                        this.setData({ wrapperStyle, showWrapper: true }); | 
				
			||||
                        this.rerender(); | 
				
			||||
                    }); | 
				
			||||
                } | 
				
			||||
                else { | 
				
			||||
                    this.rerender(); | 
				
			||||
                } | 
				
			||||
            }); | 
				
			||||
        }, | 
				
			||||
        onBeforeToggle(status) { | 
				
			||||
            const { useBeforeToggle } = this.data; | 
				
			||||
            if (!useBeforeToggle) { | 
				
			||||
                return Promise.resolve(true); | 
				
			||||
            } | 
				
			||||
            return new Promise((resolve) => { | 
				
			||||
                this.$emit('before-toggle', { | 
				
			||||
                    status, | 
				
			||||
                    callback: (value) => resolve(value), | 
				
			||||
                }); | 
				
			||||
            }); | 
				
			||||
        }, | 
				
			||||
    }, | 
				
			||||
}); | 
				
			||||
	classes: ['item-title-class'], | 
				
			||||
	field: true, | 
				
			||||
	relation: useParent('dropdown-menu', function() { | 
				
			||||
		this.updateDataFromParent(); | 
				
			||||
	}), | 
				
			||||
	props: { | 
				
			||||
		value: { | 
				
			||||
			type: null, | 
				
			||||
			observer: 'rerender', | 
				
			||||
		}, | 
				
			||||
		title: { | 
				
			||||
			type: String, | 
				
			||||
			observer: 'rerender', | 
				
			||||
		}, | 
				
			||||
		disabled: Boolean, | 
				
			||||
		titleClass: { | 
				
			||||
			type: String, | 
				
			||||
			observer: 'rerender', | 
				
			||||
		}, | 
				
			||||
		options: { | 
				
			||||
			type: Array, | 
				
			||||
			value: [], | 
				
			||||
			observer: 'rerender', | 
				
			||||
		}, | 
				
			||||
		popupStyle: String, | 
				
			||||
		useBeforeToggle: { | 
				
			||||
			type: Boolean, | 
				
			||||
			value: false, | 
				
			||||
		}, | 
				
			||||
		rootPortal: { | 
				
			||||
			type: Boolean, | 
				
			||||
			value: false, | 
				
			||||
		}, | 
				
			||||
	}, | 
				
			||||
	data: { | 
				
			||||
		transition: true, | 
				
			||||
		showPopup: false, | 
				
			||||
		showWrapper: false, | 
				
			||||
		displayTitle: '', | 
				
			||||
		safeAreaTabBar: false, | 
				
			||||
	}, | 
				
			||||
	methods: { | 
				
			||||
		rerender() { | 
				
			||||
			wx.nextTick(() => { | 
				
			||||
				var _a; | 
				
			||||
				(_a = this.parent) === null || _a === void 0 ? void 0 : _a.updateItemListData(); | 
				
			||||
			}); | 
				
			||||
		}, | 
				
			||||
		updateDataFromParent() { | 
				
			||||
			if (this.parent) { | 
				
			||||
				const { | 
				
			||||
					overlay, | 
				
			||||
					duration, | 
				
			||||
					activeColor, | 
				
			||||
					closeOnClickOverlay, | 
				
			||||
					direction, | 
				
			||||
					safeAreaTabBar, | 
				
			||||
				} = this.parent.data; | 
				
			||||
				this.setData({ | 
				
			||||
					overlay, | 
				
			||||
					duration, | 
				
			||||
					activeColor, | 
				
			||||
					closeOnClickOverlay, | 
				
			||||
					direction, | 
				
			||||
					safeAreaTabBar, | 
				
			||||
				}); | 
				
			||||
			} | 
				
			||||
		}, | 
				
			||||
		onOpen() { | 
				
			||||
			this.$emit('open'); | 
				
			||||
		}, | 
				
			||||
		onOpened() { | 
				
			||||
			this.$emit('opened'); | 
				
			||||
		}, | 
				
			||||
		onClose() { | 
				
			||||
			this.$emit('close'); | 
				
			||||
		}, | 
				
			||||
		onClosed() { | 
				
			||||
			this.$emit('closed'); | 
				
			||||
			this.setData({ | 
				
			||||
				showWrapper: false | 
				
			||||
			}); | 
				
			||||
		}, | 
				
			||||
		onOptionTap(event) { | 
				
			||||
			const { | 
				
			||||
				option | 
				
			||||
			} = event.currentTarget.dataset; | 
				
			||||
			const { | 
				
			||||
				value | 
				
			||||
			} = option; | 
				
			||||
			const shouldEmitChange = this.data.value !== value; | 
				
			||||
			this.setData({ | 
				
			||||
				showPopup: false, | 
				
			||||
				value | 
				
			||||
			}); | 
				
			||||
			this.$emit('close'); | 
				
			||||
			this.rerender(); | 
				
			||||
			if (shouldEmitChange) { | 
				
			||||
				this.$emit('change', value); | 
				
			||||
			} | 
				
			||||
		}, | 
				
			||||
		toggle(show, options = {}) { | 
				
			||||
			const { | 
				
			||||
				showPopup | 
				
			||||
			} = this.data; | 
				
			||||
			if (typeof show !== 'boolean') { | 
				
			||||
				show = !showPopup; | 
				
			||||
			} | 
				
			||||
			if (show === showPopup) { | 
				
			||||
				return; | 
				
			||||
			} | 
				
			||||
			this.onBeforeToggle(show).then((status) => { | 
				
			||||
				var _a; | 
				
			||||
				if (!status) { | 
				
			||||
					return; | 
				
			||||
				} | 
				
			||||
				this.setData({ | 
				
			||||
					transition: !options.immediate, | 
				
			||||
					showPopup: show, | 
				
			||||
				}); | 
				
			||||
				if (show) { | 
				
			||||
					(_a = this.parent) === null || _a === void 0 ? void 0 : _a.getChildWrapperStyle().then(( | 
				
			||||
						wrapperStyle) => { | 
				
			||||
						this.setData({ | 
				
			||||
							wrapperStyle, | 
				
			||||
							showWrapper: true | 
				
			||||
						}); | 
				
			||||
						this.rerender(); | 
				
			||||
					}); | 
				
			||||
				} else { | 
				
			||||
					this.rerender(); | 
				
			||||
				} | 
				
			||||
			}); | 
				
			||||
		}, | 
				
			||||
		onBeforeToggle(status) { | 
				
			||||
			const { | 
				
			||||
				useBeforeToggle | 
				
			||||
			} = this.data; | 
				
			||||
			if (!useBeforeToggle) { | 
				
			||||
				return Promise.resolve(true); | 
				
			||||
			} | 
				
			||||
			return new Promise((resolve) => { | 
				
			||||
				this.$emit('before-toggle', { | 
				
			||||
					status, | 
				
			||||
					callback: (value) => resolve(value), | 
				
			||||
				}); | 
				
			||||
			}); | 
				
			||||
		}, | 
				
			||||
	}, | 
				
			||||
}); | 
				
			||||
@ -1,117 +1,139 @@
					 | 
				
			||||
import { VantComponent } from '../common/component'; | 
				
			||||
import { useChildren } from '../common/relation'; | 
				
			||||
import { addUnit, getRect, getSystemInfoSync } from '../common/utils'; | 
				
			||||
import { | 
				
			||||
	VantComponent | 
				
			||||
} from '../common/component'; | 
				
			||||
import { | 
				
			||||
	useChildren | 
				
			||||
} from '../common/relation'; | 
				
			||||
import { | 
				
			||||
	addUnit, | 
				
			||||
	getRect, | 
				
			||||
	getSystemInfoSync | 
				
			||||
} from '../common/utils'; | 
				
			||||
let ARRAY = []; | 
				
			||||
VantComponent({ | 
				
			||||
    field: true, | 
				
			||||
    classes: ['title-class'], | 
				
			||||
    relation: useChildren('dropdown-item', function () { | 
				
			||||
        this.updateItemListData(); | 
				
			||||
    }), | 
				
			||||
    props: { | 
				
			||||
        activeColor: { | 
				
			||||
            type: String, | 
				
			||||
            observer: 'updateChildrenData', | 
				
			||||
        }, | 
				
			||||
        overlay: { | 
				
			||||
            type: Boolean, | 
				
			||||
            value: true, | 
				
			||||
            observer: 'updateChildrenData', | 
				
			||||
        }, | 
				
			||||
        zIndex: { | 
				
			||||
            type: Number, | 
				
			||||
            value: 10, | 
				
			||||
        }, | 
				
			||||
        duration: { | 
				
			||||
            type: Number, | 
				
			||||
            value: 200, | 
				
			||||
            observer: 'updateChildrenData', | 
				
			||||
        }, | 
				
			||||
        direction: { | 
				
			||||
            type: String, | 
				
			||||
            value: 'down', | 
				
			||||
            observer: 'updateChildrenData', | 
				
			||||
        }, | 
				
			||||
        safeAreaTabBar: { | 
				
			||||
            type: Boolean, | 
				
			||||
            value: false, | 
				
			||||
        }, | 
				
			||||
        closeOnClickOverlay: { | 
				
			||||
            type: Boolean, | 
				
			||||
            value: true, | 
				
			||||
            observer: 'updateChildrenData', | 
				
			||||
        }, | 
				
			||||
        closeOnClickOutside: { | 
				
			||||
            type: Boolean, | 
				
			||||
            value: true, | 
				
			||||
        }, | 
				
			||||
    }, | 
				
			||||
    data: { | 
				
			||||
        itemListData: [], | 
				
			||||
    }, | 
				
			||||
    beforeCreate() { | 
				
			||||
        const { windowHeight } = getSystemInfoSync(); | 
				
			||||
        this.windowHeight = windowHeight; | 
				
			||||
        ARRAY.push(this); | 
				
			||||
    }, | 
				
			||||
    destroyed() { | 
				
			||||
        ARRAY = ARRAY.filter((item) => item !== this); | 
				
			||||
    }, | 
				
			||||
    methods: { | 
				
			||||
        updateItemListData() { | 
				
			||||
            this.setData({ | 
				
			||||
                itemListData: this.children.map((child) => child.data), | 
				
			||||
            }); | 
				
			||||
        }, | 
				
			||||
        updateChildrenData() { | 
				
			||||
            this.children.forEach((child) => { | 
				
			||||
                child.updateDataFromParent(); | 
				
			||||
            }); | 
				
			||||
        }, | 
				
			||||
        toggleItem(active) { | 
				
			||||
            this.children.forEach((item, index) => { | 
				
			||||
                const { showPopup } = item.data; | 
				
			||||
                if (index === active) { | 
				
			||||
                    item.toggle(); | 
				
			||||
                } | 
				
			||||
                else if (showPopup) { | 
				
			||||
                    item.toggle(false, { immediate: true }); | 
				
			||||
                } | 
				
			||||
            }); | 
				
			||||
        }, | 
				
			||||
        close() { | 
				
			||||
            this.children.forEach((child) => { | 
				
			||||
                child.toggle(false, { immediate: true }); | 
				
			||||
            }); | 
				
			||||
        }, | 
				
			||||
        getChildWrapperStyle() { | 
				
			||||
            const { zIndex, direction } = this.data; | 
				
			||||
            return getRect(this, '.van-dropdown-menu').then((rect) => { | 
				
			||||
                const { top = 0, bottom = 0 } = rect; | 
				
			||||
                const offset = direction === 'down' ? bottom : this.windowHeight - top; | 
				
			||||
                let wrapperStyle = `z-index: ${zIndex};`; | 
				
			||||
                if (direction === 'down') { | 
				
			||||
                    wrapperStyle += `top: ${addUnit(offset)};`; | 
				
			||||
                } | 
				
			||||
                else { | 
				
			||||
                    wrapperStyle += `bottom: ${addUnit(offset)};`; | 
				
			||||
                } | 
				
			||||
                return wrapperStyle; | 
				
			||||
            }); | 
				
			||||
        }, | 
				
			||||
        onTitleTap(event) { | 
				
			||||
            const { index } = event.currentTarget.dataset; | 
				
			||||
            const child = this.children[index]; | 
				
			||||
            if (!child.data.disabled) { | 
				
			||||
                ARRAY.forEach((menuItem) => { | 
				
			||||
                    if (menuItem && | 
				
			||||
                        menuItem.data.closeOnClickOutside && | 
				
			||||
                        menuItem !== this) { | 
				
			||||
                        menuItem.close(); | 
				
			||||
                    } | 
				
			||||
                }); | 
				
			||||
                this.toggleItem(index); | 
				
			||||
            } | 
				
			||||
        }, | 
				
			||||
    }, | 
				
			||||
}); | 
				
			||||
	field: true, | 
				
			||||
	classes: ['title-class'], | 
				
			||||
	relation: useChildren('dropdown-item', function() { | 
				
			||||
		this.updateItemListData(); | 
				
			||||
	}), | 
				
			||||
	props: { | 
				
			||||
		activeColor: { | 
				
			||||
			type: String, | 
				
			||||
			observer: 'updateChildrenData', | 
				
			||||
		}, | 
				
			||||
		overlay: { | 
				
			||||
			type: Boolean, | 
				
			||||
			value: true, | 
				
			||||
			observer: 'updateChildrenData', | 
				
			||||
		}, | 
				
			||||
		zIndex: { | 
				
			||||
			type: Number, | 
				
			||||
			value: 10, | 
				
			||||
		}, | 
				
			||||
		duration: { | 
				
			||||
			type: Number, | 
				
			||||
			value: 200, | 
				
			||||
			observer: 'updateChildrenData', | 
				
			||||
		}, | 
				
			||||
		direction: { | 
				
			||||
			type: String, | 
				
			||||
			value: 'down', | 
				
			||||
			observer: 'updateChildrenData', | 
				
			||||
		}, | 
				
			||||
		safeAreaTabBar: { | 
				
			||||
			type: Boolean, | 
				
			||||
			value: false, | 
				
			||||
		}, | 
				
			||||
		closeOnClickOverlay: { | 
				
			||||
			type: Boolean, | 
				
			||||
			value: true, | 
				
			||||
			observer: 'updateChildrenData', | 
				
			||||
		}, | 
				
			||||
		closeOnClickOutside: { | 
				
			||||
			type: Boolean, | 
				
			||||
			value: true, | 
				
			||||
		}, | 
				
			||||
	}, | 
				
			||||
	data: { | 
				
			||||
		itemListData: [], | 
				
			||||
		currentValue: '' | 
				
			||||
	}, | 
				
			||||
	beforeCreate() { | 
				
			||||
		const { | 
				
			||||
			windowHeight | 
				
			||||
		} = getSystemInfoSync(); | 
				
			||||
		this.windowHeight = windowHeight; | 
				
			||||
		ARRAY.push(this); | 
				
			||||
	}, | 
				
			||||
	destroyed() { | 
				
			||||
		ARRAY = ARRAY.filter((item) => item !== this); | 
				
			||||
	}, | 
				
			||||
	methods: { | 
				
			||||
		updateItemListData() { | 
				
			||||
			this.setData({ | 
				
			||||
				itemListData: this.children.map((child) => child.data), | 
				
			||||
			}); | 
				
			||||
		}, | 
				
			||||
		updateChildrenData() { | 
				
			||||
			this.children.forEach((child) => { | 
				
			||||
				child.updateDataFromParent(); | 
				
			||||
			}); | 
				
			||||
		}, | 
				
			||||
		toggleItem(active) { | 
				
			||||
			this.children.forEach((item, index) => { | 
				
			||||
				const { | 
				
			||||
					showPopup | 
				
			||||
				} = item.data; | 
				
			||||
				if (index === active) { | 
				
			||||
					item.toggle(); | 
				
			||||
				} else if (showPopup) { | 
				
			||||
					item.toggle(false, { | 
				
			||||
						immediate: true | 
				
			||||
					}); | 
				
			||||
				} | 
				
			||||
			}); | 
				
			||||
		}, | 
				
			||||
		close() { | 
				
			||||
			this.children.forEach((child) => { | 
				
			||||
				child.toggle(false, { | 
				
			||||
					immediate: true | 
				
			||||
				}); | 
				
			||||
			}); | 
				
			||||
		}, | 
				
			||||
		getChildWrapperStyle() { | 
				
			||||
			const { | 
				
			||||
				zIndex, | 
				
			||||
				direction | 
				
			||||
			} = this.data; | 
				
			||||
			return getRect(this, '.van-dropdown-menu').then((rect) => { | 
				
			||||
				const { | 
				
			||||
					top = 0, bottom = 0 | 
				
			||||
				} = rect; | 
				
			||||
				const offset = direction === 'down' ? bottom : this.windowHeight - top; | 
				
			||||
				let wrapperStyle = `z-index: ${zIndex};`; | 
				
			||||
				if (direction === 'down') { | 
				
			||||
					wrapperStyle += `top: ${addUnit(offset)};`; | 
				
			||||
				} else { | 
				
			||||
					wrapperStyle += `bottom: ${addUnit(offset)};`; | 
				
			||||
				} | 
				
			||||
				return wrapperStyle; | 
				
			||||
			}); | 
				
			||||
		}, | 
				
			||||
		onTitleTap(event) { | 
				
			||||
			const { | 
				
			||||
				index | 
				
			||||
			} = event.currentTarget.dataset; | 
				
			||||
			const child = this.children[index]; | 
				
			||||
			if (!child.data.disabled) { | 
				
			||||
				ARRAY.forEach((menuItem) => { | 
				
			||||
					if (menuItem && | 
				
			||||
						menuItem.data.closeOnClickOutside && | 
				
			||||
						menuItem !== this) { | 
				
			||||
						menuItem.close(); | 
				
			||||
					} | 
				
			||||
				}); | 
				
			||||
				this.toggleItem(index); | 
				
			||||
			} | 
				
			||||
		}, | 
				
			||||
	}, | 
				
			||||
}); | 
				
			||||
@ -1,16 +1,21 @@
					 | 
				
			||||
/* eslint-disable */ | 
				
			||||
function displayTitle(item) { | 
				
			||||
  if (item.title) { | 
				
			||||
    return item.title; | 
				
			||||
  } | 
				
			||||
	if (item.title) { | 
				
			||||
		return item.title; | 
				
			||||
	} | 
				
			||||
 | 
				
			||||
  var match = item.options.filter(function(option) { | 
				
			||||
    return option.value === item.value; | 
				
			||||
  }); | 
				
			||||
  var displayTitle = match.length ? match[0].text : ''; | 
				
			||||
  return displayTitle; | 
				
			||||
	var match = item.options.filter(function(option) { | 
				
			||||
		return option.value === item.value; | 
				
			||||
	}); | 
				
			||||
	var displayTitle = match.length ? match[0].text : ''; | 
				
			||||
	return displayTitle; | 
				
			||||
} | 
				
			||||
 | 
				
			||||
function setTitleColor(item) { | 
				
			||||
	return item.value != '' ? '#17c653' : '' | 
				
			||||
} | 
				
			||||
 | 
				
			||||
module.exports = { | 
				
			||||
  displayTitle: displayTitle | 
				
			||||
}; | 
				
			||||
	displayTitle: displayTitle, | 
				
			||||
	setTitleColor: setTitleColor | 
				
			||||
}; | 
				
			||||
					Loading…
					
					
				
		Reference in new issue