第一次接触pdf.js的工具栏隐藏需求时,我也像大多数开发者一样,直接想到用CSS暴力隐藏。这个思路确实简单粗暴有效,就像给房间的开关贴上了胶布 - 虽然能用,但总觉得少了点灵活性。pdf.js作为Mozilla开源的PDF渲染引擎,其实提供了更优雅的动态控制方式。
在web/viewer.css文件中,工具栏相关的样式集中在.toolbar类。默认情况下,这个工具栏包含了缩放按钮、页码导航、下载打印等实用功能。通过Chrome开发者工具检查元素,你会发现整个工具栏实际上由多个嵌套的div组成,最外层就是我们要控制的.toolbar容器。
最直接的方法就是修改viewer.css源文件,给.toolbar添加display:none。我在早期项目中也这样做过,优点是见效快,一行代码就能让工具栏消失得无影无踪。但后来发现这种方案存在明显问题:每次更新pdf.js版本时,都需要重新修改这个文件,维护成本高。
css复制/* 直接修改viewer.css的方案 */
.toolbar {
display: none !important;
/* 保留其他原有样式 */
}
后来我改用外部CSS覆盖的方式,这样既不会污染源码,也便于维护。具体做法是在调用viewer.html的页面中,通过link引入自定义CSS文件,或者在style标签中重写样式:
html复制<!-- 在调用pdf viewer的HTML文件中 -->
<style>
#viewerContainer .toolbar {
display: none !important;
}
</style>
这里用了更具体的选择器#viewerContainer .toolbar,并加上!important确保覆盖优先级。实测下来,这种方案在大多数场景下都很稳定,但要注意CSS加载时机,避免闪烁问题。
pdf.js在viewer.js中暴露了全局对象PDFViewerApplication,这是我们实现动态控制的关键。通过控制台输入这个对象名,可以看到它包含了各种控制方法。其中与工具栏相关的有两个重要属性:
javascript复制// 获取工具栏DOM元素
const toolbar = PDFViewerApplication.toolbar;
// 获取侧边栏DOM元素
const sidebar = PDFViewerApplication.sidebar;
基于这个API,我们可以实现点击按钮切换工具栏状态的功能。下面这段代码我曾在多个项目中使用:
javascript复制function toggleToolbar() {
const toolbar = document.querySelector('.toolbar');
if(toolbar.style.display === 'none') {
toolbar.style.display = '';
console.log('工具栏已显示');
} else {
toolbar.style.display = 'none';
console.log('工具栏已隐藏');
}
}
// 绑定到按钮点击事件
document.getElementById('toggleBtn').addEventListener('click', toggleToolbar);
这种方案的优点是可以在运行时动态控制,适合需要灵活切换的场景。比如在阅读模式下隐藏工具栏,编辑模式下又显示出来。
pdf.js在初始化时可以通过webViewerInitialized事件注入配置。这是我常用的一个配置模板:
javascript复制document.addEventListener('webViewerInitialized', () => {
PDFViewerApplicationOptions.set('showToolbar', false);
PDFViewerApplicationOptions.set('showSidebar', false);
PDFViewerApplicationOptions.set('enablePrint', false);
});
结合URL参数可以实现更智能的控制。比如根据不同的业务场景决定是否显示工具栏:
javascript复制const urlParams = new URLSearchParams(window.location.search);
const isPreviewMode = urlParams.get('mode') === 'preview';
if(isPreviewMode) {
PDFViewerApplicationOptions.set('showToolbar', false);
document.documentElement.classList.add('preview-mode');
}
然后在CSS中针对preview-mode做特殊样式处理:
css复制.preview-mode .toolbar {
display: none;
}
.preview-mode .pdfViewer {
top: 0 !important;
}
隐藏工具栏后经常遇到的一个问题是内容区域不会自动撑满空间。这是因为viewer.css中写死了各个区域的定位尺寸。需要同步调整以下样式:
css复制#viewerContainer {
top: 0 !important;
}
.pdfViewer {
--toolbar-height: 0px;
}
在移动设备上,我习惯保留部分核心功能按钮,而不是完全隐藏工具栏。可以通过媒体查询实现:
css复制@media (max-width: 768px) {
.toolbar .spacer,
.toolbar .splitToolbarButton {
display: none;
}
.toolbar #viewBookmark {
display: block !important;
}
}
频繁显示/隐藏工具栏可能引发重绘问题。我的经验是给过渡动画添加will-change属性:
css复制.toolbar {
transition: transform 0.3s ease;
will-change: transform;
}
.toolbar.hidden {
transform: translateY(-100%);
}
这样用transform替代display:none,动画会更流畅。
经过多个项目的实践,我总结出几个原则:对于纯展示场景,建议使用CSS方案;对于需要动态控制的场景,优先考虑JavaScript API;对于企业级应用,推荐采用配置参数的方式。
在架构设计上,我习惯将pdf.js的工具栏控制逻辑封装成独立模块:
javascript复制class PDFToolbarManager {
constructor(options) {
this.defaultOptions = {
printable: true,
downloadable: true,
// ...其他配置
};
this.options = {...this.defaultOptions, ...options};
}
init() {
this.setupEventListeners();
this.applyInitialState();
}
setupEventListeners() {
// 各种事件监听...
}
applyInitialState() {
// 应用初始状态...
}
// 其他方法...
}
这种设计模式使代码更易维护和扩展,也方便团队协作。