vue項(xiàng)目如何實(shí)現(xiàn)前端預(yù)覽word與pdf格式文件
最近做vue項(xiàng)目遇到一個需求,就是前端實(shí)現(xiàn)上傳word或pdf文件后,后端返回文件對應(yīng)的文件流,前端需要在頁面上展示出來。word預(yù)覽簡單一些,pdf預(yù)覽我試過pdfjs,vue-pdf總是報(bào)各種奇奇怪怪的bug,但最終總算解決了問題,先看一下頁面最終呈現(xiàn)效果吧:
頁面上傳pdf文件效果如下:

頁面預(yù)覽pdf文件效果如下:

頁面上傳word文件效果如下:

頁面預(yù)覽word文件效果如下:

這里先從上傳組件頁面說起,上傳頁面組件完整代碼如下,按鈕里面v-show=“$checkPermission([‘Register_tuotpUpload’])“都是給這個按鈕設(shè)置了按鈕權(quán)限的,我們只需要關(guān)注上傳那一部分的代碼即可,我們用了el-upload組件實(shí)現(xiàn)的手動上傳,由于需求要求只能上傳word和pdf,所以能看到屬性設(shè)置的有 accept=”.pdf, .doc, .docx”,然后不展示上傳成功的文件的列表設(shè)置的屬性有:show-file-list=“false”,而handleExceed回調(diào)函數(shù)和limit都是為了限制只能上傳一個文件,上傳前的回調(diào)鉤子函數(shù)beforeAvatarUpload里進(jìn)行了文件類型判斷與提醒,手動上傳是通過UploadFile里進(jìn)行完成的,需要注意的是由于docx-preview這個插件只能預(yù)覽后綴為docx的word文件,如果是doc后綴格式的word文件一定要讓后端強(qiáng)制將上傳doc格式的文件改為docx格式,目前對于doc格式的word文件實(shí)現(xiàn)網(wǎng)頁在線預(yù)覽我只想到了docx-preview這個插件和這個解決辦法:
<template>
<div class="app-container">
<div class="cardWhite">
<div class="itemBox">
<div class="headerTitle">基本信息</div>
<el-form
:model="ruleForm"
:rules="rules"
ref="ruleForm"
label-width="120px"
class="demo-ruleForm"
>
<el-row>
<el-col :span="12">
<el-form-item label="鏈路名稱" prop="name">
<el-input
v-model="ruleForm.name"
placeholder="請輸入鏈路名稱"
clearable
></el-input>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="鏈路類型" prop="linkType">
<el-select
v-model="ruleForm.linkType"
placeholder="請選擇鏈路類型"
style="width:100%"
clearable
>
<el-option
v-for="item in linkTypeList"
:key="item.val"
:label="item.key"
:value="item.val"
></el-option>
</el-select>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="鏈路走向" prop="go">
<el-row>
<el-col :span="10">
<el-select
v-model="ruleForm.srcNetwork"
placeholder="請選擇"
style="width:100%"
clearable
@clear="clearSrc"
@change="srcChange"
>
<el-option
v-for="item in scrList"
:key="item.val"
:label="item.key"
:value="item.val"
></el-option>
</el-select>
</el-col>
<el-col :span="4">
<div style="text-align: center;width:100%">
<img
src="@/assets/toRight.png"
style="width:3.75rem;height:0.75rem;margin:0 auto"
/>
</div>
</el-col>
<el-col :span="10">
<el-select
v-model="ruleForm.dstNetwork"
placeholder="請選擇"
style="width:100%"
:clearable="false"
@clear="clearDst"
@change="dstChange"
>
<el-option
v-for="item in dstList"
:key="item.val"
:label="item.key"
:value="item.val"
></el-option>
</el-select>
</el-col>
</el-row>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="物理位置" prop="physicalPosition">
<el-input
v-model="ruleForm.physicalPosition"
placeholder="請輸入鏈路物理位置"
clearable
></el-input>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="所屬機(jī)構(gòu)" prop="orangeName">
<el-input
v-model="ruleForm.orangeName"
placeholder="例:xx市公安局"
clearable
></el-input>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="行政區(qū)編碼" prop="organCode">
<el-input
v-model="ruleForm.organCode"
placeholder="請輸入行政區(qū)編碼,例:027"
clearable
></el-input>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="責(zé)任人" prop="dutyPerson">
<el-input
v-model="ruleForm.dutyPerson"
placeholder="請輸入鏈路責(zé)任人"
clearable
></el-input>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="責(zé)任人電話" prop="dutyTel">
<el-input
v-model="ruleForm.dutyTel"
placeholder="請輸入鏈路責(zé)任人電話"
clearable
></el-input>
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col :span="12">
<el-form-item label="公安網(wǎng)郵箱" prop="dutyEmail">
<el-input
v-model="ruleForm.dutyEmail"
placeholder="請輸入負(fù)責(zé)人公安網(wǎng)郵箱"
clearable
></el-input>
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col :span="12">
<el-form-item label="鏈路IP地址" prop="ip">
<el-input
v-model="ruleForm.ip"
placeholder="請輸入鏈路IP地址"
clearable
></el-input>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="鏈路端口" prop="port">
<el-input-number
placeholder="請輸入鏈路端口"
type="text"
:min="0"
:controls="false"
v-model.trim="ruleForm.port"
style="width:100%"
></el-input-number>
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col :span="12">
<el-form-item label="管理頁面" prop="webUrl">
<el-input
v-model="ruleForm.webUrl"
placeholder="請輸入鏈路管理頁面"
clearable
></el-input>
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col :push="2">
<el-button
class="filter-item"
type="primary"
icon="el-icon-plus"
@click="saveForm"
v-show="$checkPermission(['Register_boundarySave'])"
>
保存
</el-button>
</el-col>
</el-row>
</el-form>
</div>
<div class="itemBox">
<div class="headerTitle">鏈路拓?fù)鋱D</div>
<el-form :model="tuopuForm" ref="tuopuForm" label-width="120px">
<el-row>
<el-col :span="12">
<el-form-item label="拓?fù)鋱D" prop="fileName">
<el-input
v-model="tuopuForm.fileName"
placeholder="請選擇電腦中拓?fù)鋱D文件"
clearable
disabled
>
<el-upload
accept=".pdf, .doc, .docx"
action="string"
:limit="1"
:on-exceed="handleExceed"
:before-upload="beforeAvatarUpload"
:http-request="UploadFile"
slot="append"
:show-file-list="false"
>
<el-button
type="primary"
v-show="$checkPermission(['Register_tuotpUpload'])"
icon="el-icon-upload2"
style="background:#1890ff;color:#fff;border-top-left-radius:0;border-bottom-left-radius:0"
>上傳</el-button
>
</el-upload>
</el-input>
</el-form-item>
</el-col>
<el-col :span="3" :push="1">
<el-button
class="filter-item"
type="primary"
icon="el-icon-view"
@click="preview"
v-show="$checkPermission(['Register_tuotpPreview'])"
>
預(yù)覽
</el-button>
</el-col>
</el-row>
</el-form>
</div>
<div class="itemBox">
<div class="headerTitle">設(shè)備信息列表</div>
<el-row type="flex" justify="end" style="margin:0.5rem 0;">
<el-button
class="filter-item"
type="primary"
icon="el-icon-plus"
@click="addEquipment"
v-show="$checkPermission(['Register_equipmentAdd'])"
>
添加
</el-button>
</el-row>
<div>
<commonTable
:tableHead="tableHead"
:tableData="tableData"
:dataFiter="true"
:selectionFlag="false"
:dropdownList="[]"
:resizable="true"
:tableLoading="tableLoading"
:showListD="showListD"
:toolBoxFlag="false"
@sortChange="() => {}"
@selection-change="() => {}"
@selectAction="() => {}"
@addData="() => {}"
:actionFlag="false"
:actionList="[]"
:freeElfFlag="false"
:xuhaoFlag="true"
:freeWidth="480"
>
<template
slot-scope="scope"
slot="doSomething"
fixed="right"
align="left"
>
<el-button
icon="el-icon-edit"
type="primary"
@click="handlerUpdate(scope.rows)"
v-show="$checkPermission(['Register_equipmentEdit'])"
>編輯</el-button
>
<el-button
icon="el-icon-delete"
type="danger"
@click="handlerDelete(scope.rows)"
v-show="$checkPermission(['Register_equipmentDelete'])"
style="margin-left:-0.015rem"
>刪除</el-button
>
</template>
</commonTable>
</div>
</div>
<div class="itemBox">
<div class="headerTitle">鏈路注冊</div>
<el-row type="flex" justify="end" style="margin:0.5rem 0;">
<el-button
class="filter-item"
type="primary"
icon="el-icon-plus"
@click="addRegister"
v-show="$checkPermission(['Register_registerAdd'])"
>
添加
</el-button>
</el-row>
<div>
<commonTable
:tableHead="Register_tableHead"
:tableData="Register_tableData"
:dataFiter="true"
:selectionFlag="false"
:dropdownList="[]"
:resizable="true"
:tableLoading="Register_tableLoading"
:showListD="Register_showListD"
:toolBoxFlag="false"
@sortChange="() => {}"
@selection-change="() => {}"
@selectAction="() => {}"
@addData="() => {}"
:actionFlag="false"
:actionList="[]"
:freeElfFlag="false"
:xuhaoFlag="true"
:freeWidth="480"
>
<template slot-scope="scope" slot="status">
<el-tag v-if="scope.rows.status == 1">已注冊</el-tag>
<el-tag type="success" v-if="scope.rows.status == 0"
>未注冊</el-tag
>
<el-tag type="danger" v-if="scope.rows.status == 2"
>注冊失敗</el-tag
>
</template>
<template
slot-scope="scope"
slot="doSomething"
fixed="right"
align="left"
>
<el-button
icon="el-icon-edit"
type="primary"
v-if="
scope.rows.status == 1 &&
$checkPermission(['Register_registerOff'])
"
@click="handlerLogoff(scope.rows)"
>注銷</el-button
>
<el-button
icon="el-icon-edit"
type="primary"
v-if="
($checkPermission(['Register_registerGo']) &&
scope.rows.status == 0) ||
scope.rows.status == 2
"
@click="handlerLogoff(scope.rows)"
>注冊</el-button
>
<el-button
icon="el-icon-delete"
type="danger"
v-if="$checkPermission(['Register_registerDelete'])"
@click="Register_handlerDelete(scope.rows)"
style="margin-left:-0.015rem"
>刪除</el-button
>
</template>
</commonTable>
</div>
</div>
</div>
<!-- 添加和編輯設(shè)備彈窗 -->
<el-dialog
:title="textMap[dialogStatus]"
:visible.sync="dialogFormVisible"
width="800px"
:before-close="handleClose"
:close-on-click-modal="false"
>
<add-edit
@refresh="fetchData"
@closeDialog="dialogFormVisible = false"
class="AddEdit"
ref="AddEdit"
:devTypeList="EquipmentList"
v-if="dialogFormVisible"
/>
<div slot="footer" class="dialog-footer">
<el-button @click="dialogFormVisible = false">
取消
</el-button>
<el-button type="primary" @click="submitForm()">
確定
</el-button>
</div>
</el-dialog>
<!-- 鏈路注冊彈窗 -->
<el-dialog
title="鏈路注冊"
:visible.sync="Register_dialogFormVisible"
width="800px"
:before-close="Register_handleClose"
:close-on-click-modal="false"
>
<register-add
@reg_refresh="Register_fetchData"
@reg_closeDialog="Register_dialogFormVisible = false"
ref="RegisterAdd"
v-if="Register_dialogFormVisible"
/>
<div slot="footer" class="dialog-footer">
<el-button @click="Register_dialogFormVisible = false">
取消
</el-button>
<el-button type="primary" @click="Register_submitForm()">
確定
</el-button>
</div>
</el-dialog>
</div>
</template>
<script>
import commonTable from "@/components/common-table";
import Pagination from "@/components/Pagination";
import AddEdit from "./EquipmentAddEdit.vue";
import RegisterAdd from "./RegisterAdd.vue";
import * as api from "@/api/datax-register.js";
import axios from "axios";
import { getToken } from "@/utils/auth";
export default {
components: {
Pagination,
commonTable,
AddEdit,
RegisterAdd
},
data() {
const validateGo = (rule, value, callback) => {
// if (!value) {
// callback("請輸入平臺IP地址");
// } else {
// let index = value.indexOf("/");
// let findHengT = value.indexOf("-");
// let findHengP = value.indexOf("——");
// if (index > -1 || findHengT > -1 || findHengP > -1) {
// callback("請輸入正確格式的平臺IP地址");
// } else {
// validator.IpArea(rule, value, callback);
// }
// }
if (!this.ruleForm.srcNetwork || !this.ruleForm.dstNetwork) {
callback("請選擇鏈路走向");
} else {
callback();
}
};
return {
ruleForm: {
name: "",
linkType: "",
srcNetwork: "",
dstNetwork: "",
physicalPosition: "",
orangeName: "",
organCode: "",
dutyPerson: "",
dutyTel: "",
dutyEmail: "",
ip: "",
port: undefined,
webUrl: ""
},
rules: {
name: [{ required: true, message: "請輸入鏈路名稱", trigger: "blur" }],
linkType: [
{ required: true, message: "請選擇鏈路類型", trigger: "blur" }
],
go: [
{
required: true,
message: "請選擇鏈路走向",
trigger: "blur",
validator: validateGo
}
],
physicalPosition: [
{ required: false, message: "請輸入鏈路物理位置", trigger: "blur" }
],
orangeName: [
{ required: true, message: "請輸入所屬機(jī)構(gòu)", trigger: "blur" }
],
organCode: [
{ required: true, message: "請輸入行政區(qū)編碼", trigger: "blur" }
],
dutyPerson: [
{ required: true, message: "請輸入鏈路責(zé)任人", trigger: "blur" }
],
dutyTel: [
{ required: true, message: "請輸入鏈路責(zé)任人電話", trigger: "blur" }
],
dutyEmail: [
{
required: false,
message: "請輸入負(fù)責(zé)人公安網(wǎng)郵箱",
trigger: "blur"
}
],
ip: [{ required: false, message: "請輸入鏈路IP地址", trigger: "blur" }],
port: [{ required: true, message: "請輸入鏈路端口", trigger: "blur" }],
webUrl: [
{ required: false, message: "請輸入鏈路管理頁面", trigger: "blur" }
]
},
linkTypeList: [],
scrList: [],
dstList: [],
tuopuForm: {
fileName: "",
fileUrl: ""
},
tableHead: [
{
label: "設(shè)備名稱",
prop: "name",
type: "normal",
sortable: false
},
{
label: "設(shè)備類型",
prop: "devType",
type: "normal",
sortable: false
// width: 150
},
{
label: "廠商",
prop: "manufacturer",
type: "normal",
sortable: false
// width: 150
},
{
label: "型號",
prop: "model",
type: "normal",
sortable: false
// width: 150
},
{
label: "設(shè)備IP",
prop: "devIp",
type: "normal",
sortable: false
},
{
label: "子網(wǎng)掩碼",
prop: "ipMask",
type: "normal",
sortable: false
// width: 150
},
{
label: "網(wǎng)關(guān)",
prop: "ipGaway",
type: "normal",
sortable: false
// width: 150
},
{
label: "安裝時(shí)間",
prop: "installTime",
type: "normal",
sortable: false,
width: 180
},
{
label: "操作",
prop: "doSomething",
type: "slot",
sortable: false,
slotName: "doSomething",
width: 220
}
// {
// label: "任務(wù)詳情",
// prop: "log_text",
// type: "slot",
// sortable: false,
// slotName: "log_text",
// width: 100
// }
],
showListD: [
"name",
"devType",
"manufacturer",
"model",
"devIp",
"ipMask",
"ipGaway",
"installTime",
"doSomething"
// "log_text"
],
dialogStatus: "",
dialogFormVisible: false,
textMap: {
update: "編輯設(shè)備",
Edit: "編輯設(shè)備",
edit: "編輯設(shè)備",
create: "添加設(shè)備"
},
tableData: [],
tableLoading: false,
Register_tableHead: [
{
label: "平臺名稱",
prop: "name",
type: "normal",
sortable: false
},
{
label: "平臺IP地址",
prop: "ip",
type: "normal",
sortable: false
},
{
label: "平臺端口",
prop: "port",
type: "normal",
sortable: false
},
{
label: "平臺唯一標(biāo)識",
prop: "uniquePlatformCode",
type: "normal",
sortable: false
},
{
label: "注冊時(shí)間",
prop: "lastTime",
type: "normal",
sortable: false,
width: 180
},
{
label: "注冊狀態(tài)",
prop: "status",
type: "slot",
slotName: "status",
sortable: false
},
{
label: "操作",
prop: "doSomething",
type: "slot",
sortable: false,
slotName: "doSomething",
width: 220
}
// {
// label: "任務(wù)詳情",
// prop: "log_text",
// type: "slot",
// sortable: false,
// slotName: "log_text",
// width: 100
// }
],
Register_tableData: [],
Register_tableLoading: false,
Register_showListD: [
"name",
"ip",
"port",
"uniquePlatformCode",
"lastTime",
"status",
"doSomething"
// "log_text"
],
Register_dialogFormVisible: false,
fileList: null, //拓?fù)鋱D文件列表
tuotpData: null,
EquipmentList: [],
originalList: []
};
},
created() {
this.getNews();
},
methods: {
getNews() {
//獲取邊界信息
this.getBoundaryDetail();
//獲取拓?fù)鋱D
this.getTuotp();
//獲取設(shè)備列表
this.fetchData();
//獲取鏈路注冊列表
this.Register_fetchData();
//獲取公共下拉
this.getSelect();
},
saveForm() {
this.$refs["ruleForm"].validate(valid => {
if (valid) {
let params = {
...this.ruleForm
};
console.log("修改入?yún)?, params);
//修改
api
.boundaryEdit(params)
.then(res => {
console.log("修改", res);
if (res.code == 200) {
this.$notify({
title: "成功",
message: "邊界信息修改成功",
type: "success",
duration: 2000
});
}
})
.catch(err => {});
}
});
},
preview() {
console.log("預(yù)覽", this.fileList, this.tuopuForm);
if (!this.fileList) {
this.$message.error(
"拓?fù)鋱D文件為空不能預(yù)覽,請先上傳拓?fù)鋱D文件后再預(yù)覽",
6000
);
return false;
}
this.$router.push({
path: "TuotpPreview",
query: {
fileName: this.tuopuForm.fileName,
fileUrl: this.tuopuForm.fileUrl
}
});
},
addEquipment() {
this.dialogStatus = "create";
this.dialogFormVisible = true;
setTimeout(() => {
this.$refs["AddEdit"].dialogStatus = "create";
// this.$refs.AddEdit.resetTransferDetail();
// this.getCommonData();
}, 1);
},
//獲取公共下拉
getSelect() {
api
.getLinkEquimentSelect({
clsName: "link_direction"
})
.then(res => {
console.log("鏈路走向下拉", res);
this.scrList = res.data;
this.dstList = res.data;
this.originalList = res.data;
})
.catch(err => {});
api
.getLinkEquimentSelect({
clsName: "link_type"
})
.then(res => {
console.log("鏈路類型下拉", res);
this.linkTypeList = res.data;
})
.catch(err => {});
api
.getLinkEquimentSelect({
clsName: "dev_type"
})
.then(res => {
console.log("設(shè)備類型下拉", res);
this.EquipmentList = res.data;
})
.catch(err => {});
},
//獲取邊界信息
getBoundaryDetail() {
api
.boundaryDetail()
.then(res => {
// console.log("獲取邊界信息", res);
this.ruleForm = res.data;
this.ruleForm.port = res.data.port ? res.data.port : undefined;
})
.catch(err => {});
},
//獲取拓?fù)鋱D
getTuotp() {
api
.boundaryTuopoDetail()
.then(res => {
// console.log("獲取拓?fù)鋱D成功", res);
this.tuopuForm = res.data;
this.tuopuPreview();
})
.catch(err => {
// console.log("獲取拓?fù)鋱D失敗", err);
});
},
//獲取設(shè)備列表
fetchData() {
this.tableLoading = true;
api
.equipmentList({
page: 1,
page_size: 99999,
ip: ""
})
.then(res => {
// console.log("設(shè)備列表", res);
if (res.code == 200) {
this.tableData = res.data.list;
this.tableLoading = false;
}
})
.catch(err => {});
},
//編輯
handlerUpdate(row) {
// console.log("點(diǎn)了修改", row);
this.dialogStatus = "Edit";
this.dialogFormVisible = true;
setTimeout(() => {
this.$refs["AddEdit"].setData(row);
this.$refs["AddEdit"].dialogStatus = "Edit";
}, 1);
},
handleClose() {
this.dialogFormVisible = false;
},
submitForm() {
this.$refs["AddEdit"].submitForm();
},
//刪除
handlerDelete(row) {
this.$confirm("確定刪除嗎?", "提示", {
confirmButtonText: "確定",
cancelButtonText: "取消",
type: "warning"
}).then(() => {
api
.equipmentDelete(row)
.then(response => {
if (response.code == 200) {
this.fetchData();
this.$notify({
title: "成功",
message: "刪除成功",
type: "success",
duration: 2000
});
}
})
.catch(err => {});
});
// const index = this.list.indexOf(row)
},
//注銷
handlerLogoff(row) {
api
.registerStatusSwitch({
id: row.id,
status: row.status == 1 ? 2 : 1
})
.then(res => {
this.Register_fetchData();
})
.catch(err => {});
},
//鏈路刪除
Register_handlerDelete(row) {
this.$confirm("確定刪除嗎?", "提示", {
confirmButtonText: "確定",
cancelButtonText: "取消",
type: "warning"
}).then(() => {
let id = row.id;
api.VideoTaskDelete(id).then(response => {
if (response.code == 200) {
this.fetchData();
this.$notify({
title: "成功",
message: "刪除成功",
type: "success",
duration: 2000
});
}
});
});
},
//鏈路添加
addRegister() {
this.$refs["ruleForm"].validate(valid => {
if (valid) {
this.Register_dialogFormVisible = true;
setTimeout(() => {
// this.$refs["AddEdit"].dialogStatus = "create";
// this.$refs.AddEdit.resetTransferDetail();
// this.getCommonData();
}, 1);
} else {
this.$message.error("基本信息為空不能添加,請先補(bǔ)充基本信息", 6000);
}
});
},
Register_handleClose() {
this.Register_dialogFormVisible = false;
},
Register_submitForm() {
this.$refs["RegisterAdd"].submitForm();
},
//獲取鏈路注冊列表
Register_fetchData() {
this.Register_tableLoading = true;
api
.registerList({
page: 1,
page_size: 99999,
ip: ""
})
.then(res => {
console.log("注冊列表", res);
if (res.code == 200) {
this.Register_tableData = res.data.list;
this.Register_tableLoading = false;
}
})
.catch(err => {});
},
handleExceed(files, fileList) {
if (files.length > 1) {
this.$message.warning(
`當(dāng)前限制最多選擇1個文件上傳,本次選擇了${files.length}個文件`
);
}
},
//文件上傳前的鉤子
beforeAvatarUpload(file) {
console.log("文件上傳前的鉤子", file);
// 文件類型判斷
var testmsg = file.name.substring(file.name.lastIndexOf(".") + 1);
const extension = testmsg === "doc";
const extension2 = testmsg === "pdf";
const extension3 = testmsg === "docx";
if (!extension && !extension2 && !extension3) {
this.$message({
message: "上傳的拓?fù)鋱D文件只能是word、pdf格式,請重新上傳!",
type: "error",
duration: 6000
});
this.fileList = null;
return false;
} else {
this.fileList = file;
}
},
//自定義上傳
UploadFile() {
// 參數(shù)拼接
let fileData = new FormData();
fileData.append("file", this.fileList);
// 調(diào)用接口
axios({
url: `${window.g.API_URL}/api/cascade/topo/upload`,
method: "post",
data: fileData,
headers: {
"Content-Type": "multipart/form-data",
Authorization: getToken()
}
})
.then(res => {
console.log("上傳成功", res);
if (res.data.code == 200) {
this.tuopuForm = res.data.data;
//拓?fù)漕A(yù)覽
this.tuopuPreview();
} else {
console.log("上傳失敗1");
this.$message({
message: "上傳拓?fù)鋱D文件失敗,請稍后重試!",
type: "error",
duration: 6000
});
}
})
.catch(err => {
console.log("上傳失敗2", err);
this.$message({
message: "上傳拓?fù)鋱D文件失敗,請稍后重試!",
type: "error",
duration: 6000
});
});
},
tuopuPreview() {
axios({
url: `${window.g.API_URL}/api/cascade/topo/preview`,
method: "get",
params: {
fileUrl: this.tuopuForm.fileUrl
},
headers: {
Authorization: getToken()
},
responseType: "arraybuffer"
})
.then(res => {
console.log("拓?fù)漕A(yù)覽獲取成功", res);
if (res.status == 200) {
this.fileList = res.data;
}
})
.catch(err => {
console.log("拓?fù)漕A(yù)覽失敗失敗", err);
});
},
srcChange(val) {
console.log("srcChange", val);
if (val == this.ruleForm.dstNetwork) {
this.ruleForm.dstNetwork = "";
}
this.dstList = this.originalList.filter(k => {
return k.val != val;
});
},
clearSrc() {
this.scrList = JSON.parse(JSON.stringify(this.originalList));
},
dstChange(val) {
console.log("dstChange", val);
if (val == this.ruleForm.srcNetwork) {
this.ruleForm.srcNetwork = "";
}
this.scrList = this.originalList.filter(k => {
return k.val != val;
});
},
clearDst() {
this.dstList = JSON.parse(JSON.stringify(this.originalList));
}
}
};
</script>
<style lang="scss" scoped>
.app-container {
.cardWhite {
.itemBox {
margin-bottom: 1.5rem;
.headerTitle {
font-size: 1rem;
font-weight: bold;
}
}
}
}
::v-deep .el-input-number .el-input__inner {
text-align: left;
}
</style>
上傳功能實(shí)現(xiàn)之后,我們再看預(yù)覽功能。我們需求是點(diǎn)擊預(yù)覽按鈕之后跳到一個新頁面進(jìn)行預(yù)覽,我先是對文件是否為空是否沒上傳進(jìn)行了一個判斷攔截,由于預(yù)覽頁面組件與當(dāng)前頁面組件既非父子關(guān)系,又非爺孫關(guān)系,八竿子打不著的關(guān)系,我們就不能通過綁定和sessionStorage來進(jìn)行流文件的傳遞,只能在預(yù)覽頁面再發(fā)一次請求獲取文件流,我們可以把參數(shù)通過路由帶上,預(yù)覽按鈕對應(yīng)的方法代碼如下:
preview() {
console.log("預(yù)覽", this.fileList, this.tuopuForm);
if (!this.fileList) {
this.$message.error(
"拓?fù)鋱D文件為空不能預(yù)覽,請先上傳拓?fù)鋱D文件后再預(yù)覽",
6000
);
return false;
}
this.$router.push({
path: "TuotpPreview",
query: {
fileName: this.tuopuForm.fileName,
fileUrl: this.tuopuForm.fileUrl
}
});
}
再來看預(yù)覽頁面,也就是TuotpPreview.vue組件。word預(yù)覽比較簡單,先通過命令cnpm i docx-preview --save安裝插件docx-preview,需要注意的是這個插件只能預(yù)覽后綴為docx的word文件,如果是doc后綴格式的word文件一定要讓后端強(qiáng)制將上傳doc格式的文件改為docx格式,然后當(dāng)前頁面組件就直接import { defaultOptions, renderAsync } from “docx-preview”;引入,最后在data里進(jìn)行docxOptions配置,然后在頁面上 要顯示的div上綁定一個 id="bodyContainer"的,因?yàn)橄旅嬉ㄟ^document.getElementById來獲取dom并操作dom,最后調(diào)用renderAsync方法即可。
cnpm i docx-preview --save //安裝word預(yù)覽插件docx-preview
import { defaultOptions, renderAsync } from "docx-preview"; //引入docx-preview插件對應(yīng)的方法
docxOptions: {
className: "kaimo-docx-666", // string:默認(rèn)和文檔樣式類的類名/前綴
inWrapper: true, // boolean:啟用圍繞文檔內(nèi)容的包裝器渲染
ignoreWidth: false, // boolean:禁用頁面的渲染寬度
ignoreHeight: false, // boolean:禁止渲染頁面高度
ignoreFonts: false, // boolean:禁用字體渲染
breakPages: true, // boolean:在分頁符上啟用分頁
ignoreLastRenderedPageBreak: true, // boolean:在 lastRenderedPageBreak 元素上禁用分頁
experimental: false, // boolean:啟用實(shí)驗(yàn)功能(制表符停止計(jì)算)
trimXmlDeclaration: true, // boolean:如果為true,解析前會從?? xml 文檔中移除 xml 聲明
useBase64URL: false, // boolean:如果為true,圖片、字體等會轉(zhuǎn)為base 64 URL,否則使用URL.createObjectURL
useMathMLPolyfill: false, // boolean:包括用于 chrome、edge 等的 MathML polyfill。
showChanges: false, // boolean:啟用文檔更改的實(shí)驗(yàn)性渲染(插入/刪除)
debug: false // boolean:啟用額外的日志記錄
},
pdf文件的預(yù)覽是通過獲取到blob文件流之后,直接通過window.open打開新窗口,通過瀏覽器就能預(yù)覽pdf,還有一種就是我現(xiàn)在的這種需求,要在頁面上預(yù)覽pdf,那就需要通過iframe,然后把blob流對應(yīng)的src地址賦值回顯即可。完整代碼如下:
<template>
<div>
<!-- 拓?fù)鋱D預(yù)覽 -->
<div class="app-container">
<div class="cardWhite">
<div class="topArea">
<div class="backBox">
<img src="@/assets/goBack.png" @click="goBack" alt="" />
</div>
<div class="titleBox">
{{ myTitle }}
</div>
</div>
<div class="previewBox">
<div id="bodyContainer">
<iframe :src="pdfUrl" width="100%" height="750px" />
</div>
</div>
</div>
</div>
</div>
</template>
<script>
import axios from "axios";
import { getToken } from "@/utils/auth";
import { defaultOptions, renderAsync } from "docx-preview";
export default {
data() {
return {
myTitle: "",
previewData: null,
docxOptions: {
className: "kaimo-docx-666", // string:默認(rèn)和文檔樣式類的類名/前綴
inWrapper: true, // boolean:啟用圍繞文檔內(nèi)容的包裝器渲染
ignoreWidth: false, // boolean:禁用頁面的渲染寬度
ignoreHeight: false, // boolean:禁止渲染頁面高度
ignoreFonts: false, // boolean:禁用字體渲染
breakPages: true, // boolean:在分頁符上啟用分頁
ignoreLastRenderedPageBreak: true, // boolean:在 lastRenderedPageBreak 元素上禁用分頁
experimental: false, // boolean:啟用實(shí)驗(yàn)功能(制表符停止計(jì)算)
trimXmlDeclaration: true, // boolean:如果為true,解析前會從?? xml 文檔中移除 xml 聲明
useBase64URL: false, // boolean:如果為true,圖片、字體等會轉(zhuǎn)為base 64 URL,否則使用URL.createObjectURL
useMathMLPolyfill: false, // boolean:包括用于 chrome、edge 等的 MathML polyfill。
showChanges: false, // boolean:啟用文檔更改的實(shí)驗(yàn)性渲染(插入/刪除)
debug: false // boolean:啟用額外的日志記錄
},
num: 1,
numPages: 0,
pdfUrl: ""
};
},
created() {
console.log("接收", this.$route.query);
this.resetTitle();
this.getFile();
},
methods: {
goBack() {
this.$router.go(-1);
},
//獲取文件流
getFile() {
axios({
url: `${window.g.API_URL}/api/cascade/topo/preview`,
method: "get",
params: {
fileUrl: this.$route.query.fileUrl
},
headers: {
Authorization: getToken()
},
responseType: "arraybuffer"
})
.then(res => {
console.log("文件流獲取成功", res);
if (res.status == 200) {
this.previewData = res.data;
if (
this.$route.query.fileName &&
this.$route.query.fileName.indexOf(".docx") &&
this.$route.query.fileName.indexOf(".pdf") == -1
) {
//word--docx格式
this.wordPreview(res.data);
} else if (
this.$route.query.fileName &&
this.$route.query.fileName.indexOf(".doc") &&
this.$route.query.fileName.indexOf(".pdf") == -1
) {
//word--doc格式
this.wordPreview(res.data);
} else if (
this.$route.query.fileName &&
this.$route.query.fileName.indexOf(".pdf")
) {
//pdf
this.pdfPreview(res.data);
}
}
})
.catch(err => {
console.log("文件流獲取失敗", err);
this.$message.error("獲取文件信息失敗,請稍后重試", 6000);
});
},
//重置標(biāo)題
resetTitle() {
let fileName = this.$route.query.fileName;
console.log("fileName", fileName);
if (
fileName &&
fileName.indexOf(".docx") &&
fileName.indexOf(".pdf") == -1
) {
//word--docx格式
let wordDocxArr = fileName.split(".docx");
console.log("wordDocxArr", wordDocxArr);
this.myTitle = wordDocxArr[0];
} else if (
fileName &&
fileName.indexOf(".doc") &&
fileName.indexOf(".pdf") == -1
) {
//word--doc格式
let wordDocArr = fileName.split(".docx");
console.log("wordDocArr", wordDocArr);
this.myTitle = wordDocArr[0];
} else if (fileName && fileName.indexOf(".pdf")) {
//pdf
let pdfArr = fileName.split(".pdf");
console.log("pdfArr", pdfArr);
this.myTitle = pdfArr[0];
}
},
// word文檔預(yù)覽
wordPreview(buffer) {
console.log("文檔buffer", buffer);
let bodyContainer = document.getElementById("bodyContainer");
renderAsync(
buffer, // Blob | ArrayBuffer | Uint8Array, 可以是 JSZip.loadAsync 支持的任何類型
bodyContainer, // HTMLElement 渲染文檔內(nèi)容的元素,
null, // HTMLElement, 用于呈現(xiàn)文檔樣式、數(shù)字、字體的元素。如果為 null,則將使用 bodyContainer。
this.docxOptions // 配置
)
.then(res => {
console.log("res---->", res);
})
.catch(err => {
console.log("err---->", err);
});
},
//pdf預(yù)覽
pdfPreview(data) {
// data是一個ArrayBuffer格式,也是一個buffer流的數(shù)據(jù)
console.log("pdf流", data);
const binaryData = [];
binaryData.push(data);
//獲取blob鏈接
let pdfUrl = window.URL.createObjectURL(
new Blob(binaryData, { type: "application/pdf" })
);
console.log("pdfUrl", pdfUrl);
// window.open(pdfUrl); 這種方式是直接打開新瀏覽器窗口預(yù)覽
this.pdfUrl = pdfUrl;
}
}
};
</script>
<style lang="scss" scoped>
.app-container {
.cardWhite {
display: flex;
flex-direction: column;
.topArea {
display: flex;
position: relative;
.backBox {
margin-bottom: 1rem;
img {
cursor: pointer;
}
}
.titleBox {
text-align: center;
background: #fff;
color: #000000;
position: absolute;
top: 0;
left: 50%;
width: auto;
}
}
}
}
</style>總結(jié)
到此這篇關(guān)于vue項(xiàng)目如何實(shí)現(xiàn)前端預(yù)覽word與pdf格式文件的文章就介紹到這了,更多相關(guān)vue前端預(yù)覽word與pdf格式文件內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Vue+ElementUI踩坑之動態(tài)顯示/隱藏表格的列el-table-column問題
這篇文章主要介紹了Vue+ElementUI踩坑之動態(tài)顯示/隱藏表格的列el-table-column問題,具有很好的參考價(jià)值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教2023-11-11
vue-class-setup?編寫?class?風(fēng)格組合式API
這篇文章主要為大家介紹了vue-class-setup?編寫?class?風(fēng)格組合式API,支持Vue2和Vue3,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-09-09
antdv的table因數(shù)據(jù)量過大導(dǎo)致的卡頓問題及解決
這篇文章主要介紹了antdv的table因數(shù)據(jù)量過大導(dǎo)致的卡頓問題及解決方案,具有很好的參考價(jià)值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教2023-11-11
解決vue2中使用elementUi打包報(bào)錯的問題
這篇文章主要介紹了解決vue2中使用elementUi打包報(bào)錯的問題,具有很好的參考價(jià)值,希望對大家有所幫助。一起跟隨小編過來看看吧2020-09-09
關(guān)于vue路由緩存清除在main.js中的設(shè)置
今天小編就為大家分享一篇關(guān)于vue路由緩存清除在main.js中的設(shè)置,具有很好的參考價(jià)值,希望對大家有所幫助。一起跟隨小編過來看看吧2019-11-11
Vue3 SFC 和 TSX 方式自定義組件實(shí)現(xiàn) v-model的詳細(xì)
v-model 是 vue3 中的一個內(nèi)置指令,很多表單元素都可以使用這個屬性,如 input、checkbox 等,咱可以在自定義組件中實(shí)現(xiàn) v-model,這篇文章主要介紹了Vue3 SFC 和 TSX 方式自定義組件實(shí)現(xiàn) v-model,需要的朋友可以參考下2022-10-10
Vue使用v-for數(shù)據(jù)渲染順序混亂的原因及解決方案
在 Vue.js 中,使用 v-for 指令進(jìn)行數(shù)據(jù)渲染時(shí),有時(shí)會遇到渲染順序混亂的問題,這種問題主要與 Vue 的響應(yīng)式系統(tǒng)、DOM 更新機(jī)制以及數(shù)組的變更方法有關(guān),以下是對這一現(xiàn)象的深入分析及解決方案,需要的朋友可以參考下2025-01-01
vue深拷貝的3種實(shí)現(xiàn)方式小結(jié)
當(dāng)使用同一個對象產(chǎn)生沖突時(shí),可以使用lodash包,對該對象進(jìn)行深拷貝,從而使操作的對象為不同的對象,這篇文章主要給大家介紹了關(guān)于vue深拷貝的3種實(shí)現(xiàn)方式,需要的朋友可以參考下2023-02-02

