Vue实现在线文档预览

目录

  • 背景
  • 在线预览
  • Office文档文件在线预览
    • pdf文档预览
      • 方案一
      • 方案二
    • Word文档预览
    • Excel文档预览
    • PPT文档预览
  • 纯文本、各种代码文件预览
  • 图片文件预览
  • 视频文件预览
    • Aliplayer阿里云播放器
    • Xgplayer西瓜播放器
    • Bilibiliplayer仿哔哩哔哩弹幕播放器
  • 音频文件预览
  • 在线文档预览项目(整合)
  • 源码下载

背景

在项目开发中,遇到很多次有关文件的需求,如不同文件类型的文件上传、文件下载、文件预览。文件上传在https://qkongtao.cn/?p=1410中有相关大文件分片上传、断点续传及秒传的介绍;文件下载在https://qkongtao.cn/?p=560#h2-0的第14个方法中有下载的工具方法介绍;各种文件的预览在项目中用的也比较频繁,大多数情况下的文件预览都会用第三方的服务或者后端服务进行实现,但是也有些情况适合纯web端实现各种文件的预览,本次就记录一下使用纯web端实现各种文档文件的预览,并且全部封装成单独的组件,开箱即用。

如果使用第三方服务,有以下的方案:

  1. XDOC文档预览服务:http://view.xdocin.com/
  2. kkFileView在线文件预览:https://kkfileview.keking.cn/zh-cn/docs/home.html
  3. Microsoft在线预览api:https://view.officeapps.live.com/op/view.aspx?src= 后面拼上你的服务器word文件地址

使用第三方的服务当然效果很好,但是成本更高,实现起来也没有那么灵活。

本次实现的文档预览的类型有:docx, xlsx, pptx, pdf,以及纯文本、代码文件和各种图片、视频格式的在线预览

在线预览

纯web端文档预览项目在线地址:http://file-viewer.qkongtao.cn/

Office文档文件在线预览

Office文档文件包括常见的docx、excel、pdf三种文件的预览,当然还有PPT文件预览,但是ppt使用纯前端实现预览效果不是很好,正确的做法一般会讲ppt文件在服务端转换成PDF文件后再进行预览。
本次的文档预览使用了vue-office组件库,安装方式如下:

//docx文档预览组件
npm install @vue-office/docx//excel文档预览组件
npm install @vue-office/excel//pdf文档预览组件
npm install @vue-office/pdf

pdf文档预览

方案一

使用vue-office组件库的pdf组件
安装vue-office组件:npm install @vue-office/pdf

实现代码如下:

<template><vue-office-pdf :src="pdf" @rendered="rendered" />
</template><script>
//引入VueOfficePdf组件
import VueOfficePdf from "@vue-office/pdf";export default {components: {VueOfficePdf,},props: {pdf: {type: String,default:"http://qncdn.qkongtao.cn/lib/teamadmin/files/%E6%B7%B1%E5%9C%B3-xx-Java%E9%AB%98%E7%BA%A7.pdf",},},data() {return {};},methods: {rendered() {console.log("渲染完成");},},
};
</script>

实现效果如下:
在线预览:http://file-viewer.qkongtao.cn/pdf
20230707-142149-Cs.png

方案二

使用 vue-pdf 插件来实现
安装 vue-pdf 插件:npm install --save vue-pdf

实现代码如下:

<template><div style="background-color: #fff"><div style="margin-bottom: 15px; text-align: center"><span>当前第{{ pdfpage }}页 / 共{{ pageCount ? pageCount : 0 }}页</span><spanstyle="margin-left: 20px">前往第<el-inputv-model="num":oninput="'if(!/^[0-9]+$/.test(value)) value=value.replace(/\\D/g,\'\');if(value>' +pageCount +')value=' +pageCount +';if(value<0)value=1'"style="width: 55px; display: inline-block"@blur="goPage"/></span><el-buttontype="primary"size="small"style="margin-left: 20px"@click.stop="prevIoUsPage">上一页</el-button><el-button type="primary" size="small" @click.stop="nextPage">下一页</el-button><el-button size="mini" @click.stop="zoomA">放大</el-button><el-buttonsize="mini"style="margin-left: 5px"@click.stop="zoomB">缩小</el-button><span style="margin-left: 5px">大小 {{ parseInt(scale * 100) }}%</span></div><div><pdf:src="src":page="pdfpage":style="scaleFun":class="pageCount ? 'load' : 'load_pdf'"@num-pages="loading($event)"@page-loaded="pdfpage = $event"/><div v-if="!pageCount" class="loading"><img src="../../assets/images/loading.gif" alt=""><span>加载中...</span></div></div></div>
</template><script>
import pdf from 'vue-pdf'
export default {components: {pdf},props: {src: {type: String,require: true,default:'http://qncdn.qkongtao.cn/lib/teamadmin/files/%E6%B7%B1%E5%9C%B3-xx-Java%E9%AB%98%E7%BA%A7.pdf'}},data() {return {// PDF预览pdfpage: 1,pageCount: 0,num: 1,scale: 1 // 缩放比例}},computed: {scaleFun(index) {// 缩放var scale = this.scalereturn `width: ${scale * 100}% !important`}},mounted() {},methods: {loading(event) {this.pageCount = event},// PDF改变页数prevIoUsPage() {var p = this.pdfpagep = p > 1 ? p - 1 : this.pageCountthis.pdfpage = p},nextPage() {var p = this.pdfpagep = p < this.pageCount ? p + 1 : 1this.pdfpage = p},goPage() {this.pdfpage = parseInt(this.num)},zoomA() {this.scale += 0.1},zoomB() {this.scale -= 0.1}}
}
</script><style lang="scss" scoped>
/deep/ .el-input__inner {text-align: center;
}
.pdf {display: inline-block;width: 100%;// height: 100%;transform-origin: 0 0;
}.load_pdf {display: none !important;
}.loading {width: 100%;margin-top: 25%;margin-bottom: 20%;text-align: center;img {width: 20%;}span {display: block;text-align: center;margin-top: 30px;margin-bottom: 30px;}
}
</style>

由于实在项目中用到了,所以加了一下翻页、缩放的功能

实现效果如下:
20230707-142736-XN.png

Word文档预览

使用vue-office组件库的docx组件
安装 vue-office 插件:npm install @vue-office/docx

实现代码如下:

<template><div><vue-office-docx:src="docx"style="height: 100%; margin: 0; padding: 0"@rendered="rendered"/></div>
</template><script>
//引入VueOfficeDocx组件
import VueOfficeDocx from "@vue-office/docx";
//引入相关样式
import "@vue-office/docx/lib/index.css";export default {components: {VueOfficeDocx,},props: {docx: {type: String,default:"http://qncdn.qkongtao.cn/lib/teamadmin/files/Hadoop2.7.1%E4%BC%AA%E5%88%86%E5%B8%83%E5%BC%8F%E9%9B%86%E7%BE%A4%E5%AE%89%E8%A3%85%E6%96%87%E6%A1%A3.docx", //设置文档网络地址,可以是相对地址},},data() {return {};},methods: {rendered() {console.log("渲染完成");},},
};
</script>

实现效果如下:
在线预览:http://file-viewer.qkongtao.cn/doc

20230707-143031-oQ.png

Excel文档预览

使用vue-office组件库的excel组件
安装vue-office插件:npm install @vue-office/excel

实现代码如下:

<template><vue-office-excel:src="excel"@rendered="renderedHandler"@error="errorHandler"style="height: calc(100vh - 90px)"/>
</template><script>
//引入VueOfficeExcel组件
import VueOfficeExcel from "@vue-office/excel";
//引入相关样式
import "@vue-office/excel/lib/index.css";export default {components: {VueOfficeExcel,},props: {excel: {type: String,default:"http://qncdn.qkongtao.cn/lib/teamadmin/files/2021%E5%B1%8A%E5%85%A8%E5%9B%BD%E5%90%84%E5%9C%B0%E6%B4%BE%E9%81%A3%E5%9C%B0%E5%9D%80.xlsx", //设置文档地址},},data() {return {};},methods: {renderedHandler() {console.log("渲染完成");},errorHandler() {console.log("渲染失败");},},
};
</script>

实现代码如下:
在线预览:http://file-viewer.qkongtao.cn/excel

20230707-143439-Yq.png

PPT文档预览

PPT文档预览纯前端实现起来比较困难,效果也不怎么好,建议可以先在服务端转换成PDF文档,使用PDF文档预览的效果比较好。
纯web实现方案:
需要安装以下插件:

"core-js": "^3.3.2",
"d3": "^3.5.17",
"dimple": "git+https://gitee.com/mirrors/dimple.git#2.3.0",
"jszip": "^3.10.0",

具体实现代码直接查看gitee:https://gitee.com/qkongtao/document-preview-project/tree/master/src/components/pptx

实现效果如下:
20230707-144553-lB.png

可以看到很多图片样式信息都丢失了,所以还是直接使用第三方的

可以尝试XDOC文档的:https://view.xdocin.com/view?src=https://upyun.qkongtao.cn/others/document/C006.pptx
他的实现方案是后台转成PDF然后再预览。

纯文本、各种代码文件预览

文本文件预览使用了vue-codemirror插件

  • 实现的方法也很简单,判断上传的文件时文本或者代码文件后,将其内容文本读取出来,然后放到codemirror,并且设置对应的代码高亮的mode。
  • codemirror有非常多的代码主题,高亮的模式也不一样。
  • 本次实现至此的文本有:json,java,sql,js,css,xml,html,yaml,md,py,txt。
  • codemirror插件中其实还有许多代码格式的mode,当设置对应代码的mode的时候,改代码类型的关键字就会高亮,并且在编写的时候会有关键字代码的提示。

安装vue-codemirror插件:npm install vue-codemirror@4.0.6 --save
在main.js中引入插件:

// 引入jshint用于实现js自动补全提示
import jshint from "jshint";
window.JSHINT = jshint.JSHINT;
// 引入代码编辑器
import {codemirror
} from "vue-codemirror";
import "codemirror/lib/codemirror.css";
Vue.use(codemirror);

实现代码如下:

  1. Codemirror.vue 编辑器组件
<template><codemirrorref="myCm":value="value":options="cmOptions"@changes="onCmCodeChanges"@blur="onCmBlur"@keydown.native="onKeyDown"@mousedown.native="onMouseDown"@paste.native="OnPaste"></codemirror>
</template>
<script>
import { codemirror } from "vue-codemirror";import "codemirror/mode/clike/clike";
import "codemirror/theme/blackboard.css";
import "codemirror/mode/javascript/javascript.js";
import "codemirror/mode/xml/xml.js";
import "codemirror/mode/htmlmixed/htmlmixed.js";
import "codemirror/mode/css/css.js";
import "codemirror/mode/yaml/yaml.js";
import "codemirror/mode/sql/sql.js";
import "codemirror/mode/python/python.js";
import "codemirror/mode/markdown/markdown.js";
import "codemirror/addon/hint/show-hint.css";
import "codemirror/addon/hint/show-hint.js";
import "codemirror/addon/hint/javascript-hint.js";
import "codemirror/addon/hint/xml-hint.js";
import "codemirror/addon/hint/css-hint.js";
import "codemirror/addon/hint/html-hint.js";
import "codemirror/addon/hint/sql-hint.js";
import "codemirror/addon/hint/anyword-hint.js";
import "codemirror/addon/lint/lint.css";
import "codemirror/addon/lint/lint.js";
import "codemirror/addon/lint/json-lint";
require("script-loader!jsonlint");
import "codemirror/addon/lint/javascript-lint.js";
import "codemirror/addon/fold/foldcode.js";
import "codemirror/addon/fold/foldgutter.js";
import "codemirror/addon/fold/foldgutter.css";
import "codemirror/addon/fold/brace-fold.js";
import "codemirror/addon/fold/xml-fold.js";
import "codemirror/addon/fold/comment-fold.js";
import "codemirror/addon/fold/markdown-fold.js";
import "codemirror/addon/fold/indent-fold.js";
import "codemirror/addon/edit/closebrackets.js";
import "codemirror/addon/edit/closetag.js";
import "codemirror/addon/edit/matchtags.js";
import "codemirror/addon/edit/matchbrackets.js";
import "codemirror/addon/selection/active-line.js";
import "codemirror/addon/search/jump-to-line.js";
import "codemirror/addon/dialog/dialog.js";
import "codemirror/addon/dialog/dialog.css";
import "codemirror/addon/search/searchcursor.js";
import "codemirror/addon/search/search.js";
import "codemirror/addon/display/autorefresh.js";
import "codemirror/addon/selection/mark-selection.js";
import "codemirror/addon/search/match-highlighter.js";
export default {components: {codemirror,},props: ["cmTheme", "cmMode", "autoFormatJson", "jsonIndentation", "value"],data() {return {editorValue: "",cmOptions: {theme:!this.cmTheme || this.cmTheme == "default"? "blackboard": this.cmTheme,mode:!this.cmMode || this.cmMode == "default"? "application/json": this.cmMode,extraKeys: {Tab: "autocomplete","Shift-Alt-F": () => {try {if (this.cmOptions.mode == "application/json" && this.value) {this.editorValue = this.formatStrInJson(this.value);}} catch (e) {this.$message.error("格式化代码出错:" + e.toString());}},},lineWrapping: true, //代码折叠lineNumbers: true, //是否显示行号autofocus: true,smartIndent: 4, // 自动缩进indentUnit: 4, //缩进单位tabSize: 4, //tab字符的宽度autocorrect: true, //自动更正spellcheck: true, //拼写检查lint: true,gutters: ["CodeMirror-lint-markers", //代码错误检测"CodeMirror-linenumbers","CodeMirror-foldgutter", //展开收起],foldGutter: true,matchTags: { bothTags: true },matchBrackets: true,styleActiveLine: true,autoRefresh: true,highlightSelectionMatches: {//显示当前所选单词minChars: 2,style: "matchhighlight",showToken: true,},styleSelectedText: true,enableAutoFormatJson:this.autoFormatJson == null ? true : this.autoFormatJson,defaultJsonIndentation:!this.jsonIndentation || typeof this.jsonIndentation != typeof 1? 2: this.jsonIndentation,},enableAutoFormatJson:this.autoFormatJson == null ? true : this.autoFormatJson,defaultJsonIndentation:!this.jsonIndentation || typeof this.jsonIndentation != typeof 1? 2: this.jsonIndentation,};},watch: {cmTheme: function (newValue, oldValue) {try {let theme = this.cmTheme == "default" ? "blackboard" : this.cmTheme;require("codemirror/theme/" + theme + ".css");this.cmOptions.theme = theme;this.resetLint();} catch (e) {this.$message.error("切换编辑器主题出错:" + e.toString());}},cmMode: function (newValue, oldValue) {this.$set(this.cmOptions, "mode", this.cmMode);this.resetLint();this.resetFoldGutter();},},methods: {resetLint() {if (!this.$refs.myCm.codemirror.getValue()) {this.$nextTick(() => {this.$refs.myCm.codemirror.setOption("lint", false);});return;}this.$refs.myCm.codemirror.setOption("lint", false);this.$nextTick(() => {this.$refs.myCm.codemirror.setOption("lint", true);});},resetFoldGutter() {this.$refs.myCm.codemirror.setOption("foldGutter", false);this.$nextTick(() => {this.$refs.myCm.codemirror.setOption("foldGutter", true);});},// 黏贴事件处理函数OnPaste(event) {if (this.cmOptions.mode == "application/json") {try {this.editorValue = this.formatStrInJson(this.value);} catch (e) {// 啥都不做}}},// 失去焦点时处理函数onCmBlur(cm, event) {try {let editorValue = cm.getValue();if (this.cmOptions.mode == "application/json" && editorValue) {if (!this.enableAutoFormatJson) {return;}this.editorValue = this.formatStrInJson(editorValue);}} catch (e) {// 啥也不做}},// 按下键盘事件处理函数onKeyDown(event) {const keyCode = event.keyCode || event.which || event.charCode;const keyCombination = event.ctrlKey || event.altKey || event.metaKey;if (!keyCombination && keyCode > 64 && keyCode < 123) {this.$refs.myCm.codemirror.showHint({ completeSingle: false });}},// 按下鼠标时事件处理函数onMouseDown(event) {this.$refs.myCm.codemirror.closeHint();},onCmCodeChanges(cm, changes) {this.editorValue = cm.getValue();this.resetLint();this.$emit("onChangeCode", cm.getValue());},// 格式化字符串为json格式字符串formatStrInJson(strValue) {return JSON.stringify(JSON.parse(strValue),null,this.defaultJsonIndentation);},},created() {try {if (!this.value) {this.cmOptions.lint = false;return;}if (this.cmOptions.mode == "application/json") {if (!this.enableAutoFormatJson) {return;}this.editorValue = this.formatStrInJson(this.value);}} catch (e) {// console.log("初始化codemirror出错:" + e);}},
};
</script>
<style scope>
/* 选中背景颜色 */
.CodeMirror-selected {background-color: #3b3c37 !important;
}
/* 选中字体 */
.CodeMirror-selectedtext {/* color: white !important; */
}.cm-matchhighlight {/* background-color: #ae00ae; */
}
</style>
  1. index.vue 编辑器调用组件
<template><div class="code-mirror-div"><!-- <h2 style="text-align: center">代码编辑器</h2> --><div class="tool-bar"><span>请选择主题:</span><el-selectv-model="cmTheme"placeholder="请选择"size="small"style="width: 150px; margin-left: 10px"><el-optionv-for="item in cmThemeOptions":key="item":label="item":value="item"></el-option></el-select><span style="margin-left: 30px">请选择编辑模式:</span><el-selectv-model="cmEditorMode"placeholder="请选择"size="small"style="width: 150px; margin-left: 10px"@change="onEditorModeChange"><el-optionv-for="item in cmEditorModeOptions":key="item":label="item":value="item"></el-option></el-select><span style="margin-left: 30px">字体大小:</span><el-selectv-model="cmEditorSize"placeholder="请选择"size="small"style="width: 150px; margin-left: 10px"@change="onEditorSizeChange"><el-optionv-for="item in cmEditorSizeOptions":key="item":label="item":value="item"></el-option></el-select><el-buttontype="primary"size="small"style="margin-left: 30px"@click="jsonFormatter"v-if="cmEditorMode == 'json'">格式化json</el-button><el-buttontype="primary"size="small"style="margin-left: 30px"@click="jsonPress"v-if="cmEditorMode == 'json'">压缩json</el-button></div><Codemirrorref="cmEditor":cmTheme="cmTheme":cmMode="cmMode":autoFormatJson="autoFormatJson":jsonIndentation="jsonIndentation":value="codeValue"@onChangeCode="onChangeCode"></Codemirror></div>
</template>
<script>
import Codemirror from "./Codemirror.vue";
export default {components: {Codemirror,},props: {initCodeValue: {type: String,default:'{"canvasStyleData":{"width":1280,"height":720,"scale":100,"color":"#000","opacity":1,"background":"#fff","fontSize":14,"backgroundColor":"rgba(232, 244, 200, 1)"}}', //代码},initEditorMode: {type: String,default: "json", // 编辑模式},},data() {return {cmTheme: "default", // codeMirror主题// codeMirror主题选项cmEditorSizeOptions: ["10","12","14","16","18","20","24","28","32",],cmThemeOptions: ["default","idea","3024-day","3024-night","abcdef","ambiance","ayu-dark","ayu-mirage","base16-dark","base16-light","bespin","blackboard","cobalt","colorforth","darcula","dracula","duotone-dark","duotone-light","eclipse","elegant","erlang-dark","gruvbox-dark","hopscotch","icecoder","isotope","lesser-dark","liquibyte","lucario","material","material-darker","material-palenight","material-ocean","mbo","mdn-like","midnight","monokai","moxer","neat","neo","night","nord","oceanic-next","panda-syntax","paraiso-dark","paraiso-light","pastel-on-dark","railscasts","rubyblue","seti","shadowfox","solarized dark","solarized light","the-matrix","tomorrow-night-bright","tomorrow-night-eighties","ttcn","twilight","vibrant-ink","xq-dark","xq-light","yeti","yonce","zenburn",],// 编辑模式选项cmEditorModeOptions: ["json","java","sql","js","css","xml","html","yaml","md","py","txt",],cmEditorMode: this.initEditorMode, // 编辑模式cmMode: "application/json", //codeMirror模式jsonIndentation: 2, // json编辑模式下,json格式化缩进 支持字符或数字,最大不超过10,默认缩进2个空格autoFormatJson: true, // json编辑模式下,输入框失去焦点时是否自动格式化,true 开启, false 关闭,cmEditorSize: "16",codeValue: this.initCodeValue,};},mounted() {this.onEditorModeChange(this.initEditorMode);var sd = document.getElementsByClassName("CodeMirror");sd[0].style.fontSize = this.cmEditorSize + "px";},methods: {// 切换编辑模式事件处理函数onEditorModeChange(value) {switch (value) {case "json":this.cmMode = "application/json";break;case "java":this.cmMode = "text/x-java";break;case "sql":this.cmMode = "sql";break;case "js":this.cmMode = "javascript";break;case "xml":this.cmMode = "xml";break;case "css":this.cmMode = "css";break;case "html":this.cmMode = "htmlmixed";break;case "yaml":this.cmMode = "yaml";break;case "md":this.cmMode = "markdown";break;case "txt":this.cmMode = "markdown";break;case "py":this.cmMode = "python";break;default:this.cmMode = "application/json";}},//代码修改changeCode(value) {this.codeValue = value;},// 选择字体大小onEditorSizeChange() {var sd = document.getElementsByClassName("CodeMirror");sd[0].style.fontSize = this.cmEditorSize + "px";},// 获取代码onChangeCode(code) {this.codeValue = code;},// 格式化字符串为json格式字符串jsonFormatter() {try {this.codeValue = JSON.stringify(JSON.parse(this.codeValue), null, "\t");} catch {alert("json代码有误");}},// 压缩jsonjsonPress() {try {this.codeValue = JSON.stringify(JSON.parse(this.codeValue));} catch {alert("json代码有误");}},},
};
</script>
<style scope>
.CodeMirror {position: absolute;top: 0px;left: 2px;right: 5px;bottom: 0px;padding: 2px;height: calc(100vh - 170px);margin-bottom: 50px;
}
.code-mirror-div {position: absolute;top: 0px;left: 2px;right: 5px;bottom: 0px;padding: 2px;
}
.tool-bar {margin: -50px 2px 0px 20px;
}
</style>

在调用编辑器的插件里面加入了一些小功能:

  1. 选择编辑器主题
  2. 编辑代码的模式
  3. 设置代码字体大小
  4. 代码为json文本的时候,可以对代码进行压缩和格式化

实现效果如下:
在线预览:http://file-viewer.qkongtao.cn/code
20230707-151406-3W.png

图片文件预览

图片文件预览可以直接使用img标签,或者用UI库的图片标签,如 el-image等,但是这种使用起来功能没有那么多,并且灵活性也不是很高,这次实现图片预览使用了v-viewer插件。

安装插件:npm install v-viewer --save
在main.js中挂载插件

import VueViewer from 'v-viewer';
import 'viewerjs/dist/viewer.css'Vue.use(VueViewer, {defaultOptions: {// 自定义默认配置zIndex: 9999,inline: false, // 默认值:false。启用内联模式。button: true, // 右上角关闭按钮navbar: false, // 指定导航栏(图片组)的可见性。title: true, //指定标题的可见性和内容toolbar: true, // 指定工具栏及其按钮的可见性和布局tooltip: true, //放大或缩小时显示带有图像比率(百分比)的工具提示。movable: true, // 启用以移动图像。zoomable: true, // 启用以缩放图像。rotatable: true, // 启用以旋转图像scalable: true, // 用以反转图像。transition: false, // 为某些特殊元素启用CSS3转换。fullscreen: false, // 启用以在播放时请求全屏。keyboard: true, //启用键盘支持。url: 'src', //默认值:"src"。定义获取原始图像URL以供查看的位置。},
});

功能可以自己选择开关:
在这里插入图片描述

图片预览组件实现代码如下:

<template><div><viewer><img alt="图片" :src="src" class="image" /></viewer></div>
</template><script>
export default {props: {src: {type: String,default: "http://upyun.qkongtao.cn/chevereto/2022/08/30/onepiece.png",},},data() {return {};},
};
</script><style scoped>
.image {display: block;width: auto;width: 600px;margin: 100px auto;
}
</style>

实现效果如下:
在线预览(可点击):http://file-viewer.qkongtao.cn/img
20230707-154854-SM.png

视频文件预览

本次视频文件预览尝试使用了三种插件实现:

  1. Aliplayer:https://player.alicdn.com/aliplayer/presentation/index.html?type=memoryPlay
  2. Xgplayer:https://h5player.bytedance.com/guide/
  3. Bilibiliplayer:https://qkongtao.cn/?p=1481

这三种开源的播放器功能比较全,样式也比较好看,可以适用于大部分视频播放的场景,可以真正的告别video标签了。
本次实现播放器父组件向子组件传参结构示例:

video: {poster:"https://upyun.qkongtao.cn/others/video/%E8%8D%89%E5%B8%BD%E4%B8%80%E4%BC%99%E6%82%AC%E8%B5%8F%E4%BB%A4%E4%BC%A0%E9%81%8D%E5%85%A8%E4%B8%96%E7%95%8C.mp4.jpg",thumbnailUrl:"https://upyun.qkongtao.cn/others/video/%E8%8D%89%E5%B8%BD%E4%B8%80%E4%BC%99%E6%82%AC%E8%B5%8F%E4%BB%A4%E4%BC%A0%E9%81%8D%E5%85%A8%E4%B8%96%E7%95%8C.mp4.vtx",src: "https://upyun.qkongtao.cn/AList/%E8%8D%89%E5%B8%BD%E4%B8%80%E4%BC%99%E6%82%AC%E8%B5%8F%E4%BB%A4%E4%BC%A0%E9%81%8D%E5%85%A8%E4%B8%96%E7%95%8C.mp4",},

Aliplayer阿里云播放器

官方文档:https://player.alicdn.com/aliplayer/presentation/index.html?type=memoryPlay

安装方法:在项目中引入阿里云播放器

<!-- 引用阿里云播放器 --><link rel="stylesheet" href="https://g.alicdn.com/de/prismplayer/2.8.2/skins/default/aliplayer-min.css" /><script charset="utf-8" type="text/javascript" src="https://g.alicdn.com/de/prismplayer/2.8.2/aliplayer-min.js">

封装组件实现代码:

<template><!--播放器--><divclass="prism-player"id="J_prismPlayer"style="margin-left: auto; margin-right: auto"></div>
</template>
<script>
export default {props: {//组件需要的参数video: Object,},data() {return {};},created() {//console.log("组件成功")},mounted() {this.initPlayer();},methods: {initPlayer() {//console.log(this.video)var player = new Aliplayer({id: "J_prismPlayer", // id选择器source: this.video.src, //视频地址width: "800px",height: "600px",//cover: 'http://images.qkongtao.cn/images/2021/08/15/t012cde4a5058c156b7.jpg', // 封面qualitySort: "asc", // 清晰度排序mediaType: "video", // 返回音频还是视频autoplay: false, // 自动播放isLive: false, // 直播rePlay: false, // 循环播preload: true,controlBarVisibility: "hover", // 控制条的显示方式:鼠标悬停useH5Prism: true, // 播放器类型:html5thumbnailUrl: this.video.thumbnailUrl,// 允许匿名跨域访问属性extraInfo: {crossOrigin: "anonymous",},skinLayout: [{ name: "bigPlayButton", align: "blabs", x: 30, y: 80 },{ name: "H5Loading", align: "cc" },{ name: "errorDisplay", align: "tlabs", x: 0, y: 0 },{ name: "infoDisplay" },{ name: "tooltip", align: "blabs", x: 0, y: 56 },{ name: "thumbnail" },{name: "controlBar",align: "blabs",x: 0,y: 0,children: [{ name: "progress", align: "blabs", x: 0, y: 44 },{ name: "playButton", align: "tl", x: 15, y: 12 },{ name: "timeDisplay", align: "tl", x: 10, y: 7 },{ name: "fullScreenButton", align: "tr", x: 10, y: 12 },// { name: "subtitle", align: "tr", x: 15, y: 12 },// { name: "setting", align: "tr", x: 15, y: 12 },{ name: "volume", align: "tr", x: 5, y: 10 },{ name: "snapshot", align: "tr", x: 5, y: 9 },],},],},function (player) {console.log("播放器创建成功");});// 绑定鼠标事件(暂停、播放)var _video = document.querySelector("video");_video.addEventListener("click", play);player.on("play", function (e) {_video.removeEventListener("click", play);_video.addEventListener("click", pause);});player.on("pause", function (e) {_video.removeEventListener("click", pause);_video.addEventListener("click", play);});function play() {if (player) player.play();document.getElementsByClassName("prism-big-play-btn")[0].style.display ="none";}function pause() {if (player) player.pause();document.getElementsByClassName("prism-big-play-btn")[0].style.display ="block";}/* h5截图按钮, 截图成功回调 */player.on("snapshoted", function (data) {var pictureData = data.paramData.base64;var downloadElement = document.createElement("a");downloadElement.setAttribute("href", pictureData);var fileName = "Aliplayer" + Date.now() + ".png";downloadElement.setAttribute("download", fileName);downloadElement.click();pictureData = null;});},},
};
</script><style scoped>
.prism-player {margin: 0;padding: 0;
}

实现效果如下:
20230707-160650-uh.png

Xgplayer西瓜播放器

官方文档:https://h5player.bytedance.com/guide/

安装方法:npm install xgplayer --save

封装组件实现代码:

<template><div><div id="myPlayer"></div></div>
</template><script>
import Player from "xgplayer";
import "xgplayer/dist/index.min.css";
import Danmu from "xgplayer/es/plugins/danmu";
import "xgplayer/es/plugins/danmu/index.css";
export default {props: {//组件需要的参数video: Object,},data() {return {player: null,};},mounted() {this.initXgplayer();},methods: {initXgplayer() {const config = {// 播放器IDid: "myPlayer",width: "800px",height: "500px",// 视频链接url: this.video.src,playsinline: true,// 自动播放autoplay: false,// 视频封面链接poster: this.video.poster,// 播放器插件plugins: [Danmu],// 流式布局fluid: true,// 初始音量volume: 1,// 倍数配置playbackRate: [0.5, 1, 1.5, 2],// 缩略图集thumbnail: {pic_num: 44,width: 160,height: 90,col: 10,row: 10,urls: [this.video.thumbnailUrl],},// 显示下载按钮download: true,// 显示截图按钮screenShot: true,// 防止canvas toDataURL跨域画布污染videoAttributes: {crossOrigin: "anonymous",},/***********************  弹幕配置start ***********************/danmu: {// 预设弹幕内容comments: [{duration: 15000,id: "2",start: 3000,txt: "长弹幕长弹幕长弹幕",mode: "top",style: {//弹幕自定义样式color: "#ff9500", //例:'#ff9500',"font-size": "30px", // 例:'20px',padding: "2px 11px", //例: 2px 11px',},},{duration: 15000,id: "3",start: 4000,txt: "长弹幕长弹幕长弹幕",mode: "bottom",style: {//弹幕自定义样式color: "#ff9500", //例:'#ff9500',"font-size": "40px", // 例:'20px',padding: "2px 11px", //例: 2px 11px',},},{duration: 15000,id: "4",start: 5000,txt: "长弹幕长弹幕长弹幕",mode: "scroll",style: {//弹幕自定义样式color: "#de1c31", //例:'#ff9500',"font-size": "48px", // 例:'20px',padding: "2px 11px", //例: 2px 11px',},},{duration: 15000,id: "5",start: 8000,txt: "长弹幕长弹幕长弹幕",mode: "scroll",style: {//弹幕自定义样式color: "#813c85", //例:'#ff9500',"font-size": "30px", // 例:'20px',padding: "2px 11px", //例: 2px 11px',},},],area: {start: 0,end: 1,},// 不使用默认提供弹幕开关closeDefaultBtn: false,// 关闭弹幕初始化defaultOff: true,// 弹幕控制面板panel: false,},/***********************  弹幕配置end ***********************/};this.player = new Player(config);},},
};
</script><style scoped>
</style>

实现效果如下:
20230707-160849-sZ.png

Bilibiliplayer仿哔哩哔哩弹幕播放器

参考文档:https://qkongtao.cn/?p=1481
具体的实现方法可以参考上面的文章,项目中直接使用iframe嵌入播放器。

封装组件实现代码:

<template><div><iframe:src="playerApi + src"allowfullscreen="allowfullscreen"mozallowfullscreen="mozallowfullscreen"msallowfullscreen="msallowfullscreen"oallowfullscreen="oallowfullscreen"webkitallowfullscreen="webkitallowfullscreen"width="800px"height="500px"frameborder="0"style="player"></iframe></div>
</template><script>
export default {props: {//组件需要的参数video: Object,},data() {return {playerApi: "http://code.qkongtao.cn/video/player/?url=",src: "",};},mounted() {this.src = this.video.src;},methods: {},
};
</script><style scoped>
.player {margin-top: 30px;
}
</style>

实现效果如下:
在这里插入图片描述

音频文件预览

音频文件预览的使用场景相对比较少,这里就简单的集成一下APlayer插件实现一下友好的音乐播放器。

APlayer官方文档:https://aplayer.js.org/#/zh-Hans/?id=%E5%AE%89%E8%A3%85

安装方法:npm install aplayer --save

封装组件实现代码

<template><div><div id="aplayer" class="aplayer"></div></div>
</template><script>
import APlayer from "aplayer";
import "aplayer/dist/APlayer.min.css";export default {props: {musicList: {type: Array,default: [],},},data() {return {myAPlayer: null,};},mounted() {this.initAPlayer();},methods: {initAPlayer() {const options = {container: document.getElementById("aplayer"),theme: "#e9e9e9",audio: this.musicList,};const ap = new APlayer(options);this.myAPlayer = ap;},},
};
</script><style scoped>
</style>

调用组件传入参数示例:

musicList: [{name: "新时代",artist: "Ado",url: "https://upyun.qkongtao.cn/wordpress/files/%E6%96%B0%E6%97%B6%E4%BB%A3.mp3",cover:"https://qkongtao.cn/file/music/pic/%E6%96%B0%E6%97%B6%E4%BB%A3.png",},{name: "偏爱",artist: "张芸京",url: "https://qkongtao.cn/file/music/%E5%81%8F%E7%88%B1-%E5%BC%A0%E8%8A%B8%E4%BA%AC.mp3",cover:"https://qkongtao.cn/file/music/pic/我们的爱我不放手-张芸京.jpg",},{name: "残酷月光",artist: "林宥嘉",url: "https://qkongtao.cn/file/music/%E6%AE%8B%E9%85%B7%E6%9C%88%E5%85%89%20%E6%9E%97%E5%AE%A5%E5%98%89.mp3",cover:"https://qkongtao.cn/file/music/pic/%E6%AE%8B%E9%85%B7%E6%9C%88%E5%85%89.png",},],

实现效果如下:
在线预览:http://file-viewer.qkongtao.cn/music
20230707-162017-b7.png

可以根据官方文档设置播放器场景样式。

在线文档预览项目(整合)

上述的组件是本项目主要实现的功能,最后我将组件进行了整合一下,封装成一个文件上传、下载、预览的demo。
在线预览地址:http://file-viewer.qkongtao.cn/
20230707-162545-zZ.png

源码下载

https://gitee.com/qkongtao/document-preview-project

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/12976.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

POE级联蓝牙定位系统方案_蓝牙信标,蓝牙网关,级联蓝牙网关

近年来,随着新能源行业的快速发展,在化工厂,核电厂以及电力电厂等企业,对人员定位,人员导航,资产定位,生命体征监测的需求越来越大。传统的蓝牙室内定位方案中蓝牙信标为锂亚电池供电,需定期更换电池且有安全隐患,为更好的服务有蓝牙定位导航,被动人员定位,生命体征…

MySQL之概述、安装和使用(一)

一、概述 关系数据库概述&#xff1a; https://blog.csdn.net/qq_21370419/article/details/128568920 二、数据库的安装 参考我的两篇博客&#xff1a; win10 安装mysql 5.6.36版本_windows 安装mysql5.6_人……杰的博客-CSDN博客 wind 10 安装 mysql 8.0_人……杰的博客…

50从零开始学Java之万类之王Object是怎么回事?

作者&#xff1a;孙玉昌&#xff0c;昵称【一一哥】&#xff0c;另外【壹壹哥】也是我哦 千锋教育高级教研员、CSDN博客专家、万粉博主、阿里云专家博主、掘金优质作者 前言 在前面的文章中&#xff0c;壹哥跟大家说过&#xff0c;Java是面向对象的编程语言&#xff0c;而在面…

IDEA+SpringBoot+mybatis+SSM+layui+Mysql客户管理系统源码

IDEASpringBootmybatisSSMlayuiMysql客户管理系统 一、系统介绍1.环境配置 二、系统展示1. 管理员登录2.修改密码3.客户管理4.添加客户5.充值记录管理6.消费记录管理7.客户类型8.添加客户类型 三、部分代码UserMapper.javaLoginController.javaUser.java 四、其他获取源码 一、…

自动化测试工具——Fitnesse

1 介绍 是一个完全集成的独立wiki和验收测试框架。 1.1、协作工具 由于FitNesse是一个wiki web服务器&#xff0c;它的入门和学习曲线非常低&#xff0c;这使得它成为一个优秀的工具&#xff0c;可以与业务涉众进行协作。 1.2、测试工具 FitNesse中创建的wiki页面作为测试…

17款奔驰S400加装原厂无钥匙进入系统,提升您的便利性

奔驰无钥匙进入功能&#xff0c;只要身上装着车钥匙进入车内&#xff0c;车辆就能感应到钥匙的存在&#xff0c;这时只需按下启动键就可启动车辆了 奔驰无钥匙进入功能主要有两大使用体验&#xff0c;首先就是要注意主驾驶位车门的有效检测距离不小于1.5m&#xff0c;其他门钥匙…

Elasticsearch入门

部署单点es 1创建网络 、加载镜像 docker network create es-netdocker pull elasticsearch2安装ES docker run -d \--name es \-e "ES_JAVA_OPTS-Xmx512m -Xmx512m" \-e "discovery.typesingle-node" \-v es-data:/usr/share/elasticsearch/data \-v es-…

运输层:TCP的运输连接管理

1.运输层&#xff1a;TCP的运输连接管理 笔记来源&#xff1a; 湖科大教书匠&#xff1a;TCP的连接建立 湖科大教书匠&#xff1a;TCP的连接释放 声明&#xff1a;该学习笔记来自湖科大教书匠&#xff0c;笔记仅做学习参考 TCP是面向连接的协议&#xff0c;它基于运输连接来传…

Web3 通过truffle 脚本进行智能合约测试

上文 Web3 处理智能合约部署到本地区块链&#xff0c;并在本地进行测试中 我们讲解了部署智能合约 然后在终端测试的方法 但上文那种终端测试 其实并不保险 而且也比较不专业 对于这个 有一个mocha测试 这是基于node部署环境的一种环境测试 但是这个需要一定的基础 大家可以专门…

数据结构-ArrayList

目录 线性表 顺序表 ArrayList ArrayList的使用 ArrayList的构造方法 ArrayList的常用方法 ArrayList的遍历 实现简单的ArrayList 洗牌算法 删除公共字符串问题 杨辉三角 线性表 线性表是n个具有相同特性的数据元素的有限序列.线性表是一种在实际中广泛使用的数据结…

kubectl详解之声明式管理方法

目录 一、声明式管理方法二、资源配置清单的管理2.1 查看资源配置清单2.1 修改资源配置清单并应用2.1.1 离线修改2.1.2 在线修改 一、声明式管理方法 适合于对资源的修改操作 声明式资源管理方法依赖于资源配置清单文件对资源进行管理 资源配置清单文件有两种格式&#xff1a;…

部署LVS-DR群集

目录 1、LVS-DR数据包流向分析 2、LVS-DR中ARP问题 3、LVS-DR特性 LVS-DR的优缺点 1、LVS-DR数据包流向分析 (1)客户端发送请求到 Director Server (负载均器)&#xff0c;请求的数据报文(源 IP 是CIP&#xff0c;目标 IP 是 VIP) 到达内核空间。 (2) Director Server 利 …