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

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

頁(yè)面上傳word文件效果如下:

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

這里先從上傳組件頁(yè)面說起,上傳頁(yè)面組件完整代碼如下,按鈕里面v-show=“$checkPermission([‘Register_tuotpUpload’])“都是給這個(gè)按鈕設(shè)置了按鈕權(quán)限的,我們只需要關(guān)注上傳那一部分的代碼即可,我們用了el-upload組件實(shí)現(xiàn)的手動(dòng)上傳,由于需求要求只能上傳word和pdf,所以能看到屬性設(shè)置的有 accept=”.pdf, .doc, .docx”,然后不展示上傳成功的文件的列表設(shè)置的屬性有:show-file-list=“false”,而handleExceed回調(diào)函數(shù)和limit都是為了限制只能上傳一個(gè)文件,上傳前的回調(diào)鉤子函數(shù)beforeAvatarUpload里進(jìn)行了文件類型判斷與提醒,手動(dòng)上傳是通過UploadFile里進(jìn)行完成的,需要注意的是由于docx-preview這個(gè)插件只能預(yù)覽后綴為docx的word文件,如果是doc后綴格式的word文件一定要讓后端強(qiáng)制將上傳doc格式的文件改為docx格式,目前對(duì)于doc格式的word文件實(shí)現(xiàn)網(wǎng)頁(yè)在線預(yù)覽我只想到了docx-preview這個(gè)插件和這個(gè)解決辦法:
<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="請(qǐng)輸入鏈路名稱"
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="請(qǐng)選擇鏈路類型"
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="請(qǐng)選擇"
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="請(qǐng)選擇"
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="請(qǐng)輸入鏈路物理位置"
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ǐng)輸入行政區(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="請(qǐng)輸入鏈路責(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="請(qǐng)輸入鏈路責(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="請(qǐng)輸入負(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="請(qǐng)輸入鏈路IP地址"
clearable
></el-input>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="鏈路端口" prop="port">
<el-input-number
placeholder="請(qǐng)輸入鏈路端口"
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="管理頁(yè)面" prop="webUrl">
<el-input
v-model="ruleForm.webUrl"
placeholder="請(qǐng)輸入鏈路管理頁(yè)面"
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="請(qǐng)選擇電腦中拓?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">鏈路注冊(cè)</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">已注冊(cè)</el-tag>
<el-tag type="success" v-if="scope.rows.status == 0"
>未注冊(cè)</el-tag
>
<el-tag type="danger" v-if="scope.rows.status == 2"
>注冊(cè)失敗</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)"
>注冊(cè)</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>
<!-- 鏈路注冊(cè)彈窗 -->
<el-dialog
title="鏈路注冊(cè)"
: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("請(qǐng)輸入平臺(tái)IP地址");
// } else {
// let index = value.indexOf("/");
// let findHengT = value.indexOf("-");
// let findHengP = value.indexOf("——");
// if (index > -1 || findHengT > -1 || findHengP > -1) {
// callback("請(qǐng)輸入正確格式的平臺(tái)IP地址");
// } else {
// validator.IpArea(rule, value, callback);
// }
// }
if (!this.ruleForm.srcNetwork || !this.ruleForm.dstNetwork) {
callback("請(qǐng)選擇鏈路走向");
} else {
callback();
}
};
return {
ruleForm: {
name: "",
linkType: "",
srcNetwork: "",
dstNetwork: "",
physicalPosition: "",
orangeName: "",
organCode: "",
dutyPerson: "",
dutyTel: "",
dutyEmail: "",
ip: "",
port: undefined,
webUrl: ""
},
rules: {
name: [{ required: true, message: "請(qǐng)輸入鏈路名稱", trigger: "blur" }],
linkType: [
{ required: true, message: "請(qǐng)選擇鏈路類型", trigger: "blur" }
],
go: [
{
required: true,
message: "請(qǐng)選擇鏈路走向",
trigger: "blur",
validator: validateGo
}
],
physicalPosition: [
{ required: false, message: "請(qǐng)輸入鏈路物理位置", trigger: "blur" }
],
orangeName: [
{ required: true, message: "請(qǐng)輸入所屬機(jī)構(gòu)", trigger: "blur" }
],
organCode: [
{ required: true, message: "請(qǐng)輸入行政區(qū)編碼", trigger: "blur" }
],
dutyPerson: [
{ required: true, message: "請(qǐng)輸入鏈路責(zé)任人", trigger: "blur" }
],
dutyTel: [
{ required: true, message: "請(qǐng)輸入鏈路責(zé)任人電話", trigger: "blur" }
],
dutyEmail: [
{
required: false,
message: "請(qǐng)輸入負(fù)責(zé)人公安網(wǎng)郵箱",
trigger: "blur"
}
],
ip: [{ required: false, message: "請(qǐng)輸入鏈路IP地址", trigger: "blur" }],
port: [{ required: true, message: "請(qǐng)輸入鏈路端口", trigger: "blur" }],
webUrl: [
{ required: false, message: "請(qǐng)輸入鏈路管理頁(yè)面", 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: "型號(hào)",
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: "平臺(tái)名稱",
prop: "name",
type: "normal",
sortable: false
},
{
label: "平臺(tái)IP地址",
prop: "ip",
type: "normal",
sortable: false
},
{
label: "平臺(tái)端口",
prop: "port",
type: "normal",
sortable: false
},
{
label: "平臺(tái)唯一標(biāo)識(shí)",
prop: "uniquePlatformCode",
type: "normal",
sortable: false
},
{
label: "注冊(cè)時(shí)間",
prop: "lastTime",
type: "normal",
sortable: false,
width: 180
},
{
label: "注冊(cè)狀態(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();
//獲取鏈路注冊(cè)列表
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ù)覽,請(qǐng)先上傳拓?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("基本信息為空不能添加,請(qǐng)先補(bǔ)充基本信息", 6000);
}
});
},
Register_handleClose() {
this.Register_dialogFormVisible = false;
},
Register_submitForm() {
this.$refs["RegisterAdd"].submitForm();
},
//獲取鏈路注冊(cè)列表
Register_fetchData() {
this.Register_tableLoading = true;
api
.registerList({
page: 1,
page_size: 99999,
ip: ""
})
.then(res => {
console.log("注冊(cè)列表", 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個(gè)文件上傳,本次選擇了${files.length}個(gè)文件`
);
}
},
//文件上傳前的鉤子
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格式,請(qǐng)重新上傳!",
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文件失敗,請(qǐng)稍后重試!",
type: "error",
duration: 6000
});
}
})
.catch(err => {
console.log("上傳失敗2", err);
this.$message({
message: "上傳拓?fù)鋱D文件失敗,請(qǐng)稍后重試!",
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)之后,我們?cè)倏搭A(yù)覽功能。我們需求是點(diǎn)擊預(yù)覽按鈕之后跳到一個(gè)新頁(yè)面進(jìn)行預(yù)覽,我先是對(duì)文件是否為空是否沒上傳進(jìn)行了一個(gè)判斷攔截,由于預(yù)覽頁(yè)面組件與當(dāng)前頁(yè)面組件既非父子關(guān)系,又非爺孫關(guān)系,八竿子打不著的關(guān)系,我們就不能通過綁定和sessionStorage來進(jìn)行流文件的傳遞,只能在預(yù)覽頁(yè)面再發(fā)一次請(qǐng)求獲取文件流,我們可以把參數(shù)通過路由帶上,預(yù)覽按鈕對(duì)應(yīng)的方法代碼如下:
preview() {
console.log("預(yù)覽", this.fileList, this.tuopuForm);
if (!this.fileList) {
this.$message.error(
"拓?fù)鋱D文件為空不能預(yù)覽,請(qǐng)先上傳拓?fù)鋱D文件后再預(yù)覽",
6000
);
return false;
}
this.$router.push({
path: "TuotpPreview",
query: {
fileName: this.tuopuForm.fileName,
fileUrl: this.tuopuForm.fileUrl
}
});
}
再來看預(yù)覽頁(yè)面,也就是TuotpPreview.vue組件。word預(yù)覽比較簡(jiǎn)單,先通過命令cnpm i docx-preview --save安裝插件docx-preview,需要注意的是這個(gè)插件只能預(yù)覽后綴為docx的word文件,如果是doc后綴格式的word文件一定要讓后端強(qiáng)制將上傳doc格式的文件改為docx格式,然后當(dāng)前頁(yè)面組件就直接import { defaultOptions, renderAsync } from “docx-preview”;引入,最后在data里進(jìn)行docxOptions配置,然后在頁(yè)面上 要顯示的div上綁定一個(gè) 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插件對(duì)應(yīng)的方法
docxOptions: {
className: "kaimo-docx-666", // string:默認(rèn)和文檔樣式類的類名/前綴
inWrapper: true, // boolean:?jiǎn)⒂脟@文檔內(nèi)容的包裝器渲染
ignoreWidth: false, // boolean:禁用頁(yè)面的渲染寬度
ignoreHeight: false, // boolean:禁止渲染頁(yè)面高度
ignoreFonts: false, // boolean:禁用字體渲染
breakPages: true, // boolean:在分頁(yè)符上啟用分頁(yè)
ignoreLastRenderedPageBreak: true, // boolean:在 lastRenderedPageBreak 元素上禁用分頁(yè)
experimental: false, // boolean:?jiǎn)⒂脤?shí)驗(yàn)功能(制表符停止計(jì)算)
trimXmlDeclaration: true, // boolean:如果為true,解析前會(huì)從?? xml 文檔中移除 xml 聲明
useBase64URL: false, // boolean:如果為true,圖片、字體等會(huì)轉(zhuǎn)為base 64 URL,否則使用URL.createObjectURL
useMathMLPolyfill: false, // boolean:包括用于 chrome、edge 等的 MathML polyfill。
showChanges: false, // boolean:?jiǎn)⒂梦臋n更改的實(shí)驗(yàn)性渲染(插入/刪除)
debug: false // boolean:?jiǎn)⒂妙~外的日志記錄
},
pdf文件的預(yù)覽是通過獲取到blob文件流之后,直接通過window.open打開新窗口,通過瀏覽器就能預(yù)覽pdf,還有一種就是我現(xiàn)在的這種需求,要在頁(yè)面上預(yù)覽pdf,那就需要通過iframe,然后把blob流對(duì)應(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:?jiǎn)⒂脟@文檔內(nèi)容的包裝器渲染
ignoreWidth: false, // boolean:禁用頁(yè)面的渲染寬度
ignoreHeight: false, // boolean:禁止渲染頁(yè)面高度
ignoreFonts: false, // boolean:禁用字體渲染
breakPages: true, // boolean:在分頁(yè)符上啟用分頁(yè)
ignoreLastRenderedPageBreak: true, // boolean:在 lastRenderedPageBreak 元素上禁用分頁(yè)
experimental: false, // boolean:?jiǎn)⒂脤?shí)驗(yàn)功能(制表符停止計(jì)算)
trimXmlDeclaration: true, // boolean:如果為true,解析前會(huì)從?? xml 文檔中移除 xml 聲明
useBase64URL: false, // boolean:如果為true,圖片、字體等會(huì)轉(zhuǎn)為base 64 URL,否則使用URL.createObjectURL
useMathMLPolyfill: false, // boolean:包括用于 chrome、edge 等的 MathML polyfill。
showChanges: false, // boolean:?jiǎn)⒂梦臋n更改的實(shí)驗(yàn)性渲染(插入/刪除)
debug: false // boolean:?jiǎn)⒂妙~外的日志記錄
},
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("獲取文件信息失敗,請(qǐng)稍后重試", 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是一個(gè)ArrayBuffer格式,也是一個(gè)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)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
使用Vue.js實(shí)現(xiàn)一個(gè)循環(huán)倒計(jì)時(shí)功能
在Web應(yīng)用中,倒計(jì)時(shí)功能常用于各種場(chǎng)景,如活動(dòng)倒計(jì)時(shí)、定時(shí)任務(wù)提醒等,Vue.js作為一款輕量級(jí)的前端框架,提供了豐富的工具和API來實(shí)現(xiàn)這些功能,本文將詳細(xì)介紹如何使用Vue.js實(shí)現(xiàn)一個(gè)循環(huán)倒計(jì)時(shí)功能,需要的朋友可以參考下2024-09-09
vue2.0 better-scroll 實(shí)現(xiàn)移動(dòng)端滑動(dòng)的示例代碼
本篇文章主要介紹了vue2.0 better-scroll 實(shí)現(xiàn)移動(dòng)端滑動(dòng)的示例代碼,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下。2018-01-01
Vue計(jì)算屬性實(shí)現(xiàn)成績(jī)單
這篇文章主要為大家詳細(xì)介紹了Vue計(jì)算屬性實(shí)現(xiàn)成績(jī)單,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2021-08-08
vue基于vant實(shí)現(xiàn)上拉加載下拉刷新的示例代碼
普遍存在于各種app中的上拉加載下拉刷新功能,本文主要介紹了vue基于vant實(shí)現(xiàn)上拉加載下拉刷新,文中通過示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2022-01-01

