浏览代码

修复滑动问题,但是尺寸大幅涨了

robert 15 小时之前
父节点
当前提交
891a6e8365
共有 1 个文件被更改,包括 114 次插入9 次删除
  1. 114 9
      layer.js

+ 114 - 9
layer.js

@@ -697,6 +697,9 @@
 
       // Content container
       this.dom.content = el('div', `${PREFIX}content`);
+      // In flow, stretch content so slide distance is visible.
+      this.dom.content.style.alignSelf = 'stretch';
+      this.dom.content.style.width = '100%';
       // Stack container: keep panes absolute so we can cross-fade without layout thrash
       this.dom.stepStack = el('div', `${PREFIX}step-stack`);
       this.dom.stepStack.style.position = 'relative';
@@ -2019,9 +2022,88 @@
       this.params = nextOptions;
       this._applyPopupTheme(this.params);
 
-      // Update icon/title/buttons without recreating DOM
+      const isNext = direction !== 'prev';
+      const enterFrom = isNext ? 100 : -100;
+      const exitTo = isNext ? -100 : 100;
+      const slideDuration = 320;
+
+      // Update title with directional slide (keep in sync with panes)
+      let titleAnim = null;
+      let titleCleanup = null;
       try {
-        if (this.dom.title) this.dom.title.textContent = this.params.title || '';
+        const titleEl = this.dom && this.dom.title;
+        if (titleEl) {
+          const nextTitle = this.params.title || '';
+          const prevTitle = titleEl.textContent || '';
+          if (prevTitle !== nextTitle) {
+            const clone = titleEl.cloneNode(true);
+            try { clone.textContent = prevTitle; } catch {}
+            try {
+              const popupRect = popup.getBoundingClientRect();
+              const titleRect = titleEl.getBoundingClientRect();
+              clone.style.position = 'absolute';
+              clone.style.left = '0';
+              clone.style.right = '0';
+              clone.style.top = Math.max(0, titleRect.top - popupRect.top) + 'px';
+              clone.style.width = '100%';
+              clone.style.pointerEvents = 'none';
+              clone.style.willChange = 'transform, opacity';
+              popup.appendChild(clone);
+            } catch {}
+
+            titleEl.textContent = nextTitle;
+            try {
+              titleEl.style.willChange = 'transform, opacity';
+              titleEl.style.transform = `translateX(${enterFrom}%)`;
+              titleEl.style.opacity = '0';
+            } catch {}
+
+            if (titleEl.animate && clone.animate) {
+              const inAnim = titleEl.animate(
+                [
+                  { transform: `translateX(${enterFrom}%)`, opacity: 0.2 },
+                  { transform: 'translateX(0%)', opacity: 1 }
+                ],
+                { duration: slideDuration, easing: 'cubic-bezier(0.2, 0.9, 0.2, 1)', fill: 'forwards' }
+              );
+              const outAnim = clone.animate(
+                [
+                  { transform: 'translateX(0%)', opacity: 1 },
+                  { transform: `translateX(${exitTo}%)`, opacity: 0.1 }
+                ],
+                { duration: slideDuration, easing: 'cubic-bezier(0.2, 0.9, 0.2, 1)', fill: 'forwards' }
+              );
+              titleAnim = Promise.all([
+                inAnim.finished ? inAnim.finished.catch(() => {}) : Promise.resolve(),
+                outAnim.finished ? outAnim.finished.catch(() => {}) : Promise.resolve()
+              ]);
+            } else {
+              const ease = 'cubic-bezier(0.2, 0.9, 0.2, 1)';
+              const transition = `transform ${slideDuration}ms ${ease}, opacity ${slideDuration}ms ${ease}`;
+              try { titleEl.style.transition = transition; } catch {}
+              try { clone.style.transition = transition; } catch {}
+              requestAnimationFrame(() => {
+                try {
+                  titleEl.style.transform = 'translateX(0%)';
+                  titleEl.style.opacity = '1';
+                  clone.style.transform = `translateX(${exitTo}%)`;
+                  clone.style.opacity = '0.1';
+                } catch {}
+              });
+              titleAnim = new Promise((resolve) => setTimeout(resolve, slideDuration + 40));
+            }
+
+            titleCleanup = () => {
+              try { if (clone && clone.parentNode) clone.parentNode.removeChild(clone); } catch {}
+              try { titleEl.style.willChange = ''; } catch {}
+              try { titleEl.style.transition = ''; } catch {}
+              try { titleEl.style.transform = ''; } catch {}
+              try { titleEl.style.opacity = ''; } catch {}
+            };
+          } else {
+            titleEl.textContent = nextTitle;
+          }
+        }
       } catch {}
 
       const nextBgSpec = this._normalizeBackgroundSpec(this.params && this.params.background);
@@ -2051,11 +2133,6 @@
 
       this._updateFlowActions();
 
-      // Switch panes with directional slide (next: left, prev: right)
-      const isNext = direction !== 'prev';
-      const enterFrom = isNext ? 100 : -100;
-      const exitTo = isNext ? -100 : 100;
-
       // Prepare panes for animation
       toPane.style.display = '';
       toPane.style.position = 'absolute';
@@ -2078,16 +2155,19 @@
       content.style.height = oldH + 'px';
       content.style.overflow = 'hidden';
 
-      const slideDuration = 320;
       let heightAnim = null;
       let fromAnim = null;
       let toAnim = null;
+      let slideCleanup = null;
       try {
         heightAnim = content.animate(
           [{ height: oldH + 'px' }, { height: newH + 'px' }],
           { duration: 220, easing: 'cubic-bezier(0.2, 0.9, 0.2, 1)', fill: 'forwards' }
         );
       } catch {}
+      // Ensure the new pane is in layout before starting slide (fixes missing transitions on some browsers).
+      try { void toPane.offsetWidth; } catch {}
+      await new Promise((resolve) => requestAnimationFrame(resolve));
       try {
         if (fromPane.animate && toPane.animate) {
           fromAnim = fromPane.animate(
@@ -2104,6 +2184,28 @@
             ],
             { duration: slideDuration, easing: 'cubic-bezier(0.2, 0.9, 0.2, 1)', fill: 'forwards' }
           );
+        } else {
+          const ease = 'cubic-bezier(0.2, 0.9, 0.2, 1)';
+          const transition = `transform ${slideDuration}ms ${ease}, opacity ${slideDuration}ms ${ease}`;
+          fromPane.style.transition = transition;
+          toPane.style.transition = transition;
+          slideCleanup = () => {
+            try { fromPane.style.transition = ''; } catch {}
+            try { toPane.style.transition = ''; } catch {}
+          };
+          // Force a layout so transitions apply reliably.
+          void fromPane.offsetWidth;
+          requestAnimationFrame(() => {
+            try {
+              fromPane.style.transform = `translateX(${exitTo}%)`;
+              fromPane.style.opacity = '0.1';
+              toPane.style.transform = 'translateX(0%)';
+              toPane.style.opacity = '1';
+            } catch {}
+          });
+          const fallback = new Promise((resolve) => setTimeout(resolve, slideDuration + 40));
+          fromAnim = fallback;
+          toAnim = fallback;
         }
       } catch {}
 
@@ -2112,9 +2214,12 @@
           heightAnim && heightAnim.finished ? heightAnim.finished.catch(() => {}) : Promise.resolve(),
           fromAnim && fromAnim.finished ? fromAnim.finished.catch(() => {}) : Promise.resolve(),
           toAnim && toAnim.finished ? toAnim.finished.catch(() => {}) : Promise.resolve(),
-          bgTransition && typeof bgTransition.then === 'function' ? bgTransition.catch(() => {}) : Promise.resolve()
+          bgTransition && typeof bgTransition.then === 'function' ? bgTransition.catch(() => {}) : Promise.resolve(),
+          titleAnim && typeof titleAnim.then === 'function' ? titleAnim.catch(() => {}) : Promise.resolve()
         ]);
       } catch {}
+      try { if (titleCleanup) titleCleanup(); } catch {}
+      try { if (slideCleanup) slideCleanup(); } catch {}
 
       // Cleanup styles and hide old pane
       fromPane.style.display = 'none';