浏览代码

reader mode supports scroll snapping, sticky pages with scroll triggers are always full height

Hakim El Hattab 1 年之前
父节点
当前提交
e49e89a557
共有 9 个文件被更改,包括 67 次插入43 次删除
  1. 1 0
      css/reveal.scss
  2. 0 0
      dist/reveal.css
  3. 0 0
      dist/reveal.esm.js
  4. 0 0
      dist/reveal.esm.js.map
  5. 0 0
      dist/reveal.js
  6. 0 0
      dist/reveal.js.map
  7. 13 4
      js/config.js
  8. 52 38
      js/controllers/reader.js
  9. 1 1
      js/reveal.js

+ 1 - 0
css/reveal.scss

@@ -1934,6 +1934,7 @@ $notesWidthPercent: 25%;
 		top: 50% !important;
 		left: 50% !important;
 		opacity: 1 !important;
+		transform: scale(var(--slide-scale)) translate(-50%, -50%) !important;
 		transform-style: flat !important;
 		transform-origin: 0 0 !important;
 	}

文件差异内容过多而无法显示
+ 0 - 0
dist/reveal.css


文件差异内容过多而无法显示
+ 0 - 0
dist/reveal.esm.js


文件差异内容过多而无法显示
+ 0 - 0
dist/reveal.esm.js.map


文件差异内容过多而无法显示
+ 0 - 0
dist/reveal.js


文件差异内容过多而无法显示
+ 0 - 0
dist/reveal.js.map


+ 13 - 4
js/config.js

@@ -262,10 +262,19 @@ export default {
 	//            triggered animations
 	view: null,
 
-	// When the presentation is in reader mode, this controls whether each
-	// page should be as tall as the presentation viewport. Set this to false
-	// for a more compact layout with multiple slides visible at a time.
-	readerFullPageHeight: true,
+	// Adjusts the height of each slide in reader mode
+	// - full:       Each slide is as tall as the viewport
+	// - compact:    Slides are as small as possible, allowing multiple slides
+	//               to be visible in parallel on tall devices
+	readerLayout: 'full',
+
+	// Control how scroll snapping works in reader mode.
+	// - false:   	No snapping, scrolling is continuous
+	// - proximity:  Snap when close to a slide
+	// - mandatory:  Always snap to the closest slide
+	//
+	// Only applies to presentations in reader mode.
+	readerScrollSnap: 'proximity',
 
 	// The maximum number of pages a single slide can expand onto when printing
 	// to PDF, unlimited by default

+ 52 - 38
js/controllers/reader.js

@@ -62,9 +62,6 @@ export default class Reader {
 				page.className = 'reader-page';
 				pageElements.push( page );
 
-				slide.style.width = slideWidth + 'px';
-				// slide.style.height = slideHeight + 'px';
-
 				// Copy the presentation-wide background to each individual
 				// page when printing
 				if( presentationBackground ) {
@@ -143,21 +140,29 @@ export default class Reader {
 
 	}
 
-	generatePageMap() {
+	/**
+	 * Updates our reader pages to match the latest configuration and
+	 * presentation size.
+	 */
+	sync() {
 
-		const viewportElement = this.Reveal.getViewportElement();
-		const viewportHeight = viewportElement.offsetHeight;
+		const config = this.Reveal.getConfig();
 
 		const slideSize = this.Reveal.getComputedSlideSize( window.innerWidth, window.innerHeight );
 		const scale = this.Reveal.getScale();
-		const fullPageHeight = this.Reveal.getConfig().readerFullPageHeight;
+		const readerLayout = config.readerLayout;
 
-		const pageHeight = fullPageHeight === true ? viewportHeight : slideSize.height * scale;
+		const viewportElement = this.Reveal.getViewportElement();
+		const viewportHeight = viewportElement.offsetHeight;
+		const compactHeight = slideSize.height * scale;
+		const pageHeight = readerLayout === 'full' ? viewportHeight : compactHeight;
 
 		// The height that needs to be scrolled between scroll triggers
 		const scrollTriggerHeight = viewportHeight / 2;
 
 		viewportElement.style.setProperty( '--page-height', pageHeight + 'px' );
+		viewportElement.style.scrollSnapType = typeof config.readerScrollSnap === 'string' ?
+												`y ${config.readerScrollSnap}` : '';
 
 		const pageElements = Array.from( this.Reveal.getRevealElement().querySelectorAll( '.reader-page' ) );
 
@@ -168,36 +173,18 @@ export default class Reader {
 				slideElement: pageElement.querySelector( 'section' ),
 				backgroundElement: pageElement.querySelector( '.slide-background' ),
 				top: pageElement.offsetTop,
-				pageHeight: pageHeight,
 				scrollTriggers: []
 			};
 
+			page.slideElement.style.width = slideSize.width + 'px';
+			page.slideElement.style.height = config.center === true ? '' : slideSize.height + 'px';
+
 			// Each fragment 'group' is an array containing one or more
 			// fragments. Multiple fragments that appear at the same time
 			// are part of the same group.
 			page.fragments = this.Reveal.fragments.sort( pageElement.querySelectorAll( '.fragment:not(.disabled)' ) );
 			page.fragmentGroups = this.Reveal.fragments.sort( pageElement.querySelectorAll( '.fragment' ), true );
 
-			// The amount of empty scrollable space that has been append
-			page.scrollPadding = scrollTriggerHeight * Math.max( page.fragmentGroups.length - 1, 0 );
-
-			// This variable is used to pad the height of our page in CSS
-			page.pageElement.style.setProperty( '--page-scroll-padding', page.scrollPadding + 'px' );
-
-			// The total height including scrollable space
-			page.totalHeight = page.pageHeight + page.scrollPadding;
-
-			page.bottom = page.top + page.totalHeight;
-
-			// If this is a sticky page, stick it to the vertical center
-			if( page.scrollPadding > 0 ) {
-				page.stickyElement.style.position = 'sticky';
-				page.stickyElement.style.top = Math.max( ( viewportHeight - page.pageHeight ) / 2, 0 ) + 'px';
-			}
-			else {
-				page.stickyElement.style.position = 'relative';
-			}
-
 			// Create scroll triggers that show/hide fragments
 			if( page.fragmentGroups.length ) {
 				const segmentSize = 1 / ( page.fragmentGroups.length + 1 );
@@ -211,10 +198,45 @@ export default class Reader {
 						fragmentIndex: i
 					}))
 				);
+			}
+
+
+			// Add scroll padding based on how many scroll triggers we have
+			page.scrollPadding = scrollTriggerHeight * page.scrollTriggers.length;
+
+			// In the compact layout, only slides with scroll triggers cover the
+			// full viewport height. This helps avoid empty gaps before or after
+			// a sticky slide.
+			if( readerLayout === 'compact' && page.scrollTriggers.length > 0 ) {
+				page.pageHeight = viewportHeight;
+				page.pageElement.style.setProperty( '--page-height', viewportHeight + 'px' );
+			}
+			else {
+				page.pageHeight = pageHeight;
+				page.pageElement.style.removeProperty( '--page-height' );
+			}
+
+			page.pageElement.style.scrollSnapAlign = page.pageHeight < viewportHeight ? 'center' : 'start';
+
+			// This variable is used to pad the height of our page in CSS
+			page.pageElement.style.setProperty( '--page-scroll-padding', page.scrollPadding + 'px' );
+
+			// The total height including scrollable space
+			page.totalHeight = page.pageHeight + page.scrollPadding;
+
+			page.bottom = page.top + page.totalHeight;
+
+			// If this is a sticky page, stick it to the vertical center
+			if( page.scrollTriggers.length > 0 ) {
+				page.stickyElement.style.position = 'sticky';
+				page.stickyElement.style.top = Math.max( ( viewportHeight - page.pageHeight ) / 2, 0 ) + 'px';
 
 				// Make this page freeze at the vertical center of the viewport
 				page.top -= ( viewportHeight - page.pageHeight ) / 2;
 			}
+			else {
+				page.stickyElement.style.position = 'relative';
+			}
 
 			return page;
 		} );
@@ -223,15 +245,7 @@ export default class Reader {
 
 	layout() {
 
-		this.generatePageMap();
-
-		const scale = this.Reveal.getScale();
-
-		this.pages.forEach( ( page ) => {
-			page.slideElement.style.transform = `scale(${scale}) translate(-50%, -50%)`;
-		} );
-
-
+		this.sync();
 		this.onScroll();
 
 	}

+ 1 - 1
js/reveal.js

@@ -2744,7 +2744,7 @@ export default function( revealElement, options ) {
 		isFocused: focus.isFocused.bind( focus ),
 
 		isReaderMode: reader.isActive.bind( reader ),
-		isPrintMode: print.isActive.bind( print ),
+		isPrinting: print.isActive.bind( print ),
 
 		// Checks if reveal.js has been loaded and is ready for use
 		isReady: () => ready,

部分文件因为文件数量过多而无法显示