常德市做公司网站的公司,建设部执业考试中心网站,免费生产管理erp,深圳建站网站网站公司前言
目前功能包括#xff1a;
切换到首页。切换到尾页。上一页。下一页。添加标签。标签管理页面旋转页面随意拖动双击后还原位置
其实按照自己的预期来说#xff0c;有很多功能还没有开发完#xff0c;配色也没有全都搞完#xff0c;先发出来吧#xff0c;后期有需要…前言
目前功能包括
切换到首页。切换到尾页。上一页。下一页。添加标签。标签管理页面旋转页面随意拖动双击后还原位置
其实按照自己的预期来说有很多功能还没有开发完配色也没有全都搞完先发出来吧后期有需要继续添加功能。
功能预览
1.加载后的主页面
白天模式 黑夜模式
2.功能区 一、关于这款PDF阅读器的功能说明
1. 基本布局与样式
具有响应式设计通过meta标签设置视口以适应不同设备宽度。支持主题切换明暗模式定义了一系列CSS变量来管理颜色和布局相关属性方便切换不同主题风格。
2. 工具栏功能
导航功能包含首页、上一页、下一页、末页的导航按钮对应firstPage()、prevPage()、nextPage()、lastPage()函数。缩放功能有缩小、放大按钮分别对应zoomOut()和zoomIn()函数还提供了一个范围输入控件#zoomControl用于更精确地控制缩放比例。旋转功能顺时针旋转和逆时针旋转按钮对应rotateClockwise()和rotateCounterClockwise()函数。书签功能可以输入书签名称点击添加书签按钮addBookmark()函数添加书签还有书签管理按钮toggleBookmarkPanel()函数用于管理已添加的书签。主题切换有一个主题切换按钮toggleTheme()函数点击可切换明暗主题。
3. 侧边栏与缩略图
侧边栏.sidebar用于显示PDF文档的缩略图缩略图容器为#thumbnails每个缩略图项.thumbnail-item包含一个canvas元素用于显示缩略图点击缩略图项可进行相关操作。
4. 主内容区域
主内容区域.main-content包含PDF文档的显示区域#pdf-container其中有一个canvas元素#pdf-canvas用于渲染PDF页面用户可以通过鼠标抓取操作cursor: -webkit-grab进行交互。状态栏.status-bar用于显示一些状态信息如页码等。
5. 模态窗口
书签管理模态窗口#bookmarks-modal默认隐藏用于管理已添加的书签包含书签列表#bookmarks-list和一些操作按钮.modal-buttons。
二、Html代码
!DOCTYPE html
html langzh-CN
headmeta charsetUTF-8meta nameviewport contentwidthdevice-width, initial-scale1.0link relstylesheet hrefhttps://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0/css/all.min.csstitlePDF阅读器/titlestyle:root {--primary-color: #2196F3;--hover-color: #1976D2;--background-color: #1a1a1a;--surface-color: #2d2d2d;--toolbar-bg: #333333;--text-color: #ffffff;--error-color: #ff4444;--border-radius: 8px;--gap: 20px;--toolbar-height: 60px;}body {font-family: Arial, sans-serif;margin: 0;padding: 20px;background-color: var(--background-color);color: var(--text-color);box-sizing: border-box;}.pdf-reader-container {display: flex;gap: var(--gap);max-width: 100%;min-width: 800px;margin: 0 auto;background-color: var(--surface-color);border-radius: var(--border-radius);box-shadow: 0 4px 8px rgba(0, 0, 0, 0.2);padding: var(--gap) ; /* 0 上下内边距 */margin-top: var(--toolbar-height);box-sizing: border-box;flex-wrap: nowrap;}.toolbar {position: fixed;top: 0;left: 0;right: 0;height: var(--toolbar-height);display: flex;align-items: center;justify-content: space-between;padding: 0 var(--gap);background-color: var(--toolbar-bg);border-radius: 0 0 var(--border-radius) var(--border-radius);box-shadow: 0 2px 4px rgba(0, 0, 0, 0.2);z-index: 1000;box-sizing: border-box;}.logo {display: flex;align-items: center;padding: 0 20px;height: 60%;}.logo img {height: 100%;object-fit: contain; transition: transform 0.3s ease; }.toolbar-buttons {display: flex;gap: 10px;}/* 修改按钮样式部分 */button {padding: 8px 12px;font-size: 16px;cursor: pointer;background-color: var(--primary-color);color: var(--text-color);border: none;border-radius: 50%;aspect-ratio: 1/1;transition: all 0.3s ease;display: flex;align-items: center;justify-content: center;width: 40px;height: 40px;position: relative;}button:hover {background-color: var(--hover-color);transform: translateY(-2px);box-shadow: 0 4px 8px rgba(0, 0, 0, 0.2);}button::before {font-family: Font Awesome 5 Free;font-weight: 900;}/* 为每个按钮指定图标 */button:nth-child(1)::before { content: \f100; } /* 首页 */button:nth-child(2)::before { content: \f104; } /* 上一页 */button:nth-child(3)::before { content: \f105; } /* 下一页 */button:nth-child(4)::before { content: \f101; } /* 末页 */button:nth-child(5)::before { content: \f068; } /* 缩小 */button:nth-child(7)::before { content: \f067; } /* 放大 */button:nth-child(8)::before { content: \f2f9; } /* 顺时针旋转 */button:nth-child(9)::before { content: \f2ea; } /* 逆时针旋转 */button:nth-child(11)::before { content: \f02e; } /* 添加书签 */button:nth-child(12)::before { content: \f02e; } /* 书签管理 */button span {display: none;}.toolbar-buttons {display: flex;gap: 8px;align-items: center;}#zoomControl {width: 100px;height: 6px;background: var(--surface-color);border-radius: 3px;}#bookmarkLabel {padding: 8px;border-radius: var(--border-radius);border: 1px solid var(--primary-color);background: var(--surface-color);color: var(--text-color);}button::after {content: attr(aria-label);position: absolute;bottom: -30px;left: 50%;transform: translateX(-50%);background: var(--toolbar-bg);color: var(--text-color);padding: 4px 8px;border-radius: 4px;font-size: 12px;white-space: nowrap;opacity: 0;transition: opacity 0.2s;pointer-events: none;}button:hover::after {opacity: 1;}::-webkit-scrollbar {width: 8px;}::-webkit-scrollbar-track {background-color: var(--toolbar-bg);border-radius: 4px;}::-webkit-scrollbar-thumb {background-color: var(--primary-color);border-radius: 4px;}::-webkit-scrollbar-thumb:hover {background-color: var(--hover-color);}/* 侧边栏样式 */.sidebar {flex: 0 0 250px;background-color: var(--toolbar-bg);border-radius: var(--border-radius);padding: 16px;height: calc(100vh - var(--toolbar-height) - var(--gap)*2 - 40px);overflow-y: auto;box-sizing: border-box;}.thumbnail-container {display: flex;flex-direction: column;gap: 10px;}.thumbnail-item {position: relative;cursor: pointer;border-radius: 4px;overflow: hidden;box-shadow: 0 2px 4px rgba(0, 0, 0, 0.2);}.thumbnail-item canvas {width: 100%;height: auto;}.thumbnail-item.active {border: 2px solid var(--primary-color);}.main-content {flex: 1;background-color: var(--surface-color);border-radius: var(--border-radius);/* padding: 16px; */height: calc(100vh - var(--toolbar-height) - var(--gap)*2 - 40px);box-sizing: border-box;}#pdf-container {width: 100%;height: 96%;/* height: calc(100vh - var(--toolbar-height) - var(--gap)*2 - 80px - 40px); */border: 1px solid var(--toolbar-bg);border-radius: var(--border-radius);overflow: auto;background-color: #333333;/* padding: 16px; */box-sizing: border-box;overflow-x: hidden;}.status-bar {height: 4%;font-size: 14px;color: var(--text-color);/* padding: 5px; */background-color: var(--toolbar-bg);border-radius: var(--border-radius);margin-top: auto;}.error-message {color: var(--error-color);padding: 10px;margin-top: 10px;background-color: #4d4d4d;border-radius: var(--border-radius);}/* 模态窗口样式 */.modal {display: none;position: fixed;top: 0;left: 0;width: 100%;height: 100%;background-color: rgba(0, 0, 0, 0.5);z-index: 1000;transition: opacity 0.3s ease;}.modal-content {background-color: var(--toolbar-bg);margin: 15% auto;padding: 20px;width: 80%;max-width: 500px;position: relative;border-radius: var(--border-radius);}.close {position: absolute;right: 20px;top: 10px;font-size: 28px;cursor: pointer;color: var(--text-color);}.close:hover {color: var(--primary-color);}#bookmarks-list {list-style-type: none;padding: 0;margin: 0;}#bookmarks-list li {padding: 8px;margin: 4px 0;cursor: pointer;border-radius: 4px;}#bookmarks-list li:hover {background-color: var(--primary-color);color: var(--text-color);}.modal-buttons {margin-top: 20px;}.modal-buttons button {margin: 0 5px;}canvas#pdf-canvas {position: relative;cursor: -webkit-grab;}.theme-toggle {position: relative;display: inline-block;}.light-theme {--background-color: #f9fafb; --surface-color: #ffffff;--toolbar-bg: #e5e7eb; --text-color: #374151;--error-color: #ef4444;--primary-color: #3b82f6;--hover-color: #2563eb; }.light-theme .toolbar {background-color: var(--toolbar-bg);}.light-theme .sidebar {background-color: var(--toolbar-bg);}.light-theme .main-content {background-color: var(--surface-color);}.light-theme button {background-color: var(--primary-color);color: var(--text-color);}.light-theme .status-bar {background-color: var(--toolbar-bg);}/style
/head
bodydiv classtoolbardiv classlogoimg srclogo.png altLogo/divdiv classtoolbar-buttonsbutton onclickfirstPage() aria-label首页span首页/span/buttonbutton onclickprevPage() aria-label上一页span上一页/span/buttonbutton onclicknextPage() aria-label下一页span下一页/span/buttonbutton onclicklastPage() aria-label末页span末页/span/buttonbutton onclickzoomOut() aria-label缩小span缩小/span/buttoninput typerange min0.5 max2.0 step0.1 value1.0 idzoomControlbutton onclickzoomIn() aria-label放大span放大/span/buttonbutton onclickrotateClockwise() aria-label顺时针旋转span顺时针旋转/span/buttonbutton onclickrotateCounterClockwise() aria-label逆时针旋转span逆时针旋转/span/buttoninput typetext idbookmarkLabel placeholder输入书签名称button onclickaddBookmark() aria-label添加书签span添加书签/span/buttonbutton onclicktoggleBookmarkPanel() aria-label书签管理span书签管理/span/buttonbutton onclicktoggleTheme() aria-label切换主题 classtheme-togglei classfas fa-moon/i/button/div/divdiv classpdf-reader-containerdiv classsidebardiv classthumbnail-container idthumbnails/div/divdiv classmain-contentdiv idpdf-containercanvas idpdf-canvas/canvas/divdiv classstatus-bar idstatus-bar/div/div/divdiv idbookmarks-modal classmodal styledisplay: none;div classmodal-contentspan classclose onclickcloseBookmarkPanel()times;/spanh3书签管理/h3ul idbookmarks-list/uldiv classmodal-buttonsbutton onclickaddBookmark()添加书签/buttonbutton onclickclearBookmarks()清除书签/buttonbutton onclickcloseBookmarkPanel()关闭/button/div/div/divscript srcpdf.min.js/script script srcpdf-reader.js/script
/body
/html三、Javascript代码
let doc null;
let currentPage 1;
let scale 1.5;
let rotation 0;
let bookmarks [];
let isDragging false;
let lastX 0;
let lastY 0;
let offsetX 0;
let offsetY 0;let thumbnails [];const thumbnailsContainer document.getElementById(thumbnails); const bookmarksList document.getElementById(bookmarks-list);
const bookmarksPanel document.getElementById(bookmarks-panel); const container document.getElementById(pdf-container); // 新增变量用于存储当前视口的偏移量
let viewportOffsetX 0;
let viewportOffsetY 0;// 在window.onload 中添加键盘事件监听
window.addEventListener(keydown, function(e) {if (e.key ArrowLeft) {prevPage();} else if (e.key ArrowRight) {nextPage();}
});// 初始化滚动条
const zoomControl document.getElementById(zoomControl);
zoomControl.value scale.toString(); // 初始化旋转状态
const savedRotation localStorage.getItem(pdfRotation);
if (savedRotation ! null) {rotation parseInt(savedRotation);
}// 加载PDF文件
function loadPDF(fileUrl) {pdfjsLib.getDocument(fileUrl).promise.then(function (loadedDoc) {doc loadedDoc;const numPages doc.numPages; loadPage(currentPage);createThumbnails(numPages);// 更新状态栏 document.getElementById(status-bar).textContent 第 ${currentPage} 页 / 共 ${numPages} 页 | 缩放比例: ${scale * 100}% | 旋转: ${rotation}°;}).catch(function (error) {console.error(Error loading PDF:, error);showError(加载PDF时出错${error.message}); });
}// 创建缩略图
function createThumbnails(numPages) {thumbnailsContainer.innerHTML ;for (let i 1; i numPages; i) {const thumbnailItem document.createElement(div); thumbnailItem.className thumbnail-item;thumbnailItem.dataset.page i;const canvas document.createElement(canvas); thumbnailItem.appendChild(canvas); thumbnailsContainer.appendChild(thumbnailItem); loadThumbnail(i, canvas);thumbnailItem.addEventListener(click, function() {currentPage i;loadPage(currentPage);updateThumbnailsActiveState();});}
}// 更新缩略图活动状态
function updateThumbnailsActiveState() {const items thumbnailsContainer.querySelectorAll(.thumbnail-item); items.forEach(item {item.classList.remove(active); });const currentItem thumbnailsContainer.querySelector([data-page${currentPage}]); if (currentItem) {currentItem.classList.add(active); }
}// 加载指定页面
// 修改loadPage函数
function loadPage(pageNum) {if (!doc) {showError(未加载PDF文件请检查文件路径。);return;}doc.getPage(pageNum).then(function (page) {while (container.firstChild) {container.removeChild(container.firstChild); }const defaultViewport page.getViewport({ scale: scale });const containerWidth container.clientWidth; const containerHeight container.clientHeight; const newScale Math.min( containerWidth / defaultViewport.width, containerHeight / defaultViewport.height );const finalScale Math.max(0.5, Math.min(2.0, newScale));const viewport page.getViewport({ scale: scale,rotation: rotation});const canvas document.createElement(canvas); canvas.id pdf-canvas;container.appendChild(canvas); adjustCanvasSize(canvas, viewport);const context canvas.getContext(2d); if (!context) {showError(无法获取Canvas上下文请检查浏览器支持。);return;}page.render({ canvasContext: context,viewport: viewport}).promise.then(() {console.log(Page rendered successfully);hideError();// 初始化偏移量viewportOffsetX (container.clientWidth - canvas.width) / 2;viewportOffsetY 0;updateCanvasPosition();}).catch(error {console.error(Error rendering page:, error);showError(渲染页面时出错${error.message}); });document.getElementById(status-bar).textContent 第 ${pageNum} 页 / 共 ${doc.numPages} 页 | 缩放比例: ${Number(scale.toFixed(1)) * 100}% | 旋转: ${rotation}°;}).catch(error {console.error(Error getting page:, error);showError(获取页面时出错${error.message}); });}// 调整Canvas尺寸以适应页面内容
function adjustCanvasSize(canvas, viewport) {canvas.width viewport.width; canvas.height viewport.height; const containerRect container.getBoundingClientRect(); const canvasRect canvas.getBoundingClientRect(); canvas.style.left ${(containerRect.width - canvasRect.width) / 2}px;canvas.style.top ${(containerRect.height - canvasRect.height) / 2}px;
}// 修改导航函数
function firstPage() {currentPage 1;loadPage(currentPage);
}function prevPage() {currentPage Math.max(1, currentPage - 1);loadPage(currentPage);
}function nextPage() {currentPage Math.min(doc.numPages, currentPage 1);loadPage(currentPage);
}function lastPage() {currentPage doc.numPages; loadPage(currentPage);
}// 缩放功能
function zoomIn() {scale Math.min(2.0, scale 0.1);zoomControl.value scale.toString(); updateZoomButtons();loadPage(currentPage);
}function zoomOut() {scale Math.max(0.5, scale - 0.1);zoomControl.value scale.toString(); updateZoomButtons();loadPage(currentPage);
}// 错误提示功能
function showError(message) {const errorDiv document.createElement(div); errorDiv.className error-message;errorDiv.textContent message;document.body.appendChild(errorDiv);
}function hideError() {const errorDiv document.querySelector(.error-message); if (errorDiv) {errorDiv.remove(); }
}// 旋转功能
function rotateClockwise() {rotation 90;if (rotation 360) rotation 0;localStorage.setItem(pdfRotation, rotation);loadPage(currentPage);
}function rotateCounterClockwise() {rotation - 90;if (rotation 0) rotation 360;localStorage.setItem(pdfRotation, rotation);loadPage(currentPage);
}// 初始化PDF阅读器
window.onload function () {const fileUrl https://raw.githubusercontent.com/mozilla/pdf.js/ba2edeae/web/compressed.tracemonkey-pldi-09.pdf; loadPDF(fileUrl);// 恢复旋转状态 if (savedRotation ! null) {rotation parseInt(savedRotation);loadPage(currentPage);}// 加载保存的书签 loadSavedBookmarks();// 新增事件监听const PDF document.getElementById(pdf-container); console.log(PDF);PDF.addEventListener(mousedown, startDrag);PDF.addEventListener(mousemove, drag);PDF.addEventListener(mouseup, stopDrag);PDF.addEventListener(wheel, zoomWithWheel);PDF.addEventListener(dblclick, resetPosition);const currentTheme localStorage.getItem(theme) || dark;if (currentTheme light) {document.body.classList.add(light-theme); }};// 新增拖拽功能
function startDrag(e) {if (e.button 0) { // 左键点击isDragging true;lastX e.clientX; lastY e.clientY; }
}// 双击还原
function resetPosition(e) {canvas document.getElementById(pdf-canvas);viewportOffsetX (container.clientWidth - canvas.width) / 2;viewportOffsetY 0;updateCanvasPosition();
}function drag(e) {if (isDragging) {const deltaX e.clientX - lastX;const deltaY e.clientY - lastY;// 更新偏移量viewportOffsetX deltaX;viewportOffsetY deltaY;// 限制偏移范围const canvas document.getElementById(pdf-canvas); // 更新canvas位置updateCanvasPosition();lastX e.clientX; lastY e.clientY; }
}function stopDrag() {isDragging false;
}// 新增滚轮缩放功能
function zoomWithWheel(e) {e.preventDefault(); const delta e.deltaY; if (delta 0) {zoomOut();} else {zoomIn();}
}// 更新canvas位置
function updateCanvasPosition() {const canvas document.getElementById(pdf-canvas); if (canvas) {canvas.style.left ${viewportOffsetX}px;canvas.style.top ${viewportOffsetY}px;}
}/*** 更新缩放按钮的显示 */
function updateZoomButtons() {const buttons document.querySelectorAll(button); buttons.forEach(button {if (button.onclick zoomIn) {button.textContent 放大 (${scale.toFixed(1)}); } else if (button.onclick zoomOut) {button.textContent 缩小 (${scale.toFixed(1)}); }});
}/*** 处理滚动条输入事件 */
zoomControl.addEventListener(input, function (e) {const inputValue parseFloat(e.target.value); // 反向计算 scale 值 scale inputValue - 0.1;updateZoomButtons();// 使用节流处理以优化性能 throttledLoadPage(currentPage);
});/*** 节流函数 * param {function} func 目标函数 * param {number} wait 延迟时间毫秒* returns {function} 节流后的函数 */
function throttle(func, wait) {let timeout;return function (...args) {if (!timeout) {func.apply(this, args);timeout setTimeout(() {timeout null;}, wait);}};
}// 对 loadPage 进行节流处理
const throttledLoadPage throttle(loadPage, 100);// 监听窗口调整大小事件
window.addEventListener(resize, function () {if (doc currentPage) {loadPage(currentPage);}
});// 切换书签面板显示状态
function toggleBookmarkPanel() {const isHidden bookmarksPanel.style.display none;bookmarksPanel.style.display isHidden ? block : none;if (isHidden) {loadBookmarks();}
}// 关闭书签面板
function closeBookmarkPanel() {bookmarksPanel.style.display none;
}// 添加当前页面为书签
function addBookmark() {const bookmarkLabel document.getElementById(bookmarkLabel).value.trim(); if (!bookmarkLabel) {showError(请输入书签名称);return;}const bookmark {page: currentPage,scale: scale,label: bookmarkLabel };bookmarks.push(bookmark); saveBookmarks();loadBookmarks();document.getElementById(bookmarkLabel).value ; // 清空输入框
}// 加载并显示所有书签
function loadBookmarks() {const bookmarksList document.getElementById(bookmarks-list); bookmarksList.innerHTML ;bookmarks.forEach((bookmark, index) {const li document.createElement(li); li.innerHTML span${bookmark.label}/span button onclickjumpToBookmark(${index})跳转/buttonbutton onclickdeleteBookmark(${index})删除/button;li.style.backgroundColor #4CAF50;li.style.color white;li.style.padding 8px;li.style.margin 4px 0;li.style.borderRadius 4px;bookmarksList.appendChild(li); });
}// 删除指定索引的书签
function deleteBookmark(index) {bookmarks.splice(index, 1);saveBookmarks();loadBookmarks();
}// 清除所有书签
function clearBookmarks() {bookmarks [];saveBookmarks();loadBookmarks();
}// 跳转到指定书签
function jumpToBookmark(index) {const bookmark bookmarks[index];currentPage bookmark.page; scale bookmark.scale; loadPage(currentPage);
}// 保存书签到 localStorage
function saveBookmarks() {localStorage.setItem(pdfBookmarks, JSON.stringify(bookmarks));
}// 加载保存的书签
function loadSavedBookmarks() {const saved localStorage.getItem(pdfBookmarks); if (saved) {bookmarks JSON.parse(saved); loadBookmarks();}
}function toggleBookmarkPanel() {const modal document.getElementById(bookmarks-modal); modal.style.display block;loadBookmarks();
}function closeBookmarkPanel() {const modal document.getElementById(bookmarks-modal); modal.style.display none;
}// 加载缩略图
function loadThumbnail(pageNum, canvas) {doc.getPage(pageNum).then(function (page) {const viewport page.getViewport({ scale: 0.5 });canvas.width viewport.width; canvas.height viewport.height; const context canvas.getContext(2d); if (!context) return;page.render({ canvasContext: context,viewport: viewport}).promise.then(() {if (pageNum currentPage) {thumbnailItem.classList.add(active); }});});
}function toggleTheme() {document.body.classList.toggle(light-theme); const root document.documentElement; root.style.setProperty(--background-color, document.body.classList.contains(light-theme) ? #f5f5f5 : #1a1a1a);root.style.setProperty(--surface-color, document.body.classList.contains(light-theme) ? #ffffff : #2d2d2d);root.style.setProperty(--toolbar-bg, document.body.classList.contains(light-theme) ? #f0f0f0 : #333333);root.style.setProperty(--text-color, document.body.classList.contains(light-theme) ? #333333 : #ffffff);root.style.setProperty(--error-color, document.body.classList.contains(light-theme) ? #cc0000 : #ff4444);}