143 lines
4.2 KiB
JavaScript
143 lines
4.2 KiB
JavaScript
|
Component({
|
|||
|
options: {
|
|||
|
// 关键修改:设置样式隔离选项
|
|||
|
styleIsolation: 'shared' // 完全共享页面和组件样式
|
|||
|
},
|
|||
|
properties: {
|
|||
|
visible: {
|
|||
|
type: Boolean,
|
|||
|
value: false,
|
|||
|
observer: function (newVal) {
|
|||
|
if (newVal) {
|
|||
|
this.showModal();
|
|||
|
} else {
|
|||
|
this.hideModal();
|
|||
|
}
|
|||
|
}
|
|||
|
},
|
|||
|
modalContentClass: {
|
|||
|
type: String,
|
|||
|
value: ''
|
|||
|
}
|
|||
|
},
|
|||
|
data: {
|
|||
|
animationClass: 'modal-transition', // 保持过渡效果类
|
|||
|
containerHeight: '25vh', // 设置为1/4屏幕高度
|
|||
|
initialTranslate: '100%', // 初始在屏幕外
|
|||
|
startY: 0, // 触摸起始位置
|
|||
|
currentState: 'hidden', // 'hidden', 'bottom', 'half', 'full'
|
|||
|
states: {
|
|||
|
bottom: { height: '25vh', translate: '0' }, // 1/4屏幕高度,设置translate为0使其正确显示在底部
|
|||
|
full: { height: '100vh', translate: '0' } // 全屏高度
|
|||
|
}
|
|||
|
},
|
|||
|
methods: {
|
|||
|
showModal() {
|
|||
|
this.setData({
|
|||
|
visible: true,
|
|||
|
currentState: 'bottom', // 默认显示1/4屏幕高度
|
|||
|
containerHeight: this.data.states['bottom'].height,
|
|||
|
initialTranslate: this.data.states['bottom'].translate
|
|||
|
});
|
|||
|
},
|
|||
|
hideModal() {
|
|||
|
this.setData({
|
|||
|
initialTranslate: '100%', // 设置为底部位置
|
|||
|
currentState: 'hidden'
|
|||
|
});
|
|||
|
setTimeout(() => {
|
|||
|
if (this.data.currentState === 'hidden') {
|
|||
|
this.setData({ visible: false });
|
|||
|
}
|
|||
|
}, 300); // 与动画时间一致
|
|||
|
},
|
|||
|
onHideModal() {
|
|||
|
this._triggerCloseEvent();
|
|||
|
},
|
|||
|
|
|||
|
// 遮罩层点击事件(如果有遮罩层的话)
|
|||
|
onOverlayTap() {
|
|||
|
this._triggerCloseEvent();
|
|||
|
},
|
|||
|
|
|||
|
// 共用的关闭事件触发方法
|
|||
|
_triggerCloseEvent() {
|
|||
|
this.triggerEvent('close');
|
|||
|
},
|
|||
|
preventTouchMove() {},
|
|||
|
onTouchStart(e) {
|
|||
|
this.setData({ startY: e.touches[0].clientY });
|
|||
|
this.setData({ animationClass: '' }); // 开始拖动时移除过渡效果,使拖动更跟手
|
|||
|
},
|
|||
|
onTouchMove(e) {
|
|||
|
if (!this.data.visible) return;
|
|||
|
|
|||
|
const currentY = e.touches[0].clientY;
|
|||
|
const deltaY = currentY - this.data.startY;
|
|||
|
let newTranslate = '';
|
|||
|
|
|||
|
// 根据当前状态和拖动方向计算新的位移
|
|||
|
if (this.data.currentState === 'full') {
|
|||
|
newTranslate = `calc(0px + ${deltaY}px)`; // 从全屏位置开始拖
|
|||
|
} else if (this.data.currentState === 'bottom') {
|
|||
|
newTranslate = `calc(75vh + ${deltaY}px)`; // 从1/4屏幕高度位置开始拖
|
|||
|
}
|
|||
|
|
|||
|
// 限制拖动范围,不能拖出屏幕顶部或底部之外
|
|||
|
if (this.data.currentState === 'full' && parseInt(newTranslate) > 0) {
|
|||
|
newTranslate = '0';
|
|||
|
} else if (this.data.currentState === 'bottom' && deltaY < -300) {
|
|||
|
// 向下拖动不超过屏幕
|
|||
|
newTranslate = 'calc(75vh - 300px)';
|
|||
|
}
|
|||
|
|
|||
|
this.setData({ initialTranslate: newTranslate });
|
|||
|
},
|
|||
|
onTouchEnd(e) {
|
|||
|
const endY = e.changedTouches[0].clientY;
|
|||
|
const deltaY = endY - this.data.startY;
|
|||
|
const threshold = 50; // 判断状态切换的阈值
|
|||
|
|
|||
|
// 根据拖动距离和方向,以及当前状态,决定下一个状态
|
|||
|
let nextState = this.data.currentState;
|
|||
|
if (Math.abs(deltaY) > threshold) {
|
|||
|
if (deltaY > 0) { // 向下拖
|
|||
|
if (this.data.currentState === 'full') {
|
|||
|
nextState = 'bottom';
|
|||
|
}
|
|||
|
} else { // 向上拖
|
|||
|
if (this.data.currentState === 'bottom') {
|
|||
|
nextState = 'full';
|
|||
|
}
|
|||
|
}
|
|||
|
} else {
|
|||
|
// 拖动距离小于阈值,则回到当前状态
|
|||
|
nextState = this.data.currentState;
|
|||
|
}
|
|||
|
|
|||
|
// 在切换状态前,添加过渡动画类
|
|||
|
this.setData({
|
|||
|
animationClass: 'modal-transition'
|
|||
|
}, () => {
|
|||
|
// 在回调中执行状态切换,确保动画类已经设置
|
|||
|
this.switchToState(nextState);
|
|||
|
});
|
|||
|
},
|
|||
|
switchToState(state) {
|
|||
|
if (state === 'hidden') {
|
|||
|
this.hideModal();
|
|||
|
return;
|
|||
|
}
|
|||
|
const targetState = this.data.states[state];
|
|||
|
if (targetState) {
|
|||
|
this.setData({
|
|||
|
currentState: state,
|
|||
|
containerHeight: targetState.height,
|
|||
|
initialTranslate: targetState.translate
|
|||
|
});
|
|||
|
// 通知父组件状态变化
|
|||
|
this.triggerEvent('stateChange', { state: state });
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
});
|