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 });
|
||
}
|
||
}
|
||
}
|
||
}); |