[前端] Vue封装播放器、打包、上传NPM
一、使用icomoon
1.生成和下载图标相关文件
先使用icomoon获取我们要使用的图标,例如播放、暂停、停止、全屏等图标。
icomoon网站:https://icomoon.io/app/#/select
在其中选择我们需要的图标:
然后点击右下角的 "Generate Font":
将我们图标的名字修改成自己想要的。
然后点击右下角的 "Download"。会帮我们下载一个zip压缩包。
解压,获取以下文件:
2.使用style.css
将style.css文件和fonts文件夹拷贝到项目中(路径自己决定):
在main.js中导入style.css:
import "./styles/style.css"
导入后,就可以使用图标了。
二、自定义播放器代码结构
1.基本代码结构
MyVideo.vue:
<template> <div class="video"> <video> <source src="https://video.pearvideo.com/mp4/third/20200212/cont-1651180-11487675-112807-hd.mp4"/> </video> <div class="controls"> <div class="con_left"> <span class="icon-play"></span> <span class="icon-stop"></span> <span>00:00/10:00</span> </div> <div class="con_right"> <span class="icon-volume"></span> <span class="icon-enlarge"></span> </div> </div> </div> </template> <script> export default { name: "MyVideo", } </script> <style scoped> .video { position: relative; } .video video { width: 100%; height: 100%; } .controls { width: 100%; height: 40px; position: absolute; bottom: 0; left: 0; background-color: #99a9bf; display: flex; justify-content: space-between; align-items: center; } .controls span { padding: 0 5px; color: #fff; } </style>
这是自定义播放器的基本代码结构,其中我们使用class指定了几个icomoon图标。
2.当前效果
三、实现controls中的各功能
<template> <div class="video" ref="video"> <video ref="myvideo" @canplay="getTotalTime" @timeupdate="timeUpdate"> <source :src="src"/> </video> <div class="controls"> <div class="con_left"> <span @click="togglePlay" :class="{'icon-play':isPaused,'icon-pause':!isPaused,'cursor':true}"></span> <span @click="stopPlay" class="icon-stop cursor"></span> <span>{{currentTime}}/{{totalTime}}</span> </div> <div class="con_right"> <span @click="toggleMuted" :class="{'icon-volume':!isMuted,'icon-volume-mute':isMuted,'cursor':true}"></span> <span @click="toggleFullScreen" :class="{'icon-enlarge':!isFullScreen ,'icon-shrink':isFullScreen,'cursor':true}"></span> </div> </div> </div> </template> <script> export default { name: "MyVideo", props: [ 'src' // 这里接收父组件传来的src参数,视频的url ], data() { return { // 用于存放<video>标签对象,方便调用原生API myvideo: null, video: null, // 是否暂停,用于控制播放与暂停 isPaused: true, // 播放当前时间 currentTime: "00:00", totalTime: "00:00", // 声音是否静音 isMuted: false, // 是否全屏 isFullScreen: false, } }, mounted() { // 加载完毕后,先获取<video>标签DOM对象 this.myvideo = this.$refs.myvideo this.video = this.$refs.video }, methods: { // 播放与暂停,注意,这里isPause的变化,对应图标的变化 togglePlay() { this.isPaused = !this.isPaused; if (this.isPaused) { this.myvideo.pause() } else { this.myvideo.play() } }, // 停止播放 stopPlay() { this.myvideo.pause() this.myvideo.currentTime = 0 // 停止播放了,要将播放图标从暂停切换到播放,isPaused为true的时候,图标是播放 this.isPaused = true }, // 定义一个时间处理函数,例如将100秒,处理成1:40 timeFormat(time) { let minute = Math.floor((time % 3600) / 60); // 取余 let second = Math.floor(time % 60); minute = minute < 10 ? "0" + minute : minute; second = second < 10 ? "0" + second : second; return `${minute}:${second}`; }, // 当事件oncanplay触发时,获取视频的总时间信息,然后通过timeFormat函数处理成00:00的格式,并渲染到template中 getTotalTime() { this.currentTime = this.timeFormat(this.myvideo.currentTime); this.totalTime = this.timeFormat(this.myvideo.duration); }, // 时间timeupdate触发时,更新当前播放时间 timeUpdate() { this.currentTime = this.timeFormat(this.myvideo.currentTime) }, // 声音是否静音 toggleMuted() { this.isMuted = !this.isMuted this.myvideo.muted = !this.myvideo.muted }, // 切换全屏,注意,这里进入全屏时,使用的元素是this.video,而不是this.myvideo。video是myvideo的父标签,这样控制条才能正确显示 toggleFullScreen(event) { let fullscreen = document.webkitIsFullScreen || document.fullscreen; this.isFullScreen = fullscreen if (!this.isFullScreen) { this.isFullScreen = !this.isFullScreen const inFun = this.video.requestFullscreen || this.video.webkitRequestFullScreen; inFun.call(this.video); } else { this.isFullScreen = !this.isFullScreen const exitFun = document.exitFullscreen || this.document.webkitExitFullScreen; exitFun.call(document); } } } } </script> <style scoped> .video { position: relative; } video::-webkit-media-controls { display: none !important; } .video video { width: 100%; height: 100%; } .controls { width: 100%; height: 30px; position: absolute; bottom: 0; left: 0; background-color: black; opacity: 0.5; display: flex; justify-content: space-between; align-items: center; } .controls span { padding: 0 5px; color: #fff; } .cursor { cursor: pointer; } </style>
四、打包组件
1.打包环境
由于新版本的vue-cli使用webpack模板创建的vue环境,打包一直出错,所以我们在这里选择使用webpack-simple模板创建的环境作为打包环境。
webpack模板和webpack-simple模板有一些不同,例如配置文件的结构。我们以webpack-simple模板环境为例:
2.components中的index.js
import MyVideo from './MyVideo.vue' MyVideo.install = function (Vue) { if (this.installed) return; Vue.component(MyVideo.name, MyVideo) }; // auto install if (typeof window !== 'undefined' && window.Vue) { MyVideo.install(window.Vue); } export default MyVideo
3.修改webpack.config.js配置文件
module.exports = { entry: './src/components/index.js', externals:{ vue:'vue' }, output: { path: path.resolve(__dirname, './dist'), publicPath: '/dist/', filename: 'MyVideo.js', library:'MyVideo', libraryTarget:'umd', umdNamedDefine: true }, ... ...
entry要修改为我们需要打包的组件同目录下的index.js(该文件编写参考2.节)
externals是排除不需要打包的组件,这里指定vue不打包
output设置输出目录以及输出名称为MyVideo.js
这里注意:
如果打包的组件中使用了一些特殊的文件,例如ttf字体文件等,我们需要安装对应的loader来对其进行处理,在该配置文件中需要添加对应的配置,例如:
{ test: /\.(woff2?|eot|ttf|otf)$/, loader: 'file-loader', options: { name: '[name].[ext]?[hash]' } }
4.修改package.json配置文件
{ "name": "leeoovideo123", "main": "dist/MyVideo.js", "description": "Leeoo Video Component", "version": "1.0.0", "author": "leokale", "license": "MIT", "private": false, "scripts": { "dev": "cross-env NODE_ENV=development webpack-dev-server --open --hot", "build": "cross-env NODE_ENV=production webpack --display-error-details --config webpack.config.js" }, "files": [ "dist" ], ... ...
标黄部分都很重要:
name表示上传包的名称(放在npm仓库中的名称),下载时也是指定这个名字。注意,名字中不能有大写,例如leeooPlayer就不行。
main表示上传哪个文件
private设置非私有
files表示要打包的目录,这里我们只打包了dist目录,如果该组件使用到了其他的文件,例如字体文件在assets目录中,css文件在src/styles目录中,则都需要打包进去:
"files": [ "dist", "assets", "src/styles" ],
如果文件没打包齐全,可能组件的样式,字体,图标等无法正确显示。
5.编写README
对于组件的安装和使用方法,可以写到README文件中。
README的内容会显示在npm网站中。
6.打包
配置文件修改完毕后,使用命令进行打包:
npm run build
会在dist目录中生成js文件:
至此,组件打包完毕。
五、上传到npm仓库
1.注册npm
npm网站:https://www.npmjs.com/
1)注册个人账号
2)认证邮箱(一定要去邮箱里点击链接认证)
2.上传组件
1)运行命令登录:
npm login
按提示输入npm的账号密码和邮箱。
2)在项目目录下运行命令
npm publish
上传成功后,可以在npm网站的个人packages中查看到上传成功的包。
如果上传的组件名(package.json中配置的name)与仓库中已存在的包名字相同或很像,则会提示报错,需要重新修改名称再上传。
3)删除包
npm unpublish
注意,删除包后,如果再上传同名字的包会有24小时的限制。
3.更新组件版本
只需要保证上传组件的名称一致,然后修改package.json的版本,重新打包上传即可。
六、下载和使用包
1.npm安装
npm i leeoovideo123 -S
2.cnpm安装
cnpm每10分钟从npm同步数据,所以10分钟后cnpm就可以安装我们上传的包了
cnpm i leeoovideo123 -S
3.检查包是否安装
在node_modules目录下可以找到我们安装的包:
在检查package.json:
"dependencies": { "leeoovideo123": "^1.0.0", "vue": "^2.5.2", "vue-router": "^3.0.1" },
如果没有对应的配置,可以手工添加。
4.导入和使用包
在main.js中:
import MyVideo from 'leeoovideo123' import 'leeoovideo123/src/styles/style.css' Vue.use(MyVideo)
这里注意,虽然我们上传到npm的包名是"leeoovideo123",但是组件的名称实际上是"MyVideo"。
所以,我们在使用的时候一定要导入"MyVideo"。
尽量在打包时保证组件名与包名一致,以免使用不便(可以在ReadMe中说明)。
在我们的组件App中使用:
// App.vue <template> <div id="app"> <MyVideo src="https://video.pearvideo.com/mp4/third/20200212/cont-1651180-11487675-112807-hd.mp4"></MyVideo> </div> </template>
页面效果:
(✿◠‿◠)