版本是 "pdfjs-dist": "^2.5.207"
html部分
<template>
<div class="month" style="position: absolute; height: 100%; width: 100%">
<header>
<div>
<button :disabled="isLoading"></button>
<button :disabled="isLoading" @click="enlarge"></button>
<button :disabled="isLoading" @click="shrink"></button>
<button :disabled="isLoading" @click="rotate('right')"></button>
<button :disabled="isLoading" @click="rotate('left')"></button>
<button :disabled="isLoading" @click="wdithscreen"></button>
<button :disabled="isLoading" @click="fullscreen"></button>
<button :disabled="isLoading" @click="print"></button>
<button :disabled="isLoading" @click="download"></button>
</div>
<div>
<button :disabled="isLoading" @click="add"></button>
<button :disabled="isLoading" @click="Delete"></button>
<button :disabled="isLoading" @click="upload"></button>
</div>
</header>
<div class="pdf-wrap">
<div
class="pdf-content"
id="pdfContent"
v-loading="isLoading"
element-loading-text="加载中..."
@scroll="scroll"
ref="content"
></div>
</div>
<footer>
<div>
<span>页数</span>
<span>{{ pageNum }}</span>
<span>/</span>
<span>{{ pageCount }}</span>
</div>
<Slider ref="slider" @changevalue="changescale"></Slider>
</footer>
</div>
</template>
js部分
<script>
import Slider from "@/components/Manage/Slider/index.vue";
import { TextLayerBuilder } from "pdfjs-dist/web/pdf_viewer";
import "pdfjs-dist/web/pdf_viewer.css";
import { mapState } from "vuex";
export default {
data() {
return {
height: "", //高
width: "", //宽
pdfJs: null, // 加载的pdfjs
pdfDoc: null, // pdfjs读取的页面信息
pageNum: 1, // 当前页数
pageCount: 0, // 总页数
scale: 1.8, // 放大倍数
firstscale: 1.8, //记录初始的状态
// scale:1,
maxscale: 3, // 最大放大倍数
minscale: 0.3, // 最小放大倍数
// domWaterMarkCanvas: document.createElement("canvas"), // 水印canvas元素
waterInfo: [{ watermark: "1" }, { watermark: "2" }],
isLoading: true, // 文档是否正在加载
flag: false,
deg: 0, //旋转的角度
iswdithscreen: false, //是否横屏展开
iTime: null, //定时器防抖
url: "http://mozilla.github.io/pdf.js/web/compressed.tracemonkey-pldi-09.pdf",
};
},
watch: {},
computed: {
...mapState({
//水印列表
watermarkList(state) {
return state.manageSet.WaterMaskList;
},
}),
},
created() {
// console.log(TextLayerBuilder);
// 若开启,则创建水印模板
// if (this.waterInfo.enable) this.createWatermarkTemplate();
// this.loadPdfJs(
// "https://raw.githubusercontent.com/mozilla/pdf.js/ba2edeae/web/compressed.tracemonkey-pldi-09.pdf"
// );
},
mounted() {
this.$nextTick(() => {
this.getPDF(this.url);
});
},
methods: {
add() {
this.showdiscription = !this.showdiscription;
// console.log(this.showdiscription);
},
checkboxChange(val) {
//checkbox值改变时判断选中几个 超出两个选择后重置
if (this.tableData.filter((item) => item.checked == 1).length == 2) {
console.log(val);
this.tableData.forEach((item) => {
if (item.checked == 0) {
item.disabled = true;
}
});
} else {
this.tableData.forEach((item) => {
if (item.checked == 0) {
item.disabled = false;
}
});
}
},
// 读取pdf文件资源
getPDF(url) {
import("pdfjs-dist").then((pdfJs) => {
// debugger
//获取到pdfjs-dist中的pdfjs对象
this.flag = false;
this.pdfJs = pdfJs;
pdfJs.GlobalWorkerOptions.workerSrc =
"https://cdnjs.cloudflare.com/ajax/libs/pdf.js/2.5.207/pdf.worker.js";
this.pdfJs.getDocument(url).promise.then((pdfDoc) => {
this.pageCount = pdfDoc.numPages;
this.pdfDoc = pdfDoc;
//获取到pdf容器的集合
const section = document
.getElementById("pdfContent")
.querySelectorAll("section");
//如果存在就先移除再次创建渲染
if (section.length != 0) {
//通过flag来判断是否移除元素
this.flag = true;
}
for (let i = 0; i <= pdfDoc.numPages; i++) {
try {
this.rendPDF(i);
} catch (e) {
console.error(e);
}
}
this.isLoading = false;
});
});
},
//渲染pdf指定页面
rendPDF(num) {
this.pdfDoc.getPage(num).then((page) => {
//判断页面有没有存在的容器
if (this.flag) {
document
.getElementById("pdfContent")
.removeChild(
document.getElementById("pdfContent").querySelector("section")
);
}
//创建每页pdf容器
let pageDiv = document.createElement("section");
//设置每页容器的属性
pageDiv.setAttribute("id", "page-" + (page._pageIndex + 1));
pageDiv.setAttribute(
"style",
`position: relative;margin: 0 auto 10px;transform:rotate(${this.deg}deg)`
);
//添加到页面上
document.getElementById("pdfContent").appendChild(pageDiv);
// 创建供当前pdf页面渲染的canvas元素
let canvas = document.createElement("canvas");
// 设定canvas元素样式信息
canvas.setAttribute("style", "margin: 0 auto ;display:block");
//添加到容器上
pageDiv.appendChild(canvas);
let context = canvas.getContext("2d");
// 获取当前pdf页面信息
let viewport = page.getViewport({ scale: this.scale });
// 使用获取到的pdf信息,给canvas元素设定宽高
this.height = viewport.height;
if (!this.iswdithscreen) {
this.width = viewport.width;
} else {
this.width = document.getElementById("pdfContent").clientWidth;
}
canvas.height = this.height;
canvas.width = this.width;
//创建水印模板
let waterDiv = document.createElement("div");
waterDiv.setAttribute("id", "water-" + (page._pageIndex + 1));
waterDiv.setAttribute(
"style",
`position: absolute;left:0;top:0;width:${this.width};height:${this.height};transform:rotate(${this.deg}deg)`
);
pageDiv.appendChild(waterDiv);
//添加水印内容
for (let i = 0; i < 3; i++) {
let waterDivcontent = document.createElement("div");
//根据水印列表添加内容
let str = "";
this.watermarkList.forEach((item) => {
str += `<span>${item.watermark}<span>`;
});
waterDivcontent.innerHTML = str;
waterDivcontent.style.transform = "rotate(-45deg)";
waterDivcontent.style.fontSize = "200px";
waterDivcontent.style.paddingLeft = ` ${i * 200}px`;
waterDivcontent.style.color = "rgb(0 0 0 / 11%)";
waterDivcontent.style.width = "200px";
waterDivcontent.style.margin = "250px";
waterDiv.appendChild(waterDivcontent);
}
let renderContext = {
canvasContext: context,
viewport: viewport,
};
page.render(renderContext);
page.getTextContent().then((textContent) => {
// 创建文本图层div
const textLayerDiv = document.createElement("div");
textLayerDiv.setAttribute("class", "textLayer");
textLayerDiv.setAttribute(
"style",
`width: ${this.width}px;height:100%; margin: 0 auto;`
);
// 将文本图层div添加至每页pdf的div中
pageDiv.appendChild(textLayerDiv);
// 创建新的TextLayerBuilder实例
var textLayer = new TextLayerBuilder({
textLayerDiv: textLayerDiv,
pageIndex: page._pageIndex,
viewport: viewport,
});
textLayer.setTextContent(textContent);
try {
textLayer.render();
} catch (error) {
return;
}
});
});
},
//放大
enlarge() {
this.$refs.slider.add();
},
shrink() {
this.$refs.slider.reducing();
},
//旋转
rotate(deg) {
if (deg == "right") {
this.deg += 90;
} else {
this.deg -= 90;
}
document
.getElementById("pdfContent")
.querySelectorAll("section")
.forEach((item) => {
item.style.transform = `rotate(${this.deg}deg)`;
});
},
//滚动获取当前页码
scroll() {
if (this.$refs.content.scrollTop / this.height < 1) {
this.pageNum = 1;
} else {
this.pageNum = Math.ceil(this.$refs.content.scrollTop / this.height);
}
},
//拖动条值改变
changescale(val) {
clearTimeout(this.iTime);
this.iTime = setTimeout(() => {
this.scale = (1.8 / 100) * Number(val);
// console.log(Number(val));
this.getPDF(this.url);
}, 300);
},
//横向屏
wdithscreen() {
this.iswdithscreen = !this.iswdithscreen;
if (this.iswdithscreen) {
document.getElementById("pdfContent").style.width = "100%";
this.scale = 2.8;
let url =
"http://mozilla.github.io/pdf.js/web/compressed.tracemonkey-pldi-09.pdf";
this.getPDF(url);
} else {
document.getElementById("pdfContent").style.width = "1110px";
this.scale = 1.8;
let url =
"http://mozilla.github.io/pdf.js/web/compressed.tracemonkey-pldi-09.pdf";
this.getPDF(url);
}
},
//全屏
fullscreen() {
let docElm = document.getElementById("pdfContent");
if (docElm.requestFullscreen) {
docElm.requestFullscreen();
}
//FireFox
else if (docElm.mozRequestFullScreen) {
docElm.mozRequestFullScreen();
}
//Chrome等
else if (docElm.webkitRequestFullScreen) {
docElm.webkitRequestFullScreen();
}
//IE11
else if (elem.msRequestFullscreen) {
elem.msRequestFullscreen();
}
},
//打印
print() {
this.scale = 3;
const canvas = document.querySelectorAll("canvas");
var newWindow = window.open();
newWindow.title = "aaa";
let str = "";
canvas.forEach((item) => {
let dataURL = item.toDataURL("image/png");
str += '<img width="900px" src="' + dataURL + '"/ >';
});
newWindow.document.write(str);
this.$nextTick(() => {
newWindow.print();
});
},
Delete() {},
upload() {
this.$refs.UPLOAD.Upload();
},
download() {},
},
components: {
Slider,
UPLOAD,
},
};
</script>
css部分
<style lang="scss" scoped>
header {
height: 57px;
background: #1c3970;
display: flex;
justify-content: flex-end;
div {
display: flex;
align-items: center;
button {
display: inline-block;
width: 26px;
height: 26px;
background-position: center;
background-repeat: no-repeat;
line-height: 57px;
margin-right: 42px;
cursor: pointer;
background-color: transparent;
border: 0;
outline: 0;
}
&:nth-of-type(1) {
button {
&:nth-of-type(1) {
background-image: url("~@/assets/img/pdf/对比.png");
&:hover {
background-image: url("~@/assets/img/pdf/对比(1).png");
}
}
&:nth-of-type(2) {
background-image: url("~@/assets/img/pdf/搜索放大.png");
&:hover {
background-image: url("~@/assets/img/pdf/搜索放大(1).png");
}
}
&:nth-of-type(3) {
background-image: url("~@/assets/img/pdf/缩小.png");
&:hover {
background-image: url("~@/assets/img/pdf/缩小(1).png");
}
}
&:nth-of-type(4) {
background-image: url("~@/assets/img/pdf/旋转 拷贝.png");
&:hover {
background-image: url("~@/assets/img/pdf/旋转 拷贝(1).png");
}
}
&:nth-of-type(5) {
background-image: url("~@/assets/img/pdf/旋转.png");
&:hover {
background-image: url("~@/assets/img/pdf/旋转(1).png");
}
}
&:nth-of-type(6) {
background-image: url("~@/assets/img/pdf/单箭头,长箭头,右 拷贝.png");
&:hover {
background-image: url("~@/assets/img/pdf/单箭头,长箭头,右 拷贝(1).png");
}
}
&:nth-of-type(7) {
background-image: url("~@/assets/img/pdf/全屏.png");
&:hover {
background-image: url("~@/assets/img/pdf/全屏(1).png");
}
}
&:nth-of-type(8) {
background-image: url("~@/assets/img/pdf/打印机.png");
&:hover {
background-image: url("~@/assets/img/pdf/打印机(1).png");
}
}
&:nth-of-type(9) {
margin-right: 28px;
background-image: url("~@/assets/img/pdf/下载 (1).png");
&:hover {
background-image: url("~@/assets/img/pdf/下载 (2).png");
}
}
}
}
&:nth-of-type(2) {
&::before {
content: "";
width: 1px;
height: 26px;
background: #566a8f;
}
button {
&:nth-of-type(1) {
margin-left: 34px;
background-image: url("~@/assets/img/pdf/详情、门票.png");
&:hover {
background-image: url("~@/assets/img/pdf/详情、门票(1).png");
}
}
&:nth-of-type(2) {
background-image: url("~@/assets/img/pdf/删除 (2).png");
&:hover {
background-image: url("~@/assets/img/pdf/删除 (3).png");
}
}
&:nth-of-type(3) {
background-image: url("~@/assets/img/pdf/上传.png");
&:hover {
background-image: url("~@/assets/img/pdf/上传(1).png");
}
}
}
}
}
}
.discription {
position: absolute;
top: 57px;
left: 0;
height: 0;
width: 100%;
background-color: #0d2752;
transition: all 0.3s;
z-index: 9999;
overflow-y: hidden;
box-sizing: border-box;
display: flex;
.left,
.right {
.title {
display: flex;
width: 100%;
justify-content: space-between;
section {
width: 242px;
height: 34px;
background: url("~@/assets/img/mange-home/矩形 26 拷贝 3.png") no-repeat
center;
line-height: 34px;
font-size: 20px;
color: #23cefd;
margin-bottom: 17px;
span {
margin-left: 17px;
}
}
.btn {
height: 34px;
margin-right: 0;
}
}
}
.middle {
height: 187px;
width: 1px;
background-color: #24437d;
margin: 26px 80px 0;
}
.right {
width: 1000px;
}
.edit {
display: flex;
flex-direction: row;
flex-wrap: nowrap;
justify-content: space-around;
span {
color: #02c0ff;
text-decoration: underline;
}
}
}
.down {
height: 315px;
transition: all 0.3s;
padding: 38px 66px 38px 66px;
overflow-y: hidden;
}
.pdf-wrap {
height: calc(100% - 124px);
overflow-x: auto;
// overflow-y: auto;
.pdf-content {
height: 100%;
margin: 0 auto;
overflow-y: scroll;
background-color: rgba(0, 0, 0, 0.2);
width: 1110px;
position: relative;
// height: 400px;
}
}
footer {
margin-top: 18px;
position: sticky;
bottom: 0;
left: 0;
height: 48px;
border-top: 1px solid #324a88;
line-height: 48px;
padding: 0 28px;
display: flex;
justify-content: space-between;
flex-direction: row;
flex-wrap: nowrap;
}
</style>
<style lang="scss">
.month {
.el-table td {
padding: 2px 0 !important;
}
.el-table .el-table__cell {
padding: 0px !important;
}
}
</style>
slider组件
<template>
<div class="block">
<span style="width: 60px" v-show="flag" @click="toggle">{{
value + "%"
}}</span>
<el-input
ref="input"
style="width: 60px"
v-show="!flag"
v-model="inputValue"
@blur="blurValue"
oninput="value=value.replace(/[^\d.]/g,'')"
></el-input>
<span
style="
cursor: pointer;
padding: 0px 10px 0px 0px;
transform: translateY(-1px);
"
@click="reducing"
>-</span
>
<el-slider
v-model="value"
:format-tooltip="formatTooltip"
:min="min"
:max="max"
style="width: 138px; display: inline-block"
@change="change"
></el-slider>
<span
style="
cursor: pointer;
padding: 0px 0px 0px 10px;
transform: translateY(-1px);
"
@click="add"
>+</span
>
</div>
</template>
<script>
export default {
data() {
return {
value: 100,
flag: true,
min: 50,
max: 200,
inputValue: "",
};
},
watch: {
inputValue: {
handler(newval) {
this.$emit("changevalue", newval);
},
},
},
methods: {
blurValue() {
//文本框显示出来
this.flag = !this.flag;
//文本框获取到最新的值
this.value = Number(this.inputValue);
},
formatTooltip(val) {
return val + "%";
},
//点击切换到input框 并且自动聚焦
toggle() {
this.flag = !this.flag;
this.$nextTick(() => this.$refs.input.focus());
//获取到Input框的值
this.inputValue = this.value;
},
//点击减号 减少10%
reducing() {
if (this.value > this.min) {
this.value -= 10;
this.$emit("changevalue", this.value);
}
},
//点击加号 增加10%
add() {
if (this.value < this.max) {
this.value += 10;
this.$emit("changevalue", this.value);
}
},
change(newval) {
this.$emit("changevalue", newval);
},
},
};
</script>
<style lang="scss" scoped>
.block {
display: flex;
align-items: center;
}
</style>
<style>
.el-slider__runway {
height: 3px;
}
//左侧进度条样式
.el-slider__bar {
height: 3px;
}
//中间button样式
.el-slider__button {
width: 4px;
height: 4px;
border: 1px solid #409EFF;
background-color: #FFF;
}
.el-slider__button-wrapper {
height: auto;
width: auto;
position: absolute;
top: 0;
transform: translate(-50%, -50%);
}
</style>