├── .babelrc ├── .gitignore ├── README.md ├── _config.yml ├── es5 ├── config.rb ├── css │ └── Dvideo.css ├── index.html ├── js │ └── Dvideo.js └── sass │ ├── Dvideo.scss │ └── Dvideo │ ├── _content.scss │ ├── _ctrl.scss │ ├── _global.scss │ └── _type.scss ├── index.html ├── lib ├── d-video.css ├── d-video.js └── index.html ├── package-lock.json ├── package.json ├── src ├── commonjs │ ├── dom.js │ ├── storage.js │ └── utils.js ├── index.js ├── script │ └── Dvideo.js └── scss │ ├── Dvideo.scss │ ├── Dvideo │ ├── _content.scss │ ├── _ctrl.scss │ ├── _global.scss │ └── _type.scss │ └── common │ ├── _index.scss │ ├── _mixin.scss │ ├── _utils.scss │ └── _variable.scss ├── static └── font-icon │ ├── Read Me.txt │ ├── demo-files │ ├── demo.css │ └── demo.js │ ├── demo.html │ ├── fonts │ ├── icomoon.eot │ ├── icomoon.svg │ ├── icomoon.ttf │ └── icomoon.woff │ ├── selection.json │ └── style.css ├── tea.yaml └── webpack.config.js /.babelrc: -------------------------------------------------------------------------------- 1 | { "presets": [ "es2015" ] } -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | node_modules/ 3 | dist/ 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | .sass-cache/ 8 | # Editor directories and files 9 | .idea 10 | *.suo 11 | *.ntvs* 12 | *.njsproj 13 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | # d-video 3 | 基于原生js的 video 插件  d-video 4 | 5 | ![](https://img.shields.io/badge/javascript-4EDD96.svg) 6 | 7 | 支持音量  语速  清晰度 ie全屏等一系列操作  兼容IE 9 + 8 | 9 | #### 项目运行 10 | ✅ clone 项目之后在项目根目录执行 11 | 安装依赖: 12 | 13 |
 14 |   npm install
 15 | 
16 | 17 | ⚠️ 注意: 由于webpack使用的是4.0以上的版本,extract-text-webpack-plugin在安装时需要单独执行,Vue下需要配置scss的sass-loader  安装sass-loader和node-sass 18 |
 19 |   npm install extract-text-webpack-plugin@next
 20 | 
21 | 来安装 22 | 否则项目安装之后执行 npm run dev 会报错 23 | 开启服务: 24 | 25 |
 26 | npm run dev
 27 | 
28 | 29 | 编译版本 30 | 31 |
 32 |   npm run build
 33 | 
34 | 35 | 原先的es5版本也会同时更新  后续会放在这个项目单独的文件下 36 | 37 | #### 初始化 38 |
 39 | var video = new Dvideo ({
 40 | 	ele: '#testVideo',
 41 | 	title: 'Pneumatic Tokyo - EnV',
 42 | 	nextVideoExtend: function () {
 43 | 		alert('您点击了下一页')
 44 | 	},
 45 | 	showNext: true,
 46 | 	width: '580px',
 47 | 	height: '292px',
 48 | 	src: 'http://www.daiwei.org/index/video/EnV%20-%20PneumaticTokyo.mp4',
 49 | 	autoplay: true,
 50 | 	setVideoDefinition: function (type, e, current) {
 51 | 		if (type === '0') {
 52 | 			alert('你点击了标清')
 53 | 			// video.setVideoInfo('這是標清','这里填写视频的标清地址',current)
 54 | 		}
 55 | 		if (type === '1') {
 56 | 			alert('你点击了标清')
 57 | 			// video.setVideoInfo('這是標清','这里填写视频的高清地址',current)
 58 | 		}
 59 | 		if (type === '2') {
 60 | 			alert('你点击了标清')
 61 | 			// video.setVideoInfo('這是標清','这里填写视频的超清地址',current)
 62 | 		}
 63 | 		video.showLoading(false)
 64 | 
 65 | 		// setTimeout(function () {
 66 | 		// 	video.videoEle.currentTime = current
 67 | 		// 	video.videoPlay()
 68 | 		// 	video.showLoading(false)
 69 | 		// }, 3000)
 70 | 	},
 71 | })
 72 | 
73 | 74 | 75 | ### 在苹果本地跑dvideo会提示操作localStorage不安全的错误,放在服务端就不存在这个问题了 76 | 77 | ## 实例化 78 | 实例化Dvideo对象 79 | ```js 80 | var video = new Dvideo({...}) 81 | ``` 82 | 83 | #### 属性 84 | - ele: dom 元素, 元素id需要带 # , 比如 #video 或者 .video 85 | - src: 视频地址 string 86 | - isShowPoster: 是否显示封面,默认为true bool 87 | - poster: 封面的地址 string 88 | - title: 视频的名称 string 89 | - width: 视频显示宽度 string '300px' 90 | - height: 视频显示高度 string '160px' 91 | - showNext: 是否显示下一集按钮 bool 默认true 92 | - autoplay: 是否自动播放 bool 默认true 93 | - ctrSpeedDuration: 控制条 关闭的时间 number (ms) 94 | - loop: 视频是否循环播放 bool 默认false 95 | - showVolume: 是否显示音量设置 bool 默认true 96 | - volume: 音量大小 number 0.8 97 | - showVolumeUnFull: 在非全屏幕下是否显示音量调整条 bool 默认false 98 | - showPlayBackRate: 是否显示设置语速菜单列表 bool 默认true 99 | - showPlayBackRateUnFull: 是否在未全屏的情况下 显示语速 bool 默认true 100 | - playbackRate: 语速的设置 object 101 | - activeIndex: 索引 number 102 | - rateList: 语速 array [0.8, 1, 1.2, 2] 103 | - showVideoDefinition: 是否显示清晰度 bool 默认true 104 | - showVideoDefinitionUnFull: 非全屏的状态下是否显示 bool 默认true 105 | - videoDefinition: 清晰度的设置 object 106 | - activeIndex: 索引 number 107 | - definitionList: 清晰度选项 array 108 | - type: 类型 109 | - name: 名称 110 | - nextVideoExtend: function 可让用户自定义扩展 点击下一个视频的操作 111 | - setVideoDefinition: function 设置清晰度的回调 参数 (type, event, currentT) 112 | - onTimeupdate: 进度更新事件 参数(currentT) 113 | - onPlaying: 视频播放事件 参数(currentT) 114 | - onPause: 视频暂停事件 115 | - onEnded: 视频播放结束事件 116 | - onLoadedMetaData: 元数据加载成功事件 117 | 118 | #### 方法 119 | - 更新视频宽度 120 | ```js 121 | video.updateVideoSize() 122 | @param { number } width 宽度 123 | @param { number } height 高度 124 | ``` 125 | 126 | - 显示上下菜单 127 | ```js 128 | video.showTopBottomCtrl() 129 | @param { bool } disappearance 是否自动消失 130 | ``` 131 | 132 | - 关闭上下菜单 133 | ```js 134 | video.hideTopBottomCtrl() 135 | @param { bool } immediately 是否立刻关闭 136 | ``` 137 | 138 | - 更新音量 139 | ```js 140 | video.updateVolume() 141 | @param { number } vol 音量大小 0 - 1 之间 142 | ``` 143 | 144 | - 更新音量 145 | ```js 146 | video.updateVolume() 147 | @param { number } vol 音量大小 0 - 1 之间 148 | ``` 149 | 150 | - 快进 151 | ```js 152 | video.videoForward() 153 | @param { number } seconds 快进时长 154 | ``` 155 | 156 | - 快退 157 | ```js 158 | video.videoRewind() 159 | @param { number } seconds 快退时长 160 | ``` 161 | 162 | - 跳转到具体位置 163 | ```js 164 | video.videoSeek() 165 | @param { number } seconds 跳转的位置 166 | ``` 167 | 168 | - 切换视频地址 169 | ```js 170 | video.setVideoInfo() 171 | @param { sting } title 视频的名称 172 | @param { string } url 视频的地址 173 | @param { number } currentT 视频开始播放的时间,默认为0 174 | ``` 175 | 176 | 177 | 178 | ### DEMO1  http://www.daiwei.org/components/Dvideo 179 | 180 | -------------------------------------------------------------------------------- /_config.yml: -------------------------------------------------------------------------------- 1 | theme: jekyll-theme-cayman -------------------------------------------------------------------------------- /es5/config.rb: -------------------------------------------------------------------------------- 1 | require 'compass/import-once/activate' 2 | # Require any additional compass plugins here. 3 | 4 | # Set this to the root of your project when deployed: 5 | http_path = "/" 6 | css_dir = "css" 7 | sass_dir = "sass" 8 | images_dir = "images" 9 | javascripts_dir = "js" 10 | 11 | # You can select your preferred output style here (can be overridden via the command line): 12 | # output_style = :expanded or :nested or :compact or :compressed 13 | 14 | # To enable relative paths to assets via compass helper functions. Uncomment: 15 | # relative_assets = true 16 | 17 | # To disable debugging comments that display the original location of your selectors. Uncomment: 18 | # line_comments = false 19 | 20 | 21 | # If you prefer the indented syntax, you might want to regenerate this 22 | # project again passing --syntax sass, or you can uncomment this: 23 | # preferred_syntax = :sass 24 | # and then run: 25 | # sass-convert -R --from scss --to sass sass scss && rm -rf sass && mv scss sass 26 | -------------------------------------------------------------------------------- /es5/css/Dvideo.css: -------------------------------------------------------------------------------- 1 | /* line 5, C:/Ruby22-x64/lib/ruby/gems/2.2.0/gems/compass-core-1.0.3/stylesheets/compass/reset/_utilities.scss */ 2 | html, body, div, span, applet, object, iframe, 3 | h1, h2, h3, h4, h5, h6, p, blockquote, pre, 4 | a, abbr, acronym, address, big, cite, code, 5 | del, dfn, em, img, ins, kbd, q, s, samp, 6 | small, strike, strong, sub, sup, tt, var, 7 | b, u, i, center, 8 | dl, dt, dd, ol, ul, li, 9 | fieldset, form, label, legend, 10 | table, caption, tbody, tfoot, thead, tr, th, td, 11 | article, aside, canvas, details, embed, 12 | figure, figcaption, footer, header, hgroup, 13 | menu, nav, output, ruby, section, summary, 14 | time, mark, audio, video { 15 | margin: 0; 16 | padding: 0; 17 | border: 0; 18 | font: inherit; 19 | font-size: 100%; 20 | vertical-align: baseline; 21 | } 22 | 23 | /* line 22, C:/Ruby22-x64/lib/ruby/gems/2.2.0/gems/compass-core-1.0.3/stylesheets/compass/reset/_utilities.scss */ 24 | html { 25 | line-height: 1; 26 | } 27 | 28 | /* line 24, C:/Ruby22-x64/lib/ruby/gems/2.2.0/gems/compass-core-1.0.3/stylesheets/compass/reset/_utilities.scss */ 29 | ol, ul { 30 | list-style: none; 31 | } 32 | 33 | /* line 26, C:/Ruby22-x64/lib/ruby/gems/2.2.0/gems/compass-core-1.0.3/stylesheets/compass/reset/_utilities.scss */ 34 | table { 35 | border-collapse: collapse; 36 | border-spacing: 0; 37 | } 38 | 39 | /* line 28, C:/Ruby22-x64/lib/ruby/gems/2.2.0/gems/compass-core-1.0.3/stylesheets/compass/reset/_utilities.scss */ 40 | caption, th, td { 41 | text-align: left; 42 | font-weight: normal; 43 | vertical-align: middle; 44 | } 45 | 46 | /* line 30, C:/Ruby22-x64/lib/ruby/gems/2.2.0/gems/compass-core-1.0.3/stylesheets/compass/reset/_utilities.scss */ 47 | q, blockquote { 48 | quotes: none; 49 | } 50 | /* line 103, C:/Ruby22-x64/lib/ruby/gems/2.2.0/gems/compass-core-1.0.3/stylesheets/compass/reset/_utilities.scss */ 51 | q:before, q:after, blockquote:before, blockquote:after { 52 | content: ""; 53 | content: none; 54 | } 55 | 56 | /* line 32, C:/Ruby22-x64/lib/ruby/gems/2.2.0/gems/compass-core-1.0.3/stylesheets/compass/reset/_utilities.scss */ 57 | a img { 58 | border: none; 59 | } 60 | 61 | /* line 116, C:/Ruby22-x64/lib/ruby/gems/2.2.0/gems/compass-core-1.0.3/stylesheets/compass/reset/_utilities.scss */ 62 | article, aside, details, figcaption, figure, footer, header, hgroup, main, menu, nav, section, summary { 63 | display: block; 64 | } 65 | 66 | /* line 1, ../sass/Dvideo/_content.scss */ 67 | .ie-fullscreen { 68 | position: fixed; 69 | top: 0; 70 | left: 0; 71 | bottom: 0; 72 | right: 0; 73 | width: 100% !important; 74 | height: 100% !important; 75 | z-index: 2147483647; 76 | } 77 | 78 | /* line 12, ../sass/Dvideo/_content.scss */ 79 | .Dvideo-content { 80 | position: relative; 81 | background: #000; 82 | width: 100%; 83 | height: 100%; 84 | overflow: hidden; 85 | -moz-user-select: -moz-none; 86 | -ms-user-select: none; 87 | -webkit-user-select: none; 88 | user-select: none; 89 | } 90 | /* line 20, ../sass/Dvideo/_content.scss */ 91 | .Dvideo-content .Dvideo-ele { 92 | width: 100%; 93 | height: 100%; 94 | position: absolute; 95 | top: 50%; 96 | left: 50%; 97 | -moz-transform: translate(-50%, -50%); 98 | -ms-transform: translate(-50%, -50%); 99 | -webkit-transform: translate(-50%, -50%); 100 | transform: translate(-50%, -50%); 101 | } 102 | 103 | /* line 2, ../sass/Dvideo/_ctrl.scss */ 104 | .Dvideo-content .Dvideo-ctrl { 105 | position: absolute; 106 | bottom: -40px; 107 | height: 40px; 108 | background: rgba(7, 12, 17, 0.8); 109 | width: 100%; 110 | left: 0; 111 | right: 0; 112 | -moz-transition: all 0.5s ease; 113 | -o-transition: all 0.5s ease; 114 | -webkit-transition: all 0.5s ease; 115 | transition: all 0.5s ease; 116 | font-size: 0; 117 | } 118 | /* line 14, ../sass/Dvideo/_ctrl.scss */ 119 | .Dvideo-content .Dvideo-ctrl.active { 120 | bottom: 0; 121 | } 122 | /* line 19, ../sass/Dvideo/_ctrl.scss */ 123 | .Dvideo-content .Dvideo-ctrl:before { 124 | content: ''; 125 | position: absolute; 126 | left: 0; 127 | right: 0; 128 | bottom: 40px; 129 | height: 10px; 130 | background: transparent; 131 | } 132 | /* line 28, ../sass/Dvideo/_ctrl.scss */ 133 | .Dvideo-content .Dvideo-ctrl .Dvideo-detail { 134 | width: 100%; 135 | height: 100%; 136 | font-size: 0; 137 | position: relative; 138 | } 139 | /* line 33, ../sass/Dvideo/_ctrl.scss */ 140 | .Dvideo-content .Dvideo-ctrl .Dvideo-detail .Dvideo-ctrl-state { 141 | display: inline-block; 142 | vertical-align: middle; 143 | *vertical-align: auto; 144 | *zoom: 1; 145 | *display: inline; 146 | width: auto; 147 | height: 100%; 148 | padding: 0 8px; 149 | text-align: center; 150 | } 151 | /* line 39, ../sass/Dvideo/_ctrl.scss */ 152 | .Dvideo-content .Dvideo-ctrl .Dvideo-detail .Dvideo-ctrl-state:after { 153 | content: ''; 154 | display: inline-block; 155 | vertical-align: middle; 156 | *vertical-align: auto; 157 | *zoom: 1; 158 | *display: inline; 159 | width: 0; 160 | height: 100%; 161 | vertical-align: middle; 162 | } 163 | /* line 46, ../sass/Dvideo/_ctrl.scss */ 164 | .Dvideo-content .Dvideo-ctrl .Dvideo-detail .Dvideo-ctrl-state .Dvideo-ctrl-playPause { 165 | display: inline-block; 166 | vertical-align: middle; 167 | *vertical-align: auto; 168 | *zoom: 1; 169 | *display: inline; 170 | vertical-align: middle; 171 | color: #fff; 172 | font-size: 24px; 173 | margin-right: 16px; 174 | cursor: pointer; 175 | } 176 | /* line 53, ../sass/Dvideo/_ctrl.scss */ 177 | .Dvideo-content .Dvideo-ctrl .Dvideo-detail .Dvideo-ctrl-state .Dvideo-ctrl-playPause:hover { 178 | color: #0484d5; 179 | } 180 | /* line 57, ../sass/Dvideo/_ctrl.scss */ 181 | .Dvideo-content .Dvideo-ctrl .Dvideo-detail .Dvideo-ctrl-state .Dvideo-ctrl-next { 182 | display: inline-block; 183 | vertical-align: middle; 184 | *vertical-align: auto; 185 | *zoom: 1; 186 | *display: inline; 187 | vertical-align: middle; 188 | color: #fff; 189 | font-size: 20px; 190 | cursor: pointer; 191 | } 192 | /* line 63, ../sass/Dvideo/_ctrl.scss */ 193 | .Dvideo-content .Dvideo-ctrl .Dvideo-detail .Dvideo-ctrl-state .Dvideo-ctrl-next:hover { 194 | color: #0484d5; 195 | } 196 | /* line 68, ../sass/Dvideo/_ctrl.scss */ 197 | .Dvideo-content .Dvideo-ctrl .Dvideo-detail .Dvideo-time-content { 198 | display: inline-block; 199 | vertical-align: middle; 200 | *vertical-align: auto; 201 | *zoom: 1; 202 | *display: inline; 203 | width: auto; 204 | color: #787d82; 205 | font-size: 0; 206 | font-weight: 200; 207 | } 208 | /* line 74, ../sass/Dvideo/_ctrl.scss */ 209 | .Dvideo-content .Dvideo-ctrl .Dvideo-detail .Dvideo-time-content .Dvideo-text-current, .Dvideo-content .Dvideo-ctrl .Dvideo-detail .Dvideo-time-content .Dvideo-text-duration { 210 | display: inline-block; 211 | vertical-align: middle; 212 | *vertical-align: auto; 213 | *zoom: 1; 214 | *display: inline; 215 | font-size: 12px; 216 | width: 50px; 217 | text-align: center; 218 | position: relative; 219 | } 220 | /* line 81, ../sass/Dvideo/_ctrl.scss */ 221 | .Dvideo-content .Dvideo-ctrl .Dvideo-detail .Dvideo-time-content .Dvideo-text-duration:before { 222 | content: '/'; 223 | position: absolute; 224 | top: 50%; 225 | left: 0; 226 | color: #fff; 227 | -moz-transform: translate(-50%, -50%); 228 | -ms-transform: translate(-50%, -50%); 229 | -webkit-transform: translate(-50%, -50%); 230 | transform: translate(-50%, -50%); 231 | } 232 | /* line 90, ../sass/Dvideo/_ctrl.scss */ 233 | .Dvideo-content .Dvideo-ctrl .Dvideo-detail .Dvideo-menu-right-content { 234 | position: absolute; 235 | top: 0; 236 | right: 0; 237 | height: 100%; 238 | width: auto; 239 | } 240 | /* line 97, ../sass/Dvideo/_ctrl.scss */ 241 | .Dvideo-content .Dvideo-ctrl .Dvideo-detail .Dvideo-menu-right-content:after { 242 | content: ''; 243 | display: inline-block; 244 | vertical-align: middle; 245 | *vertical-align: auto; 246 | *zoom: 1; 247 | *display: inline; 248 | width: 0; 249 | height: 100%; 250 | vertical-align: middle; 251 | } 252 | /* line 105, ../sass/Dvideo/_ctrl.scss */ 253 | .Dvideo-content .Dvideo-ctrl .Dvideo-detail .Dvideo-menu-right-content i { 254 | display: inline-block; 255 | vertical-align: middle; 256 | *vertical-align: auto; 257 | *zoom: 1; 258 | *display: inline; 259 | font-size: 16px; 260 | color: #787d82; 261 | vertical-align: middle; 262 | cursor: pointer; 263 | margin: 0 10px; 264 | } 265 | /* line 112, ../sass/Dvideo/_ctrl.scss */ 266 | .Dvideo-content .Dvideo-ctrl .Dvideo-detail .Dvideo-menu-right-content i:hover { 267 | color: #0484d5; 268 | } 269 | /* line 116, ../sass/Dvideo/_ctrl.scss */ 270 | .Dvideo-content .Dvideo-ctrl .Dvideo-detail .Dvideo-menu-right-content .Dvideo-playbackRate { 271 | color: #787d82; 272 | width: 35px; 273 | height: 100%; 274 | display: inline-block; 275 | vertical-align: middle; 276 | *vertical-align: auto; 277 | *zoom: 1; 278 | *display: inline; 279 | margin: 0 10px; 280 | -moz-box-sizing: border-box; 281 | -webkit-box-sizing: border-box; 282 | box-sizing: border-box; 283 | cursor: pointer; 284 | text-align: center; 285 | font-size: 12px; 286 | position: relative; 287 | color: #787d82; 288 | } 289 | /* line 128, ../sass/Dvideo/_ctrl.scss */ 290 | .Dvideo-content .Dvideo-ctrl .Dvideo-detail .Dvideo-menu-right-content .Dvideo-playbackRate .Dvideo-playbackRateText { 291 | color: rgba(7, 12, 17, 0.8); 292 | width: 35px; 293 | height: 14px; 294 | line-height: 14px; 295 | margin: calc((100% - 14px) / 2) 0; 296 | vertical-align: middle; 297 | display: inline-block; 298 | vertical-align: middle; 299 | *vertical-align: auto; 300 | *zoom: 1; 301 | *display: inline; 302 | padding: 2px 0; 303 | -moz-border-radius: 2px; 304 | -webkit-border-radius: 2px; 305 | border-radius: 2px; 306 | background: #787d82; 307 | cursor: pointer; 308 | position: relative; 309 | -moz-transition: background 0.3s; 310 | -o-transition: background 0.3s; 311 | -webkit-transition: background 0.3s; 312 | transition: background 0.3s; 313 | } 314 | /* line 144, ../sass/Dvideo/_ctrl.scss */ 315 | .Dvideo-content .Dvideo-ctrl .Dvideo-detail .Dvideo-menu-right-content .Dvideo-playbackRate .Dvideo-playbackRate-content { 316 | display: none; 317 | position: absolute; 318 | bottom: 100%; 319 | background: rgba(7, 12, 17, 0.8); 320 | padding-bottom: 10px; 321 | width: 60px; 322 | height: auto; 323 | left: 50%; 324 | z-index: 3; 325 | -moz-transform: translate(-50%, 0); 326 | -ms-transform: translate(-50%, 0); 327 | -webkit-transform: translate(-50%, 0); 328 | transform: translate(-50%, 0); 329 | } 330 | /* line 155, ../sass/Dvideo/_ctrl.scss */ 331 | .Dvideo-content .Dvideo-ctrl .Dvideo-detail .Dvideo-menu-right-content .Dvideo-playbackRate .Dvideo-playbackRate-content.active { 332 | display: block; 333 | } 334 | /* line 158, ../sass/Dvideo/_ctrl.scss */ 335 | .Dvideo-content .Dvideo-ctrl .Dvideo-detail .Dvideo-menu-right-content .Dvideo-playbackRate .Dvideo-playbackRate-content .Dvideo-playbackRate-list { 336 | display: block; 337 | width: 100%; 338 | height: 30px; 339 | line-height: 30px; 340 | color: #787d82; 341 | } 342 | /* line 164, ../sass/Dvideo/_ctrl.scss */ 343 | .Dvideo-content .Dvideo-ctrl .Dvideo-detail .Dvideo-menu-right-content .Dvideo-playbackRate .Dvideo-playbackRate-content .Dvideo-playbackRate-list.active { 344 | color: #0484d5; 345 | } 346 | /* line 167, ../sass/Dvideo/_ctrl.scss */ 347 | .Dvideo-content .Dvideo-ctrl .Dvideo-detail .Dvideo-menu-right-content .Dvideo-playbackRate .Dvideo-playbackRate-content .Dvideo-playbackRate-list:hover { 348 | background: #1F2429; 349 | } 350 | /* line 172, ../sass/Dvideo/_ctrl.scss */ 351 | .Dvideo-content .Dvideo-ctrl .Dvideo-detail .Dvideo-menu-right-content .Dvideo-playbackRate.none { 352 | display: none; 353 | } 354 | /* line 176, ../sass/Dvideo/_ctrl.scss */ 355 | .Dvideo-content .Dvideo-ctrl .Dvideo-detail .Dvideo-menu-right-content .Dvideo-playbackRate:hover .Dvideo-playbackRateText { 356 | background: #0484d5; 357 | } 358 | /* line 181, ../sass/Dvideo/_ctrl.scss */ 359 | .Dvideo-content .Dvideo-ctrl .Dvideo-detail .Dvideo-menu-right-content .Dvideo-definition { 360 | color: #787d82; 361 | width: 35px; 362 | height: 100%; 363 | display: inline-block; 364 | vertical-align: middle; 365 | *vertical-align: auto; 366 | *zoom: 1; 367 | *display: inline; 368 | margin: 0 10px; 369 | -moz-box-sizing: border-box; 370 | -webkit-box-sizing: border-box; 371 | box-sizing: border-box; 372 | cursor: pointer; 373 | text-align: center; 374 | font-size: 12px; 375 | position: relative; 376 | color: #787d82; 377 | } 378 | /* line 193, ../sass/Dvideo/_ctrl.scss */ 379 | .Dvideo-content .Dvideo-ctrl .Dvideo-detail .Dvideo-menu-right-content .Dvideo-definition .Dvideo-definitionText { 380 | color: rgba(7, 12, 17, 0.8); 381 | width: 35px; 382 | height: 14px; 383 | line-height: 14px; 384 | margin: calc((100% - 14px) / 2) 0; 385 | vertical-align: middle; 386 | display: inline-block; 387 | vertical-align: middle; 388 | *vertical-align: auto; 389 | *zoom: 1; 390 | *display: inline; 391 | padding: 2px 0; 392 | -moz-border-radius: 2px; 393 | -webkit-border-radius: 2px; 394 | border-radius: 2px; 395 | background: #787d82; 396 | cursor: pointer; 397 | position: relative; 398 | -moz-transition: background 0.3s; 399 | -o-transition: background 0.3s; 400 | -webkit-transition: background 0.3s; 401 | transition: background 0.3s; 402 | } 403 | /* line 208, ../sass/Dvideo/_ctrl.scss */ 404 | .Dvideo-content .Dvideo-ctrl .Dvideo-detail .Dvideo-menu-right-content .Dvideo-definition .Dvideo-definition-content { 405 | display: none; 406 | position: absolute; 407 | bottom: 100%; 408 | background: rgba(7, 12, 17, 0.8); 409 | padding-bottom: 10px; 410 | width: 60px; 411 | height: auto; 412 | left: 50%; 413 | z-index: 3; 414 | -moz-transform: translate(-50%, 0); 415 | -ms-transform: translate(-50%, 0); 416 | -webkit-transform: translate(-50%, 0); 417 | transform: translate(-50%, 0); 418 | } 419 | /* line 219, ../sass/Dvideo/_ctrl.scss */ 420 | .Dvideo-content .Dvideo-ctrl .Dvideo-detail .Dvideo-menu-right-content .Dvideo-definition .Dvideo-definition-content.active { 421 | display: block; 422 | } 423 | /* line 222, ../sass/Dvideo/_ctrl.scss */ 424 | .Dvideo-content .Dvideo-ctrl .Dvideo-detail .Dvideo-menu-right-content .Dvideo-definition .Dvideo-definition-content .Dvideo-definition-list { 425 | display: block; 426 | width: 100%; 427 | height: 30px; 428 | line-height: 30px; 429 | color: #787d82; 430 | } 431 | /* line 228, ../sass/Dvideo/_ctrl.scss */ 432 | .Dvideo-content .Dvideo-ctrl .Dvideo-detail .Dvideo-menu-right-content .Dvideo-definition .Dvideo-definition-content .Dvideo-definition-list.active { 433 | color: #0484d5; 434 | } 435 | /* line 231, ../sass/Dvideo/_ctrl.scss */ 436 | .Dvideo-content .Dvideo-ctrl .Dvideo-detail .Dvideo-menu-right-content .Dvideo-definition .Dvideo-definition-content .Dvideo-definition-list:hover { 437 | background: #1F2429; 438 | } 439 | /* line 236, ../sass/Dvideo/_ctrl.scss */ 440 | .Dvideo-content .Dvideo-ctrl .Dvideo-detail .Dvideo-menu-right-content .Dvideo-definition.none { 441 | display: none; 442 | } 443 | /* line 240, ../sass/Dvideo/_ctrl.scss */ 444 | .Dvideo-content .Dvideo-ctrl .Dvideo-detail .Dvideo-menu-right-content .Dvideo-definition:hover .Dvideo-definitionText { 445 | background: #0484d5; 446 | } 447 | /* line 245, ../sass/Dvideo/_ctrl.scss */ 448 | .Dvideo-content .Dvideo-ctrl .Dvideo-detail .Dvideo-menu-right-content .Dvideo-volume { 449 | display: inline-block; 450 | font-size: 16px; 451 | position: relative; 452 | width: 100px; 453 | height: 2px; 454 | background: #999; 455 | margin-right: 15px; 456 | cursor: pointer; 457 | } 458 | /* line 254, ../sass/Dvideo/_ctrl.scss */ 459 | .Dvideo-content .Dvideo-ctrl .Dvideo-detail .Dvideo-menu-right-content .Dvideo-volume:before { 460 | content: ''; 461 | position: absolute; 462 | top: -8px; 463 | left: 0; 464 | height: 8px; 465 | right: 0; 466 | z-index: 9; 467 | } 468 | /* line 263, ../sass/Dvideo/_ctrl.scss */ 469 | .Dvideo-content .Dvideo-ctrl .Dvideo-detail .Dvideo-menu-right-content .Dvideo-volume:after { 470 | content: ''; 471 | position: absolute; 472 | bottom: -8px; 473 | left: 0; 474 | height: 8px; 475 | right: 0; 476 | z-index: 9; 477 | } 478 | /* line 273, ../sass/Dvideo/_ctrl.scss */ 479 | .Dvideo-content .Dvideo-ctrl .Dvideo-detail .Dvideo-menu-right-content .Dvideo-volume.none { 480 | display: none; 481 | } 482 | /* line 277, ../sass/Dvideo/_ctrl.scss */ 483 | .Dvideo-content .Dvideo-ctrl .Dvideo-detail .Dvideo-menu-right-content .Dvideo-volume .Dvideo-volume-P { 484 | width: 100%; 485 | height: 2px; 486 | -moz-border-radius: 1px; 487 | -webkit-border-radius: 1px; 488 | border-radius: 1px; 489 | background: #999; 490 | } 491 | /* line 282, ../sass/Dvideo/_ctrl.scss */ 492 | .Dvideo-content .Dvideo-ctrl .Dvideo-detail .Dvideo-menu-right-content .Dvideo-volume .Dvideo-volume-P .Dvideo-volume-R { 493 | width: 80%; 494 | height: 2px; 495 | -moz-border-radius: 1px; 496 | -webkit-border-radius: 1px; 497 | border-radius: 1px; 498 | background: #cacaca; 499 | } 500 | /* line 289, ../sass/Dvideo/_ctrl.scss */ 501 | .Dvideo-content .Dvideo-ctrl .Dvideo-detail .Dvideo-menu-right-content .Dvideo-volume .Dvideo-volume-range { 502 | width: 12px; 503 | height: 12px; 504 | position: absolute; 505 | top: 0; 506 | left: 80%; 507 | margin-left: -6px; 508 | margin-top: -5px; 509 | -moz-border-radius: 50%; 510 | -webkit-border-radius: 50%; 511 | border-radius: 50%; 512 | background: #fff; 513 | z-index: 10; 514 | cursor: pointer; 515 | } 516 | /* line 303, ../sass/Dvideo/_ctrl.scss */ 517 | .Dvideo-content .Dvideo-ctrl .Dvideo-detail .Dvideo-menu-right-content .Dvideo-volume .Dvideo-volume-range:hover:before { 518 | content: attr(data-volume); 519 | position: absolute; 520 | top: -30px; 521 | left: 50%; 522 | -moz-transform: translate(-50%, 0); 523 | -ms-transform: translate(-50%, 0); 524 | -webkit-transform: translate(-50%, 0); 525 | transform: translate(-50%, 0); 526 | width: 42px; 527 | height: 22px; 528 | line-height: 22px; 529 | text-align: center; 530 | color: #fff; 531 | font-size: 12px; 532 | background: #333; 533 | -moz-border-radius: 3px; 534 | -webkit-border-radius: 3px; 535 | border-radius: 3px; 536 | } 537 | /* line 318, ../sass/Dvideo/_ctrl.scss */ 538 | .Dvideo-content .Dvideo-ctrl .Dvideo-detail .Dvideo-menu-right-content .Dvideo-volume .Dvideo-volume-range:hover:after { 539 | content: ''; 540 | position: absolute; 541 | top: -8px; 542 | left: 50%; 543 | -moz-transform: translate(-50%, 0); 544 | -ms-transform: translate(-50%, 0); 545 | -webkit-transform: translate(-50%, 0); 546 | transform: translate(-50%, 0); 547 | width: 0; 548 | height: 0; 549 | border-top: 6px solid #333; 550 | border-left: 6px solid transparent; 551 | border-right: 6px solid transparent; 552 | border-bottom: 6px solid transparent; 553 | } 554 | /* line 336, ../sass/Dvideo/_ctrl.scss */ 555 | .Dvideo-content .Dvideo-ctrl .Dvideo-progress-content { 556 | height: 2px; 557 | width: 100%; 558 | cursor: pointer; 559 | position: absolute; 560 | bottom: 40px; 561 | background: #333; 562 | z-index: 2; 563 | } 564 | /* line 344, ../sass/Dvideo/_ctrl.scss */ 565 | .Dvideo-content .Dvideo-ctrl .Dvideo-progress-content .Dvideo-progress-detail { 566 | height: 100%; 567 | width: 100%; 568 | } 569 | /* line 347, ../sass/Dvideo/_ctrl.scss */ 570 | .Dvideo-content .Dvideo-ctrl .Dvideo-progress-content .Dvideo-progress-detail .Dvideo-progress-buffered { 571 | width: 0; 572 | height: 100%; 573 | background: #999; 574 | position: absolute; 575 | top: 0; 576 | left: 0; 577 | -moz-transition: width 0.3s; 578 | -o-transition: width 0.3s; 579 | -webkit-transition: width 0.3s; 580 | transition: width 0.3s; 581 | } 582 | /* line 356, ../sass/Dvideo/_ctrl.scss */ 583 | .Dvideo-content .Dvideo-ctrl .Dvideo-progress-content .Dvideo-progress-detail .Dvideo-progress-real { 584 | width: 0%; 585 | height: 100%; 586 | background: url('data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz4gPHN2ZyB2ZXJzaW9uPSIxLjEiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+PGRlZnM+PGxpbmVhckdyYWRpZW50IGlkPSJncmFkIiBncmFkaWVudFVuaXRzPSJvYmplY3RCb3VuZGluZ0JveCIgeDE9IjAuMCIgeTE9IjAuNSIgeDI9IjEuMCIgeTI9IjAuNSI+PHN0b3Agb2Zmc2V0PSI3MCUiIHN0b3AtY29sb3I9IiMwNDg0ZDUiLz48c3RvcCBvZmZzZXQ9IjEwMCUiIHN0b3AtY29sb3I9IiNmZmZmZmYiLz48L2xpbmVhckdyYWRpZW50PjwvZGVmcz48cmVjdCB4PSIwIiB5PSIwIiB3aWR0aD0iMTAwJSIgaGVpZ2h0PSIxMDAlIiBmaWxsPSJ1cmwoI2dyYWQpIiAvPjwvc3ZnPiA='); 587 | background: -webkit-gradient(linear, 0% 50%, 100% 50%, color-stop(70%, #0484d5), color-stop(100%, #ffffff)); 588 | background: -moz-linear-gradient(left, #0484d5 70%, #ffffff); 589 | background: -webkit-linear-gradient(left, #0484d5 70%, #ffffff); 590 | background: linear-gradient(to right, #0484d5 70%, #ffffff); 591 | position: relative; 592 | -moz-transition: width 0.3s; 593 | -o-transition: width 0.3s; 594 | -webkit-transition: width 0.3s; 595 | transition: width 0.3s; 596 | } 597 | /* line 365, ../sass/Dvideo/_ctrl.scss */ 598 | .Dvideo-content .Dvideo-ctrl .Dvideo-progress-content .Dvideo-circle-range { 599 | display: none; 600 | position: absolute; 601 | top: -5px; 602 | left: 0; 603 | margin-left: -7px; 604 | width: 14px; 605 | height: 14px; 606 | background: #fff; 607 | -moz-border-radius: 50%; 608 | -webkit-border-radius: 50%; 609 | border-radius: 50%; 610 | } 611 | /* line 375, ../sass/Dvideo/_ctrl.scss */ 612 | .Dvideo-content .Dvideo-ctrl .Dvideo-progress-content .Dvideo-circle-range:after { 613 | content: ''; 614 | position: absolute; 615 | top: 50%; 616 | left: 50%; 617 | width: 6px; 618 | height: 6px; 619 | -moz-border-radius: 50%; 620 | -webkit-border-radius: 50%; 621 | border-radius: 50%; 622 | background: #0484d5; 623 | -moz-transform: translate(-50%, -50%); 624 | -ms-transform: translate(-50%, -50%); 625 | -webkit-transform: translate(-50%, -50%); 626 | transform: translate(-50%, -50%); 627 | } 628 | /* line 387, ../sass/Dvideo/_ctrl.scss */ 629 | .Dvideo-content .Dvideo-ctrl .Dvideo-progress-content.active { 630 | height: 4px; 631 | } 632 | /* line 390, ../sass/Dvideo/_ctrl.scss */ 633 | .Dvideo-content .Dvideo-ctrl .Dvideo-progress-content.active .Dvideo-progress-detail .Dvideo-progress-real { 634 | -moz-transition: none; 635 | -o-transition: none; 636 | -webkit-transition: none; 637 | transition: none; 638 | } 639 | /* line 394, ../sass/Dvideo/_ctrl.scss */ 640 | .Dvideo-content .Dvideo-ctrl .Dvideo-progress-content.active .Dvideo-circle-range { 641 | display: block; 642 | } 643 | /* line 399, ../sass/Dvideo/_ctrl.scss */ 644 | .Dvideo-content .Dvideo-ctrl .Dvideo-tips-info { 645 | position: absolute; 646 | left: 0; 647 | right: 0; 648 | bottom: 40px; 649 | height: 28px; 650 | line-height: 28px; 651 | z-index: 1; 652 | background: transparent; 653 | color: #fff; 654 | font-size: 12px; 655 | padding: 0 5px; 656 | -moz-box-sizing: border-box; 657 | -webkit-box-sizing: border-box; 658 | box-sizing: border-box; 659 | display: block; 660 | } 661 | /* line 413, ../sass/Dvideo/_ctrl.scss */ 662 | .Dvideo-content .Dvideo-ctrl .Dvideo-tips-info.hide { 663 | display: none; 664 | } 665 | /* line 419, ../sass/Dvideo/_ctrl.scss */ 666 | .Dvideo-content .Dvideo-header { 667 | position: absolute; 668 | top: 0; 669 | height: 36px; 670 | line-height: 36px; 671 | background: rgba(7, 12, 17, 0.8); 672 | width: 100%; 673 | left: 0; 674 | right: 0; 675 | -moz-transition: all 0.5s ease; 676 | -o-transition: all 0.5s ease; 677 | -webkit-transition: all 0.5s ease; 678 | transition: all 0.5s ease; 679 | filter: progid:DXImageTransform.Microsoft.Alpha(Opacity=0); 680 | opacity: 0; 681 | visibility: hidden; 682 | } 683 | /* line 431, ../sass/Dvideo/_ctrl.scss */ 684 | .Dvideo-content .Dvideo-header.active { 685 | filter: progid:DXImageTransform.Microsoft.Alpha(enabled=false); 686 | opacity: 1; 687 | visibility: visible; 688 | } 689 | /* line 436, ../sass/Dvideo/_ctrl.scss */ 690 | .Dvideo-content .Dvideo-header .Dvideo-header-title { 691 | width: 80%; 692 | height: 100%; 693 | padding: 0 8px; 694 | font-size: 14px; 695 | color: rgba(255, 255, 255, 0.8); 696 | text-overflow: ellipsis; 697 | white-space: nowrap; 698 | overflow: hidden; 699 | margin: 0; 700 | } 701 | /* line 454, ../sass/Dvideo/_ctrl.scss */ 702 | .Dvideo-content.full .Dvideo-ctrl .Dvideo-detail .Dvideo-menu-right-content .Dvideo-volume.none { 703 | display: inline-block; 704 | vertical-align: middle; 705 | *vertical-align: auto; 706 | *zoom: 1; 707 | *display: inline; 708 | } 709 | /* line 459, ../sass/Dvideo/_ctrl.scss */ 710 | .Dvideo-content.full .Dvideo-ctrl .Dvideo-detail .Dvideo-menu-right-content .Dvideo-definition.none { 711 | display: inline-block; 712 | vertical-align: middle; 713 | *vertical-align: auto; 714 | *zoom: 1; 715 | *display: inline; 716 | } 717 | /* line 464, ../sass/Dvideo/_ctrl.scss */ 718 | .Dvideo-content.full .Dvideo-ctrl .Dvideo-detail .Dvideo-menu-right-content .Dvideo-playbackRate.none { 719 | display: inline-block; 720 | vertical-align: middle; 721 | *vertical-align: auto; 722 | *zoom: 1; 723 | *display: inline; 724 | } 725 | /* line 474, ../sass/Dvideo/_ctrl.scss */ 726 | .Dvideo-content.gradient .Dvideo-ctrl { 727 | background: url('data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz4gPHN2ZyB2ZXJzaW9uPSIxLjEiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+PGRlZnM+PGxpbmVhckdyYWRpZW50IGlkPSJncmFkIiBncmFkaWVudFVuaXRzPSJvYmplY3RCb3VuZGluZ0JveCIgeDE9IjAuNSIgeTE9IjEuMCIgeDI9IjAuNSIgeTI9IjAuMCI+PHN0b3Agb2Zmc2V0PSIwJSIgc3RvcC1jb2xvcj0iIzA2MTAxYSIgc3RvcC1vcGFjaXR5PSIwLjYiLz48c3RvcCBvZmZzZXQ9IjEwMCUiIHN0b3AtY29sb3I9IiMwMDAwMDAiIHN0b3Atb3BhY2l0eT0iMC4wIi8+PC9saW5lYXJHcmFkaWVudD48L2RlZnM+PHJlY3QgeD0iMCIgeT0iMCIgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0idXJsKCNncmFkKSIgLz48L3N2Zz4g'); 728 | background: -webkit-gradient(linear, 50% 100%, 50% 0%, color-stop(0%, rgba(6, 16, 26, 0.6)), color-stop(100%, rgba(0, 0, 0, 0))); 729 | background: -moz-linear-gradient(bottom, rgba(6, 16, 26, 0.6), rgba(0, 0, 0, 0)); 730 | background: -webkit-linear-gradient(bottom, rgba(6, 16, 26, 0.6), rgba(0, 0, 0, 0)); 731 | background: linear-gradient(to top, rgba(6, 16, 26, 0.6), rgba(0, 0, 0, 0)); 732 | } 733 | /* line 477, ../sass/Dvideo/_ctrl.scss */ 734 | .Dvideo-content.gradient .Dvideo-ctrl .Dvideo-detail .Dvideo-time-content { 735 | color: rgba(177, 187, 197, 0.6); 736 | } 737 | /* line 481, ../sass/Dvideo/_ctrl.scss */ 738 | .Dvideo-content.gradient .Dvideo-ctrl .Dvideo-detail .Dvideo-menu-right-content i { 739 | color: rgba(177, 187, 197, 0.6); 740 | } 741 | /* line 485, ../sass/Dvideo/_ctrl.scss */ 742 | .Dvideo-content.gradient .Dvideo-ctrl .Dvideo-detail .Dvideo-playbackRate { 743 | background: rgba(177, 187, 197, 0.6); 744 | } 745 | /* line 487, ../sass/Dvideo/_ctrl.scss */ 746 | .Dvideo-content.gradient .Dvideo-ctrl .Dvideo-detail .Dvideo-playbackRate .Dvideo-playbackRate-content { 747 | background: transparent; 748 | } 749 | /* line 489, ../sass/Dvideo/_ctrl.scss */ 750 | .Dvideo-content.gradient .Dvideo-ctrl .Dvideo-detail .Dvideo-playbackRate .Dvideo-playbackRate-content .Dvideo-playbackRate-list { 751 | color: rgba(177, 187, 197, 0.6); 752 | background: rgba(177, 187, 197, 0.6); 753 | } 754 | /* line 492, ../sass/Dvideo/_ctrl.scss */ 755 | .Dvideo-content.gradient .Dvideo-ctrl .Dvideo-detail .Dvideo-playbackRate .Dvideo-playbackRate-content .Dvideo-playbackRate-list:active { 756 | color: rgba(255, 0, 0, 0.3); 757 | } 758 | /* line 495, ../sass/Dvideo/_ctrl.scss */ 759 | .Dvideo-content.gradient .Dvideo-ctrl .Dvideo-detail .Dvideo-playbackRate .Dvideo-playbackRate-content .Dvideo-playbackRate-list:hover { 760 | background: rgba(31, 36, 41, 0.6); 761 | } 762 | /* line 501, ../sass/Dvideo/_ctrl.scss */ 763 | .Dvideo-content.gradient .Dvideo-ctrl .Dvideo-detail .Dvideo-definition { 764 | background: rgba(177, 187, 197, 0.6); 765 | } 766 | /* line 503, ../sass/Dvideo/_ctrl.scss */ 767 | .Dvideo-content.gradient .Dvideo-ctrl .Dvideo-detail .Dvideo-definition .Dvideo-definition-content { 768 | background: transparent; 769 | } 770 | /* line 505, ../sass/Dvideo/_ctrl.scss */ 771 | .Dvideo-content.gradient .Dvideo-ctrl .Dvideo-detail .Dvideo-definition .Dvideo-definition-content .Dvideo-definition-list { 772 | color: rgba(177, 187, 197, 0.6); 773 | background: rgba(177, 187, 197, 0.6); 774 | } 775 | /* line 508, ../sass/Dvideo/_ctrl.scss */ 776 | .Dvideo-content.gradient .Dvideo-ctrl .Dvideo-detail .Dvideo-definition .Dvideo-definition-content .Dvideo-definition-list.active { 777 | color: rgba(255, 0, 0, 0.3); 778 | } 779 | /* line 511, ../sass/Dvideo/_ctrl.scss */ 780 | .Dvideo-content.gradient .Dvideo-ctrl .Dvideo-detail .Dvideo-definition .Dvideo-definition-content .Dvideo-definition-list:hover { 781 | background: rgba(31, 36, 41, 0.6); 782 | } 783 | /* line 518, ../sass/Dvideo/_ctrl.scss */ 784 | .Dvideo-content.gradient .Dvideo-ctrl .Dvideo-progress-content { 785 | width: calc(100% - 20px); 786 | left: 50%; 787 | -moz-border-radius: 2px; 788 | -webkit-border-radius: 2px; 789 | border-radius: 2px; 790 | -moz-transform: translate(-50%, 0); 791 | -ms-transform: translate(-50%, 0); 792 | -webkit-transform: translate(-50%, 0); 793 | transform: translate(-50%, 0); 794 | background: rgba(51, 51, 51, 0.3); 795 | } 796 | /* line 525, ../sass/Dvideo/_ctrl.scss */ 797 | .Dvideo-content.gradient .Dvideo-ctrl .Dvideo-progress-content .Dvideo-progress-detail .Dvideo-progress-buffered { 798 | background: rgba(153, 153, 153, 0.3); 799 | } 800 | /* line 528, ../sass/Dvideo/_ctrl.scss */ 801 | .Dvideo-content.gradient .Dvideo-ctrl .Dvideo-progress-content .Dvideo-progress-detail .Dvideo-progress-real { 802 | background: url('data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz4gPHN2ZyB2ZXJzaW9uPSIxLjEiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+PGRlZnM+PGxpbmVhckdyYWRpZW50IGlkPSJncmFkIiBncmFkaWVudFVuaXRzPSJvYmplY3RCb3VuZGluZ0JveCIgeDE9IjAuMCIgeTE9IjAuNSIgeDI9IjEuMCIgeTI9IjAuNSI+PHN0b3Agb2Zmc2V0PSIwJSIgc3RvcC1jb2xvcj0iI2ZmMDAwMCIgc3RvcC1vcGFjaXR5PSIwLjgiLz48c3RvcCBvZmZzZXQ9IjEwMCUiIHN0b3AtY29sb3I9IiNmZjAwMDAiIHN0b3Atb3BhY2l0eT0iMC4xIi8+PC9saW5lYXJHcmFkaWVudD48L2RlZnM+PHJlY3QgeD0iMCIgeT0iMCIgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0idXJsKCNncmFkKSIgLz48L3N2Zz4g'); 803 | background: -webkit-gradient(linear, 0% 50%, 100% 50%, color-stop(0%, rgba(255, 0, 0, 0.8)), color-stop(100%, rgba(255, 0, 0, 0.1))); 804 | background: -moz-linear-gradient(left, rgba(255, 0, 0, 0.8), rgba(255, 0, 0, 0.1)); 805 | background: -webkit-linear-gradient(left, rgba(255, 0, 0, 0.8), rgba(255, 0, 0, 0.1)); 806 | background: linear-gradient(to right, rgba(255, 0, 0, 0.8), rgba(255, 0, 0, 0.1)); 807 | } 808 | /* line 534, ../sass/Dvideo/_ctrl.scss */ 809 | .Dvideo-content.gradient .Dvideo-header { 810 | background: url('data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz4gPHN2ZyB2ZXJzaW9uPSIxLjEiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+PGRlZnM+PGxpbmVhckdyYWRpZW50IGlkPSJncmFkIiBncmFkaWVudFVuaXRzPSJvYmplY3RCb3VuZGluZ0JveCIgeDE9IjAuNSIgeTE9IjAuMCIgeDI9IjAuNSIgeTI9IjEuMCI+PHN0b3Agb2Zmc2V0PSIwJSIgc3RvcC1jb2xvcj0iIzA2MTAxYSIgc3RvcC1vcGFjaXR5PSIwLjYiLz48c3RvcCBvZmZzZXQ9IjEwMCUiIHN0b3AtY29sb3I9IiMwMDAwMDAiIHN0b3Atb3BhY2l0eT0iMC4wIi8+PC9saW5lYXJHcmFkaWVudD48L2RlZnM+PHJlY3QgeD0iMCIgeT0iMCIgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0idXJsKCNncmFkKSIgLz48L3N2Zz4g'); 811 | background: -webkit-gradient(linear, 50% 0%, 50% 100%, color-stop(0%, rgba(6, 16, 26, 0.6)), color-stop(100%, rgba(0, 0, 0, 0))); 812 | background: -moz-linear-gradient(top, rgba(6, 16, 26, 0.6), rgba(0, 0, 0, 0)); 813 | background: -webkit-linear-gradient(top, rgba(6, 16, 26, 0.6), rgba(0, 0, 0, 0)); 814 | background: linear-gradient(to bottom, rgba(6, 16, 26, 0.6), rgba(0, 0, 0, 0)); 815 | } 816 | 817 | /* line 11, ../sass/Dvideo.scss */ 818 | :-webkit-full-screen { 819 | /* properties */ 820 | background-color: black; 821 | position: fixed; 822 | top: 0; 823 | right: 0; 824 | left: 0; 825 | bottom: 0; 826 | } 827 | 828 | /* line 21, ../sass/Dvideo.scss */ 829 | :-moz-full-screen { 830 | /* properties */ 831 | } 832 | 833 | /* line 25, ../sass/Dvideo.scss */ 834 | :-ms-fullscreen { 835 | /* properties */ 836 | } 837 | 838 | /* line 29, ../sass/Dvideo.scss */ 839 | :full-screen { 840 | /*pre-spec */ 841 | /* properties */ 842 | } 843 | 844 | /* line 33, ../sass/Dvideo.scss */ 845 | :fullscreen { 846 | /* spec */ 847 | /* properties */ 848 | } 849 | 850 | /* deeper elements */ 851 | /* line 38, ../sass/Dvideo.scss */ 852 | :-webkit-full-screen video { 853 | width: 100%; 854 | height: 100%; 855 | } 856 | 857 | /* styling the backdrop*/ 858 | /* line 44, ../sass/Dvideo.scss */ 859 | ::backdrop { 860 | /* properties */ 861 | } 862 | 863 | /* line 47, ../sass/Dvideo.scss */ 864 | ::-ms-backdrop { 865 | /* properties */ 866 | } 867 | -------------------------------------------------------------------------------- /es5/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Document 6 | 7 | 8 | 9 | 10 | 78 | 79 | 80 |
81 |

基于原生js的Dvideo.js组件

82 |
83 |
84 | 点击全屏 85 | 播放 ctrl + space 86 | 暂停 ctrl + space 87 | 播放暂停 88 | 100的音量大小 ctrl + up 89 | 30的音量大小 ctrl + down 90 | 2.0的语速 91 | 正常的语速 92 | 快退 ctrl + left 93 | 快进 ctrl + right 94 | 显示进度信息 95 | 显示上下菜单且不自动关闭 96 | 立刻关闭上下菜单 97 | 显示菜单自动关闭 98 | 固定时间后自动关闭 99 | 设置宽720 高480 100 |
101 | github: https://github.com/IFmiss/Dvideo.js 102 |
103 | 104 | 105 | 203 | -------------------------------------------------------------------------------- /es5/js/Dvideo.js: -------------------------------------------------------------------------------- 1 | (function (window, document) { 2 | var Dvideo = function (options) { 3 | // 判断是否是new Dvideo 的 不是的话 帮他new一下 4 | if (!(this instanceof Dvideo)) return new Dvideo(options) 5 | this.localValue = { 6 | // video元素 7 | ele: '', 8 | 9 | // 地址 10 | src: 'http://www.daiwei.org/index/video/EnV%20-%20PneumaticTokyo.mp4', 11 | 12 | // 视频封面 未加载完成的封面 13 | poster: 'http://www.daiwei.org/vue/image/17-07-07/IMG_0330.jpg', 14 | 15 | // 显示的名称 16 | title: '这是一个视频标题这是一个视频标题这是一个视频标题这是一个视频标题', 17 | 18 | // 宽度 19 | width: '420px', 20 | // 高度 21 | height: '250px', 22 | 23 | // 是否显示播放下一集的提示按钮 24 | showNext: false, 25 | 26 | // 是否设置自动播放 27 | autoplay: false, 28 | 29 | // 控制栏显示隐藏动画的 时间 30 | ctrSpeedDuration: 3000, 31 | 32 | // 是否自动循环 33 | loop: true, 34 | 35 | // 音量默认大小 36 | volume: 0.8, 37 | 38 | // 是否显示音量的控制效果 39 | showVolume: true, 40 | 41 | // 在非全屏下是否显示控制 42 | showVolumeUnFull: false, 43 | 44 | // 提示信息的元素dom 45 | tipsInfo: null, 46 | 47 | // 是否显示语速的设置 48 | showPlayBackRate: true, 49 | playbackRate: { 50 | // 索引 51 | activeIndex: 1, 52 | // 选项 53 | rateList: [0.8,1,1.5,2] 54 | }, 55 | // 是否在未全屏的情况下 显示语速 56 | showPlayBackRateUnFull: true, 57 | 58 | // 是否显示清晰度的设置 59 | showVideoDefinition: true, 60 | videoDefinition: { 61 | // 索引 62 | activeIndex: 1, 63 | // 选项 64 | definitionList: [ 65 | { 66 | // 类型 字符串标识 67 | type: '0', 68 | // 类型 展示效果标识 69 | name: '标清' 70 | }, 71 | { 72 | type: '1', 73 | name: '高清' 74 | }, 75 | { 76 | type: '2', 77 | name: '超清' 78 | } 79 | ] 80 | }, 81 | // 是否在未全屏幕的情况下 显示清晰度 82 | showVideoDefinitionUnFull: true, 83 | 84 | // 可让用户自定义扩展 播放下一个视频的操作 85 | nextVideoExtend: function () {}, 86 | // 设置清晰度的操作 87 | setVideoDefinition: function (type, ele, currentT) {}, 88 | 89 | // video事件 90 | onTimeupdate: function (currentT) {}, 91 | onPlaying: function (currentT) {}, 92 | onPause: function () {}, 93 | onEnded: function () {}, 94 | onLoadedMetaData: function () {} 95 | } 96 | 97 | this.opt = this.extend(this.localValue, options, true) 98 | 99 | // this.clearLStorage() 100 | 101 | //================初始化部分变量 102 | // 设置全屏的状态 103 | this.isFull = false 104 | 105 | // 是否已经加载初始化元数据 106 | this.isLoadMate = false 107 | 108 | // 设置视频时长 109 | this.durationT = 0 110 | 111 | // 当前的播放时间 112 | this.currentT = 0 113 | 114 | // 这是鼠标移入显示控制菜单的timeout 115 | this.showCtrlT = '' 116 | 117 | // 进度百分比 118 | this.currentP = 0 119 | 120 | // 进度条是否可拖动 121 | this.isDrag = false 122 | 123 | // 快进快退事件 124 | this.onpress = false 125 | 126 | // 进度条的宽度 127 | this.maxProgressWidth = 0 128 | 129 | // 进度条拖动的位置 130 | this.dragProgressTo = 0 131 | 132 | // 音量大小 133 | this.volume = 1 134 | 135 | // 音量最大宽度 136 | this.maxVolumeWidth = 0 137 | 138 | // 音量拖动的位置 139 | this.dragVolumeTo = 0 140 | 141 | // 获取浏览器版本 142 | this.browserV = this.browserVersion() 143 | 144 | // 通过时间戳与当前时间的差值来判断是否需要加载 145 | this.reduceTBefore = 0 // 时间戳与当前时间的差值 (初始化) 146 | this.reduceTAfter = 0 // 时间戳与当前时间的差值 (执行中) 147 | 148 | // 判断传进来的是DOM还是字符串 149 | if ((typeof options.ele) === "string") { 150 | this.opt.ele = document.querySelector(options.ele) 151 | }else{ 152 | this.opt.ele = options.ele 153 | } 154 | this.isPlaying = this.opt.autoplay 155 | this.initDom() 156 | this.showTopBottomCtrl(true) 157 | } 158 | 159 | Dvideo.prototype = { 160 | constructor: this, 161 | initDom: function () { 162 | this.opt.ele.style.width = this.opt.width 163 | this.opt.ele.style.height = this.opt.height 164 | 165 | // 创建组件的content区域 166 | this.createVideoC() 167 | 168 | // 创建Video 169 | this.createVideoEle() 170 | 171 | // 创建头部菜单信息 172 | this.createHeaderC() 173 | 174 | // 创建控制菜单 175 | this.createCtrlC() 176 | 177 | // 显示提示信息 178 | this.createVideoTips() 179 | 180 | // 音乐播放暂停 下一集 181 | this.createvideoPlayState() 182 | 183 | // 进度条 184 | this.createPcProgress() 185 | 186 | // 创建current / duration 时间显示 187 | this.createCurrentDurationText() 188 | 189 | // 菜单栏右侧信息 190 | this.menuRightC = document.createElement('div') 191 | this.menuRightC.className = 'Dvideo-menu-right-content' 192 | this.videoCtrlDetail.appendChild(this.menuRightC) 193 | 194 | // 音量拖动效果 195 | if (this.opt.showVolume) { 196 | this.createVolume() 197 | } 198 | 199 | // 语速选项的列表 200 | if (this.opt.showPlayBackRate) { 201 | this.createPlaybackRateList() 202 | } 203 | 204 | 205 | // 设置清晰度区域 206 | if (this.opt.showVideoDefinition) { 207 | this.createVideoDefinition() 208 | } 209 | 210 | 211 | // 全屏按钮 212 | this.createSelectVideoFull() 213 | 214 | // 初始化事件 215 | this.initEvent() 216 | }, 217 | 218 | extend: function(o,n,override) { 219 | for(var key in n){ 220 | if (n.hasOwnProperty(key) && (!o.hasOwnProperty(key) || override)) { 221 | o[key] = n[key] 222 | } 223 | } 224 | return o 225 | }, 226 | 227 | // 开启全屏 228 | launchFullScreen: function (element) { 229 | if(this.browserV.indexOf('IE10') >= 0 || this.browserV.indexOf('IE9') >= 0) { 230 | console.log('启用IE全屏') 231 | this.launchFullScreenIE11L(); 232 | } else { 233 | // alert(screenChange) 234 | if (element.requestFullscreen) { 235 | element.requestFullscreen() 236 | } else if (element.mozRequestFullScreen) { 237 | element.mozRequestFullScreen() 238 | } else if (element.webkitRequestFullscreen) { 239 | element.webkitRequestFullscreen() 240 | } else if (element.msRequestFullscreen) { 241 | element.msRequestFullscreen() 242 | } 243 | console.log('启用全屏 包括ie11') 244 | this.launchFullScreenStyle(element) 245 | } 246 | this.updateFullScreenState(true) 247 | }, 248 | 249 | // 全屏下视频的样式 250 | launchFullScreenStyle: function () { 251 | this.opt.ele.style.width = '100%' 252 | this.opt.ele.style.height = '100%' 253 | }, 254 | 255 | // 全屏下IE 11 以下视频的样式 256 | launchFullScreenIE11L: function () { 257 | var cName = this.opt.ele.className 258 | this.opt.ele.className = cName + ' ie-fullscreen' 259 | // var wscript = new ActiveXObject("WScript.Shell"); 260 | // if (wscript !== null) { 261 | // wscript.SendKeys("{F11}"); 262 | // } 263 | }, 264 | 265 | // 关闭全屏 266 | exitFullscreen: function () { 267 | if(this.browserV.indexOf('IE10') >= 0 || this.browserV.indexOf('IE9') >= 0) { 268 | console.log('启用IE9 IE10全屏') 269 | // this.isFull = true 270 | this.exitFullscreenIE11L(); 271 | } else { 272 | // this.exitFullScreenStyle() 273 | if (document.exitFullscreen) { 274 | document.exitFullscreen(); 275 | } else if (document.mozCancelFullScreen) { 276 | document.mozCancelFullScreen(); 277 | } else if (document.webkitExitFullscreen) { 278 | document.webkitExitFullscreen(); 279 | } else if (document.msExitFullscreen) { 280 | document.msExitFullscreen(); 281 | } 282 | } 283 | }, 284 | 285 | // 关闭全屏IE 10及以下 286 | exitFullscreenIE11L: function () { 287 | console.log('关闭全屏 IE 10及以下') 288 | this.updateFullScreenState(false) 289 | var cName = this.opt.ele.className 290 | this.opt.ele.className = cName.split(' ').slice(cName.split(' ').indexOf('ie-fullscreen'), 1) 291 | // var wscript = new ActiveXObject("WScript.Shell"); 292 | // if (wscript !== null) { 293 | // wscript.SendKeys("{F11}"); 294 | // } 295 | this.opt.ele.style.width = this.opt.width 296 | this.opt.ele.style.height = this.opt.height 297 | }, 298 | 299 | // 关闭全屏的元素样式 300 | exitFullScreenStyle: function () { 301 | console.log('关闭全屏 其他浏览器 和 非IE11以下') 302 | this.updateFullScreenState(false) 303 | this.opt.ele.style.width = this.opt.width 304 | this.opt.ele.style.height = this.opt.height 305 | }, 306 | 307 | // 更新视频宽度 308 | updateVideoSize: function (width, height) { 309 | if (!(width && height)) { 310 | throw Error ('noneeleerror','请填写信息') 311 | return; 312 | } 313 | console.log('改变video的宽高') 314 | this.updateFullScreenState(false) 315 | this.opt.ele.style.width = width + 'px' 316 | this.opt.ele.style.height = height + 'px' 317 | this.opt.width = width + 'px' 318 | this.opt.height = height + 'px' 319 | }, 320 | 321 | // 更新全屏状态 包括显示全屏图标样式 322 | updateFullScreenState: function (bool) { 323 | this.isFull = bool || false 324 | // 全屏图标样式 325 | var iconClassName = this.isFull ? 'Dvideo-menu-fullscreenConfig icon-canclefullscreen' : 'Dvideo-menu-fullscreenConfig icon-fullscreen' 326 | // 文案 327 | var title = this.isFull ? '取消全屏' : '全屏' 328 | this.fullscreenConfig.className = iconClassName 329 | this.fullscreenConfig.title = title 330 | // 设置页面是否全屏的class 331 | var videoClassName = this.isFull ? 'Dvideo-content full' : 'Dvideo-content' 332 | this.videoC.className = videoClassName 333 | }, 334 | 335 | // 屏幕全屏模式改变事件 包括ie 11 以下 336 | screenChangeEvent: function (element) { 337 | var _this = this 338 | if(_this.browserV.indexOf('IE11') >= 0) { 339 | document.onkeydown = function (e) { 340 | var keyNum = window.event ? e.keyCode : e.which 341 | if (keyNum === 27 && _this.isFull) { 342 | // ie退出全屏 这里针对的是IE11 343 | _this.exitFullScreenStyle() 344 | } 345 | } 346 | } 347 | else if (this.browserV.indexOf('IE10') >= 0 || this.browserV.indexOf('IE9') >= 0) { 348 | document.onkeydown = function (e) { 349 | var keyNum = window.event ? e.keyCode : e.which 350 | if (keyNum === 27 && _this.isFull) { 351 | // ie退出全屏 这里针对的是IE10 9 352 | _this.exitFullscreenIE11L() 353 | } 354 | } 355 | } 356 | else { 357 | var eventList = ['webkitfullscreenchange', 'mozfullscreenchange', 'fullscreenchange', 'msfullscreenchange'] 358 | for(var i = 0; i < eventList.length; i++) { 359 | document.addEventListener(eventList[i], function () { 360 | // 全屏显示的网页元素 361 | var fullscreenElement = document.fullscreenElement || document.mozFullScreenElement || document.webkitFullscreenElement || document.msFullscreenElement 362 | 363 | // 判断网页是否处于全屏状态下 364 | var isFullScreen = document.fullScreen || document.mozFullScreen || document.webkitIsFullScreen || document.msIsFullScreen 365 | 366 | if (fullscreenElement) { 367 | console.log('全屏') 368 | _this.launchFullScreenStyle(_this.opt.ele); 369 | } else { 370 | console.log('不是全屏') 371 | _this.exitFullScreenStyle() 372 | } 373 | }) 374 | } 375 | } 376 | }, 377 | 378 | browserVersion: function () { 379 | var userAgent = navigator.userAgent, 380 | rMsie = /(msie\s|trident.*rv:)([\w.]+)/, 381 | rFirefox = /(firefox)\/([\w.]+)/, 382 | rOpera = /(opera).+version\/([\w.]+)/, 383 | rChrome = /(chrome)\/([\w.]+)/, 384 | rSafari = /version\/([\w.]+).*(safari)/; 385 | var browser; 386 | var version; 387 | var ua = userAgent.toLowerCase(); 388 | function uaMatch(ua){ 389 | var match = rMsie.exec(ua); 390 | if(match != null){ 391 | return { browser : "IE", version : match[2] || "0" }; 392 | } 393 | var match = rFirefox.exec(ua); 394 | if (match != null) { 395 | return { browser : match[1] || "", version : match[2] || "0" }; 396 | } 397 | var match = rOpera.exec(ua); 398 | if (match != null) { 399 | return { browser : match[1] || "", version : match[2] || "0" }; 400 | } 401 | var match = rChrome.exec(ua); 402 | if (match != null) { 403 | return { browser : match[1] || "", version : match[2] || "0" }; 404 | } 405 | var match = rSafari.exec(ua); 406 | if (match != null) { 407 | return { browser : match[2] || "", version : match[1] || "0" }; 408 | } 409 | if (match != null) { 410 | return { browser : "", version : "0" }; 411 | } 412 | } 413 | var browserMatch = uaMatch(userAgent.toLowerCase()); 414 | if (browserMatch.browser){ 415 | browser = browserMatch.browser; 416 | version = browserMatch.version; 417 | } 418 | return browser + version 419 | }, 420 | 421 | // 显示上下菜单 disappearance 是否自动消失 422 | showTopBottomCtrl: function (disappearance) { 423 | clearTimeout(this.showCtrlT) 424 | this.videoCtrl.className = 'Dvideo-ctrl active' 425 | this.videoHeader.className = 'Dvideo-header active' 426 | if (disappearance) { 427 | this.hideTopBottomCtrl() 428 | } 429 | }, 430 | 431 | // 关闭上下菜单 immediately 是否立刻关闭 432 | hideTopBottomCtrl: function (immediately) { 433 | clearTimeout(this.showCtrlT) 434 | var _this = this 435 | if (immediately) { 436 | this.videoCtrl.className = 'Dvideo-ctrl' 437 | this.videoHeader.className = 'Dvideo-header' 438 | this.hideProgressRange() 439 | } else { 440 | // 隐藏控制栏 441 | this.showCtrlT = setTimeout(function () { 442 | _this.videoCtrl.className = 'Dvideo-ctrl' 443 | _this.videoHeader.className = 'Dvideo-header' 444 | _this.hideProgressRange() 445 | }, _this.opt.ctrSpeedDuration) 446 | } 447 | }, 448 | 449 | // 显示隐藏进度条小球 450 | showProgressRange: function () { 451 | this.videoProressC.className = 'Dvideo-progress-content active' 452 | }, 453 | 454 | hideProgressRange: function () { 455 | this.videoProressC.className = 'Dvideo-progress-content' 456 | }, 457 | 458 | videoPlay: function () { 459 | try{ 460 | this.videoEle.play(); 461 | this.isPlaying = true 462 | } catch (e) { 463 | console.log(e) 464 | } 465 | }, 466 | 467 | videoPause: function () { 468 | try{ 469 | this.videoEle.pause(); 470 | this.isPlaying = false 471 | console.log(this.isPlaying + '222222') 472 | } catch (e) { 473 | console.log(e) 474 | } 475 | }, 476 | 477 | videoPlayPause: function () { 478 | console.log(this.isPlaying + '--------------' ) 479 | if (this.isPlaying) { 480 | this.videoPause(); 481 | } else { 482 | this.videoPlay(); 483 | } 484 | }, 485 | 486 | showLoading: function (bool, text) { 487 | var text = text || '视频加载中,请稍等 或者切换稍低的清晰度' 488 | if (bool) { 489 | this.tipsInfo.innerText = text 490 | this.tipsInfo.className = 'Dvideo-tips-info' 491 | } else { 492 | this.tipsInfo.className = 'Dvideo-tips-info hide' 493 | } 494 | }, 495 | 496 | /** 497 | * 跳转到某一个位置 498 | */ 499 | videoSeek (seconds) { 500 | if (seconds > this.durationT) return 501 | if (this.videoEle.currentTime) { 502 | this.videoEle.currentTime = seconds 503 | this.updatePorgress() 504 | } 505 | }, 506 | 507 | // 快退 参数 退多少秒 508 | videoForward: function(seconds) { 509 | var sec = seconds || 10 510 | if (this.videoEle.currentTime) { 511 | this.currentT = this.currentT + sec > this.durationT ? this.durationT : this.currentT + sec 512 | this.videoEle.currentTime = this.currentT 513 | this.updatePorgress() 514 | } 515 | }, 516 | 517 | videoRewind: function (seconds) { 518 | var sec = seconds || 10 519 | if (this.videoEle.currentTime) { 520 | this.currentT = this.currentT - sec < 0 ? 0 : this.currentT - sec 521 | this.videoEle.currentTime = this.currentT 522 | this.updatePorgress() 523 | } 524 | }, 525 | 526 | // 快进 参数 进多少秒 527 | 528 | // 音乐初始化事件 529 | initEvent: function () { 530 | var _this = this 531 | 532 | // if (_this.browserV.indexOf('IE') >= 0) {} 533 | 534 | // 键盘事件 (ie 没有ctrl键) 535 | document.onkeydown = function (e) { 536 | var e = e || window.event 537 | if ((e.keyCode || e.which || e.charCode) === 32) { // 空格 暂停 538 | // console.log(e.ctrlKey + '------' + (e.keyCode || e.which || e.charCode)) 539 | e.stopPropagation(); 540 | e.preventDefault(); 541 | _this.videoPlayPause() 542 | } 543 | if ((e.keyCode || e.which || e.charCode) === 39) { // --> 快进 544 | e.stopPropagation(); 545 | e.preventDefault(); 546 | _this.showTopBottomCtrl() 547 | _this.videoForward(10) 548 | } 549 | if ((e.keyCode || e.which || e.charCode) === 37) { // <-- 快退 550 | e.stopPropagation(); 551 | e.preventDefault(); 552 | _this.showTopBottomCtrl() 553 | _this.videoRewind(10) 554 | } 555 | 556 | if ((e.keyCode || e.which || e.charCode) === 38) { // up 音量增加 557 | e.stopPropagation(); 558 | e.preventDefault(); 559 | _this.showTopBottomCtrl() 560 | _this.volume = _this.volume * 1 + 0.02 > 1 ? 1 : _this.volume * 1 + 0.02 561 | _this.setVolume() 562 | } 563 | 564 | if ((e.keyCode || e.which || e.charCode) === 40) { // down 音量降低 565 | e.stopPropagation(); 566 | e.preventDefault(); 567 | _this.showTopBottomCtrl() 568 | _this.volume = _this.volume * 1 - 0.02 < 0 ? 0 : _this.volume * 1 - 0.02 569 | _this.setVolume() 570 | } 571 | } 572 | 573 | // 添加监听是否改变窗口大小事件 574 | _this.screenChangeEvent() 575 | }, 576 | 577 | // playIng事件 578 | onPlaying: function () { 579 | this.opt.onPlaying(this.currentT) 580 | }, 581 | 582 | onPause: function () { 583 | this.opt.onPause() 584 | }, 585 | 586 | onLoadedMetaData: function () { 587 | this.opt.onLoadedMetaData() 588 | }, 589 | 590 | onTimeupdate: function () { 591 | this.opt.onTimeupdate(this.currentT) 592 | }, 593 | 594 | onEnded: function () { 595 | this.opt.onEnded() 596 | }, 597 | 598 | // 格式化时间 599 | formartTime: function (seconds) { 600 | var formatNumber = function (n) { 601 | n = n.toString() 602 | return n[1] ? n : '0' + n 603 | } 604 | var m = Math.floor(seconds / 60); 605 | var s = Math.floor(seconds % 60); 606 | return formatNumber(m) + ":" + formatNumber(s); 607 | }, 608 | 609 | // // initEvent 初始化事件 610 | // initEvent: function () { 611 | // var _this = this 612 | 613 | // _this.initVideoEvent() 614 | // }, 615 | setVideoDefinition: function (e) { 616 | // 显示提示信息 617 | this.showLoading(true, '视频清晰度切换中,请稍等') 618 | 619 | // 获取索引 以及清晰度类型 620 | var index = e.target.getAttribute('data-index') 621 | var type = e.target.getAttribute('data-type') 622 | 623 | this.currentT = this.videoEle.currentTime 624 | 625 | // this.videoEle.currentTime = this.currentT 626 | // this.videoPlay() 627 | 628 | this.opt.videoDefinition = { 629 | activeIndex: index, 630 | definitionList: this.opt.videoDefinition.definitionList 631 | } 632 | 633 | // 文本显示 634 | this.videoDefinitionText.title = this.opt.videoDefinition.definitionList[index].name 635 | this.videoDefinitionText.innerText = this.opt.videoDefinition.definitionList[index].name 636 | // 存储至本地 637 | this.setLStorage('D-videoDefinition', JSON.stringify(this.opt.videoDefinition)) 638 | 639 | // 设置列表active状态 640 | this.getDomByClass('Dvideo-definition-list active')[0].className = 'Dvideo-definition-list' 641 | e.target.className = 'Dvideo-definition-list active' 642 | this.videoDefinitionC.style.display = 'none' 643 | 644 | 645 | this.opt.setVideoDefinition(type, e, this.currentT) 646 | }, 647 | 648 | setVideoInfo: function(title, url, currentT) { 649 | var _this = this 650 | this.isLoadMate = false 651 | this.isPlaying = false 652 | // 地址 653 | this.videoEle.src = url || '', 654 | // title 655 | this.videoHeaderTitle.innerText = title || '这是一个title' 656 | this.videoHeaderTitle.title = title || '这是一个title' 657 | 658 | var loadProPlay = function () { 659 | if (_this.isLoadMate) { 660 | clearInterval(loadTime) 661 | _this.videoEle.currentTime = currentT || 0 662 | } 663 | _this.videoPlay(); 664 | } 665 | 666 | // 是否有currentT 667 | var loadTime = setInterval(function () { 668 | loadProPlay(); 669 | }, 500) 670 | 671 | }, 672 | 673 | setPlayBackRate: function (index) { 674 | this.playbackR = this.opt.playbackRate.rateList[index] 675 | this.videoEle.playbackRate = this.playbackR 676 | this.playbackRateText.title = this.playbackR.toFixed(1) + ' x' 677 | this.playbackRateText.innerText = this.playbackR.toFixed(1) + ' x' 678 | 679 | 680 | this.opt.playbackRate = { 681 | activeIndex: index, 682 | rateList: this.opt.playbackRate.rateList 683 | } 684 | // 存储至本地 685 | this.setLStorage('D-playbackRate', JSON.stringify(this.opt.playbackRate)) 686 | 687 | // 设置列表active状态 688 | this.getDomByClass('Dvideo-playbackRate-list active')[0].className = 'Dvideo-playbackRate-list' 689 | this.getDomByClass('Dvideo-playbackRate-list')[index].className = 'Dvideo-playbackRate-list active' 690 | this.playbackRateC.style.display = 'none' 691 | }, 692 | 693 | // 更新进度条位置 694 | updatePorgress: function (isDrag) { 695 | var isDrag = isDrag || false 696 | if (isDrag) { 697 | this.circleRange.style.left = this.dragProgressTo + 'px' 698 | this.realProress.style.width = this.dragProgressTo + 'px' 699 | var currentTime = Math.floor(this.dragProgressTo / this.maxProgressWidth * this.durationT) 700 | this.textCurrentT.innerText = this.formartTime(currentTime) 701 | } else { 702 | this.currentP = Number((this.currentT / this.durationT) * 100) 703 | this.currentP = this.currentP > 100 ? 100 : this.currentP 704 | this.realProress.style.width = this.currentP + '%' 705 | this.circleRange.style.left = this.currentP + '%' 706 | // 更改时间进度 707 | this.textCurrentT.innerText = this.formartTime(this.videoEle.currentTime) 708 | } 709 | }, 710 | 711 | // 下一集的点击事件 712 | nextVideo: function () { 713 | console.log('你点击了播放下一集 可使用实例化的对象调用nextVideo 方法实现播放下一集的效果') 714 | if (typeof this.opt.nextVideoExtend === 'function') this.opt.nextVideoExtend() 715 | }, 716 | 717 | // 设置音量大小 718 | setVolume: function () { 719 | // this.videoEle.volume = this.volume 720 | var persent = this.volume / 1 721 | this.updateVolume(persent) 722 | }, 723 | 724 | // 创建PlaybackRateList 725 | createPlaybackRateList: function () { 726 | var showVClassName = this.opt.showPlayBackRateUnFull ? '' : 'none' 727 | var oFragment = document.createDocumentFragment(); 728 | // 语速数据 729 | var playbackrateData = this.hasLStorage('D-playbackRate') ? JSON.parse(this.getLStorage('D-playbackRate')) : this.opt.playbackRate 730 | 731 | // 当前active索引 732 | var playbackrateIndex = Number(playbackrateData.activeIndex) 733 | 734 | // 当前语速 735 | var playbackR = Number(playbackrateData.rateList[playbackrateIndex]) 736 | 737 | 738 | // 设置语速区域 739 | this.playbackRate = document.createElement('span') 740 | this.playbackRate.className = 'Dvideo-playbackRate ' + showVClassName 741 | this.menuRightC.appendChild(this.playbackRate) 742 | 743 | // 显示语速文本 744 | this.playbackRateText = document.createElement('span') 745 | this.playbackRateText.className = 'Dvideo-playbackRateText' 746 | this.videoEle.playbackRate = playbackR 747 | this.playbackRateText.title = playbackR.toFixed(1) + ' x' 748 | this.playbackRateText.innerText = playbackR.toFixed(1) + ' x' 749 | this.playbackRate.appendChild(this.playbackRateText) 750 | 751 | // 语速选项的内容 752 | this.playbackRateC = document.createElement('div') 753 | this.playbackRateC.className = 'Dvideo-playbackRate-content' 754 | this.playbackRate.appendChild(this.playbackRateC) 755 | 756 | 757 | for (var i = 0; i < playbackrateData.rateList.length; i++) { 758 | var playbackRateL = document.createElement('span') 759 | if (i === playbackrateIndex) { 760 | playbackRateL.className = 'Dvideo-playbackRate-list active' 761 | } else { 762 | playbackRateL.className = 'Dvideo-playbackRate-list' 763 | } 764 | playbackRateL.title = playbackrateData.rateList[i].toFixed(1) + 'x' 765 | playbackRateL.innerText = playbackrateData.rateList[i].toFixed(1) + 'x' 766 | playbackRateL.setAttribute('data-index', i) 767 | oFragment.appendChild(playbackRateL) 768 | } 769 | this.playbackRateC.appendChild(oFragment) 770 | 771 | var _this = this 772 | 773 | // ====================设置语速交互 774 | _this.playbackRate.onmouseenter = function (event) { 775 | _this.playbackRateC.style.display = 'block' 776 | } 777 | 778 | _this.playbackRate.onmouseleave = function (event) { 779 | _this.playbackRateC.style.display = 'none' 780 | } 781 | 782 | _this.playbackRateC.onclick = function (event) { 783 | var e = event || window.event 784 | var index = e.target.getAttribute('data-index') 785 | _this.setPlayBackRate(index) 786 | } 787 | }, 788 | 789 | // 创建currentduration 790 | createCurrentDurationText: function () { 791 | var oFragment = document.createDocumentFragment(); 792 | // 显示当前时间和总时长 区域 793 | this.textVideoTimeC = document.createElement('div') 794 | this.textVideoTimeC.className = 'Dvideo-time-content' 795 | this.videoCtrlDetail.appendChild(this.textVideoTimeC) 796 | 797 | // 显示当前秒数 798 | this.textCurrentT = document.createElement('span') 799 | this.textCurrentT.className = 'Dvideo-text-current' 800 | this.textCurrentT.innerText = '--:-- ' 801 | oFragment.appendChild(this.textCurrentT) 802 | 803 | // 显示时长 804 | this.textDurationT = document.createElement('span') 805 | this.textDurationT.className = 'Dvideo-text-duration' 806 | this.textDurationT.innerText = ' --:--' 807 | oFragment.appendChild(this.textDurationT) 808 | this.textVideoTimeC.appendChild(oFragment) 809 | }, 810 | 811 | // pc 端进度条 812 | createPcProgress: function () { 813 | // 进度条区域 814 | this.videoProressC = document.createElement('div') 815 | this.videoProressC.className = 'Dvideo-progress-content' 816 | this.videoCtrl.appendChild(this.videoProressC) 817 | 818 | // 进度条内容 (包涵进度条和缓冲条) videoProressDetail 819 | this.videoProressD = document.createElement('div') 820 | this.videoProressD.className = 'Dvideo-progress-detail' 821 | this.videoProressC.appendChild(this.videoProressD) 822 | 823 | // 缓冲条 824 | this.bufferedProress = document.createElement('div') 825 | this.bufferedProress.className = 'Dvideo-progress-buffered' 826 | this.videoProressD.appendChild(this.bufferedProress) 827 | 828 | // 播放进度条 829 | this.realProress = document.createElement('div') 830 | this.realProress.className = 'Dvideo-progress-real' 831 | this.videoProressD.appendChild(this.realProress) 832 | 833 | // 播放进度条圆形按钮 834 | this.circleRange = document.createElement('span') 835 | this.circleRange.className = 'Dvideo-circle-range' 836 | this.videoProressC.appendChild(this.circleRange) 837 | 838 | var _this = this 839 | 840 | // 点击进度条跳转 841 | _this.videoProressD.onclick = function (event) { 842 | // var e = event || window.event 843 | // var l = e.layerX 844 | // var w = _this.videoProressD.offsetWidth 845 | 846 | // _this.videoEle.currentTime = Math.floor(l / w * _this.durationT) 847 | // _this.currentT = _this.videoEle.currentTime 848 | // _this.updatePorgress() 849 | var e = event || window.event 850 | // alert(e.target.offsetLeft) 851 | var videoProgressCW = _this.videoProressD.offsetWidth 852 | var eW = e.offsetX 853 | _this.videoEle.currentTime = _this.currentT = Math.floor(eW / videoProgressCW * _this.durationT) 854 | _this.updatePorgress() 855 | } 856 | 857 | // 进度条拖动 (PC) 858 | _this.circleRange.onmousedown = function (event) { 859 | _this.isDrag = true 860 | var e = event || window.event 861 | var x = e.clientX 862 | var l = event.target.offsetLeft + 7 863 | e.stopPropagation() 864 | _this.maxProgressWidth = _this.videoProressD.offsetWidth 865 | _this.videoCtrl.onmousemove = function (event) { 866 | var e = event || window.event 867 | if (_this.isDrag) { 868 | var thisX = e.clientX 869 | _this.dragProgressTo = Math.min(_this.maxProgressWidth, Math.max(0, l + (thisX - x))) 870 | // update Time 871 | _this.updatePorgress(true) 872 | } 873 | } 874 | _this.videoCtrl.onmouseup = function (event) { 875 | var e = event || window.event 876 | e.stopPropagation() 877 | if (_this.isDrag) { 878 | _this.isDrag = false 879 | _this.videoEle.currentTime = Math.floor(_this.dragProgressTo / _this.maxProgressWidth * _this.durationT) 880 | } else { 881 | return 882 | } 883 | } 884 | 885 | _this.videoCtrl.onmouseleave = function (event) { 886 | var e = event || window.event 887 | e.stopPropagation() 888 | if (_this.isDrag) { 889 | _this.isDrag = false 890 | _this.videoEle.currentTime = Math.floor(_this.dragProgressTo / _this.maxProgressWidth * _this.durationT) 891 | } else { 892 | return 893 | } 894 | 895 | _this.hideTopBottomCtrl() 896 | } 897 | } 898 | }, 899 | 900 | // 创建视频 901 | createVideoEle: function () { 902 | this.videoEle = document.createElement('video') 903 | this.videoEle.className = 'Dvideo-ele' 904 | this.videoEle.src = this.opt.src 905 | this.videoEle.loop = this.opt.loop 906 | this.videoEle.autoplay = this.opt.autoplay 907 | this.videoEle.poster = this.opt.poster 908 | this.videoC.appendChild(this.videoEle) 909 | 910 | var _this = this 911 | 912 | // 视频事件 913 | _this.videoEle.onloadstart = function () { 914 | _this.showLoading(true, '视频加载中,请稍等') 915 | }, 916 | 917 | _this.videoEle.oncanplay = function () { 918 | _this.showLoading(false) 919 | }, 920 | 921 | _this.videoEle.onplaying = function () { 922 | _this.isPlaying = true 923 | _this.videoPlayPauseI.className = 'Dvideo-ctrl-playPause icon-pause' 924 | _this.videoPlayPauseI.title = '暂停 space' 925 | var date = new Date () 926 | _this.reduceTBefore = Date.parse(date) - Math.floor(_this.videoEle.currentTime * 1000) 927 | _this.showLoading(false) 928 | _this.onPlaying() 929 | }, 930 | _this.videoEle.onpause = function () { 931 | _this.isPlaying = false 932 | _this.videoPlayPauseI.className = 'Dvideo-ctrl-playPause icon-play' 933 | _this.videoPlayPauseI.title = '播放 space' 934 | _this.onPause() 935 | }, 936 | 937 | // 视频元数据 (时长 尺寸 以及文本轨道) 938 | _this.videoEle.onloadedmetadata = function () { 939 | _this.isLoadMate = true 940 | _this.durationT = _this.videoEle.duration 941 | // 初始化视频时间 942 | _this.textDurationT.innerText = _this.formartTime(_this.durationT) 943 | _this.onLoadedMetaData() 944 | }, 945 | 946 | // 绑定进度条 947 | _this.videoEle.ontimeupdate = function () { 948 | if (!_this.isDrag) { 949 | _this.currentT = _this.videoEle.currentTime 950 | _this.updatePorgress() 951 | var date = new Date () 952 | _this.reduceTBefore = Date.parse(date) - Math.floor(_this.currentT * 1000) 953 | } 954 | // console.log(2) 955 | _this.onTimeupdate() 956 | }, 957 | _this.videoEle.onprogress = function () { 958 | if(_this.videoEle.buffered.length > 0) { 959 | var bufferedT = 0 960 | for (var i = 0; i < _this.videoEle.buffered.length; i++) { 961 | bufferedT += _this.videoEle.buffered.end(i) - _this.videoEle.buffered.start(i) 962 | if(bufferedT > _this.durationT) { 963 | bufferedT = _this.durationT 964 | console.log('缓冲完成') 965 | } 966 | } 967 | var bufferedP = Math.floor((bufferedT / _this.durationT) * 100) 968 | _this.bufferedProress.style.width = bufferedP + '%' 969 | } else { 970 | console.log('未缓冲') 971 | } 972 | 973 | var date = new Date () 974 | // console.log(_this.reduceTAfter + '-------------------------' + _this.reduceTBefore) 975 | if(!_this.videoEle.paused) { 976 | _this.reduceTAfter = Date.parse(date) - Math.floor(_this.currentT * 1000) 977 | console.log(_this.reduceTAfter) 978 | if(_this.reduceTAfter - _this.reduceTBefore > 1000) { 979 | _this.showLoading(true) 980 | } else { 981 | _this.showLoading(false) 982 | } 983 | } else { 984 | return 985 | } 986 | } 987 | 988 | _this.videoEle.onended = function () { 989 | _this.onEnded(); 990 | } 991 | 992 | _this.videoEle.onwaiting = function () { 993 | _this.showLoading(true, '视频加载中,请稍等') 994 | } 995 | }, 996 | 997 | createVideoC: function () { 998 | // video content 999 | this.videoC = document.createElement('div') 1000 | this.videoC.className = 'Dvideo-content' 1001 | this.opt.ele.appendChild(this.videoC) 1002 | 1003 | var _this = this 1004 | // 鼠标事件 移动显示菜单 1005 | _this.videoC.onmousemove = function () { 1006 | _this.showTopBottomCtrl(true) 1007 | } 1008 | 1009 | // 界面点击播放暂停 1010 | var startTime = 0; 1011 | _this.videoC.onclick = function () { 1012 | var date = (new Date()).valueOf(); 1013 | // > 1秒是播放暂停的操作 1014 | if (date - startTime > 500) { 1015 | if (_this.isPlaying) { 1016 | _this.videoPause() 1017 | } else { 1018 | _this.videoPlay() 1019 | } 1020 | } else { 1021 | // 否则就是全屏的操作 1022 | if (_this.isFull) { 1023 | _this.exitFullscreen() 1024 | } else { 1025 | _this.launchFullScreen(_this.opt.ele) 1026 | } 1027 | } 1028 | startTime = date 1029 | } 1030 | }, 1031 | 1032 | createCtrlC: function () { 1033 | // 底部控制条 1034 | this.videoCtrl = document.createElement('div') 1035 | this.videoCtrl.className = 'Dvideo-ctrl' 1036 | this.videoC.appendChild(this.videoCtrl) 1037 | 1038 | //除底部进度条信息之外 底部的所有内容 1039 | this.videoCtrlDetail = document.createElement('div') 1040 | this.videoCtrlDetail.className = 'Dvideo-detail' 1041 | this.videoCtrl.appendChild(this.videoCtrlDetail) 1042 | 1043 | var _this = this 1044 | // 移动显示粗的进度条 1045 | _this.videoCtrl.onmouseenter = function () { 1046 | _this.showProgressRange() 1047 | } 1048 | // 关闭两个菜单控制栏的冒泡事件 1049 | _this.videoCtrl.onclick = function (e) { 1050 | e.stopPropagation(); 1051 | } 1052 | }, 1053 | 1054 | createHeaderC: function () { 1055 | // 头部的信息 1056 | this.videoHeader = document.createElement('div') 1057 | this.videoHeader.className = 'Dvideo-header' 1058 | this.videoC.appendChild(this.videoHeader) 1059 | // 头部的title 1060 | this.videoHeaderTitle = document.createElement('p') 1061 | this.videoHeaderTitle.className = 'Dvideo-header-title' 1062 | this.videoHeaderTitle.innerText = this.opt.title 1063 | this.videoHeaderTitle.title = this.opt.title 1064 | this.videoHeader.appendChild(this.videoHeaderTitle) 1065 | 1066 | var _this = this 1067 | 1068 | // 关闭两个菜单控制栏的冒泡事件 1069 | _this.videoHeader.onclick = function (e) { 1070 | e.stopPropagation(); 1071 | } 1072 | 1073 | }, 1074 | 1075 | // 放大缩小 1076 | createSelectVideoFull: function () { 1077 | // 放大缩小功能 1078 | var iconFullScreenITitle = this.isFull ? '全屏' : '取消全屏' 1079 | this.fullscreenConfig = document.createElement('i') 1080 | this.fullscreenConfig.className = 'Dvideo-menu-fullscreenConfig icon-fullscreen' 1081 | this.fullscreenConfig.title = iconFullScreenITitle 1082 | this.menuRightC.appendChild(this.fullscreenConfig) 1083 | // 初始全屏效果 1084 | this.updateFullScreenState(this.isFull) 1085 | 1086 | var _this = this 1087 | // 点击切换全屏与非全屏状态 1088 | _this.fullscreenConfig.onclick = function () { 1089 | if (_this.isFull) { 1090 | _this.exitFullscreen() 1091 | } else { 1092 | _this.launchFullScreen(_this.opt.ele) 1093 | } 1094 | } 1095 | }, 1096 | 1097 | // 播放暂停包括下一集 1098 | createvideoPlayState: function () { 1099 | this.videoCtrlStateC = document.createElement('div') 1100 | this.videoCtrlStateC.className = 'Dvideo-ctrl-state' 1101 | this.videoCtrlDetail.appendChild(this.videoCtrlStateC) 1102 | 1103 | // 播放按钮 1104 | var iconPlayPauseClass = this.isPlaying ? 'icon-pause' : 'icon-play' 1105 | var iconPlayPauseITitle = this.isPlaying ? '暂停 space' : '播放 space' 1106 | this.videoPlayPauseI = document.createElement('i') 1107 | this.videoPlayPauseI.className = 'Dvideo-ctrl-playPause ' + iconPlayPauseClass 1108 | this.videoPlayPauseI.title = iconPlayPauseITitle 1109 | this.videoCtrlStateC.appendChild(this.videoPlayPauseI) 1110 | 1111 | // 下一集控制区域 1112 | var displayStyle = this.opt.showNext ? 'inline-block' : 'none' 1113 | this.videoNextI = document.createElement('i') 1114 | this.videoNextI.className = 'Dvideo-ctrl-next icon-nextdetail' 1115 | this.videoNextI.title = '下一集 next' 1116 | this.videoNextI.style.display = displayStyle 1117 | this.videoCtrlStateC.appendChild(this.videoNextI) 1118 | 1119 | var _this = this 1120 | // 播放下一集 1121 | _this.videoNextI.onclick = function () { 1122 | _this.nextVideo () 1123 | } 1124 | 1125 | // 播放暂停按钮 1126 | _this.videoPlayPauseI.onclick = function () { 1127 | if (_this.isPlaying) { 1128 | _this.videoPause() 1129 | } else { 1130 | _this.videoPlay() 1131 | } 1132 | } 1133 | }, 1134 | 1135 | // 创建提示信息 1136 | createVideoTips: function () { 1137 | this.tipsInfo = document.createElement('div') 1138 | this.tipsInfo.className = 'Dvideo-tips-info' 1139 | this.videoCtrl.appendChild(this.tipsInfo) 1140 | }, 1141 | 1142 | // 创建切换视频清晰度效果 1143 | createVideoDefinition: function () { 1144 | var showVClassName = this.opt.showVideoDefinitionUnFull ? '' : 'none' 1145 | var oFragment = document.createDocumentFragment(); 1146 | // 获取的数据 本地存储或者初始化的清晰度 1147 | var videoDefinitionData = this.hasLStorage('D-videoDefinition') ? JSON.parse(this.getLStorage('D-videoDefinition')) : this.opt.videoDefinition 1148 | // active索引 1149 | var videoDefinitionIndex = Number(videoDefinitionData.activeIndex) 1150 | // active类型 0 标清 1 高清 2 超清 1151 | var videoDefinitionType = videoDefinitionData.definitionList[videoDefinitionIndex].type 1152 | // active名字 0 标清 1 高清 2 超清 1153 | var videoDefinitionName = videoDefinitionData.definitionList[videoDefinitionIndex].name 1154 | 1155 | // 设置清晰度区域 1156 | this.videoDefinition = document.createElement('span') 1157 | this.videoDefinition.className = 'Dvideo-definition ' + showVClassName 1158 | this.menuRightC.appendChild(this.videoDefinition) 1159 | 1160 | // 显示清晰度文本 1161 | this.videoDefinitionText = document.createElement('span') 1162 | this.videoDefinitionText.className = 'Dvideo-definitionText' 1163 | this.videoDefinitionText.title = videoDefinitionName 1164 | this.videoDefinitionText.innerText = videoDefinitionName 1165 | this.videoDefinition.appendChild(this.videoDefinitionText) 1166 | 1167 | // 清晰度选项的内容 1168 | this.videoDefinitionC = document.createElement('div') 1169 | this.videoDefinitionC.className = 'Dvideo-definition-content' 1170 | this.videoDefinition.appendChild(this.videoDefinitionC) 1171 | 1172 | 1173 | for (var i = 0; i < videoDefinitionData.definitionList.length; i++) { 1174 | var videoDefinitionL = document.createElement('span') 1175 | if (i === videoDefinitionIndex) { 1176 | videoDefinitionL.className = 'Dvideo-definition-list active' 1177 | } else { 1178 | videoDefinitionL.className = 'Dvideo-definition-list' 1179 | } 1180 | videoDefinitionL.title = videoDefinitionData.definitionList[i].name 1181 | videoDefinitionL.innerText = videoDefinitionData.definitionList[i].name 1182 | videoDefinitionL.setAttribute('data-index', i) 1183 | videoDefinitionL.setAttribute('data-type', videoDefinitionData.definitionList[i].type) 1184 | oFragment.appendChild(videoDefinitionL) 1185 | } 1186 | this.videoDefinitionC.appendChild(oFragment) 1187 | 1188 | var _this = this 1189 | 1190 | // ====================设置语速交互 1191 | _this.videoDefinition.onmouseenter = function (event) { 1192 | _this.videoDefinitionC.style.display = 'block' 1193 | } 1194 | 1195 | _this.videoDefinition.onmouseleave = function (event) { 1196 | _this.videoDefinitionC.style.display = 'none' 1197 | } 1198 | 1199 | _this.videoDefinition.onclick = function (event) { 1200 | var e = event || window.event 1201 | _this.setVideoDefinition(e) 1202 | } 1203 | }, 1204 | 1205 | // 创建设置音量的效果 1206 | createVolume: function () { 1207 | var showVClassName = this.opt.showVolumeUnFull ? '' : 'none' 1208 | // 设置清晰度区域 1209 | this.videoVolumeC = document.createElement('div') 1210 | this.videoVolumeC.className = 'Dvideo-volume ' + showVClassName 1211 | this.menuRightC.appendChild(this.videoVolumeC) 1212 | 1213 | // 进度线条 1214 | this.videoVolumeP = document.createElement('div') 1215 | this.videoVolumeP.className = 'Dvideo-volume-P' 1216 | this.videoVolumeC.appendChild(this.videoVolumeP) 1217 | 1218 | // 事实的进度信息 1219 | this.videoVolumeR = document.createElement('div') 1220 | this.videoVolumeR.className = 'Dvideo-volume-R' 1221 | this.videoVolumeP.appendChild(this.videoVolumeR) 1222 | 1223 | // 可拖动的小圆点 1224 | this.videoVolumeRange = document.createElement('div') 1225 | this.videoVolumeRange.className = 'Dvideo-volume-range' 1226 | this.videoVolumeC.appendChild(this.videoVolumeRange) 1227 | 1228 | // 初始化音量 有本地存储 设置过就使用本地存储 1229 | this.initVolume (); 1230 | 1231 | var isDrag = false 1232 | 1233 | var _this = this 1234 | var persent = 0 1235 | // 进度条拖动 (PC) 1236 | _this.videoVolumeRange.onmousedown = function (event) { 1237 | isDrag = true 1238 | var e = event || window.event 1239 | var x = e.clientX 1240 | var l = event.target.offsetLeft + 6 1241 | e.stopPropagation() 1242 | _this.maxVolumeWidth = _this.videoVolumeC.offsetWidth 1243 | 1244 | _this.videoVolumeC.onmousemove = function (event) { 1245 | if(isDrag) { 1246 | var e = event || window.event 1247 | var thisX = e.clientX 1248 | _this.dragVolumeTo = Math.min(_this.maxVolumeWidth, Math.max(0, l + (thisX - x))) 1249 | persent = _this.dragVolumeTo / _this.maxVolumeWidth 1250 | _this.updateVolume(persent); 1251 | } 1252 | } 1253 | 1254 | _this.videoVolumeC.onmouseup = function (event) { 1255 | isDrag = false 1256 | e.stopPropagation() 1257 | e.preventDefault() 1258 | // 本地存储 1259 | _this.setLStorage('Dvideo-volume', persent) 1260 | return 1261 | } 1262 | 1263 | _this.videoVolumeC.onmouseleave = function (event) { 1264 | isDrag = false 1265 | e.stopPropagation() 1266 | e.preventDefault() 1267 | // 本地存储 1268 | _this.setLStorage('Dvideo-volume', persent) 1269 | return 1270 | } 1271 | } 1272 | 1273 | _this.videoVolumeP.onclick = function (event) { 1274 | var e = event || window.event 1275 | // alert(e.target.offsetLeft) 1276 | var videoVolumeCW = _this.videoVolumeP.offsetWidth 1277 | var eW = e.offsetX 1278 | // console.log(videoVolumeCW) 1279 | _this.updateVolume(eW / videoVolumeCW); 1280 | } 1281 | }, 1282 | 1283 | // 更新音量界面显示以及音量调整 1284 | updateVolume: function (persent) { 1285 | this.videoVolumeRange.style.left = persent * 100 + '%' 1286 | this.videoVolumeR.style.width = persent * 100 + '%' 1287 | this.videoVolumeRange.setAttribute('data-volume', Math.round(persent * 100)) 1288 | this.volume = persent 1289 | this.videoEle.volume = persent 1290 | // 本地存储 1291 | this.setLStorage('Dvideo-volume', persent) 1292 | }, 1293 | 1294 | // 初始化音量 1295 | initVolume: function () { 1296 | if(this.getLStorage('Dvideo-volume') === null) { 1297 | this.updateVolume(0.8) 1298 | this.volume = 0.8 1299 | } else { 1300 | var persent = this.getLStorage('Dvideo-volume') 1301 | this.updateVolume(persent) 1302 | this.volume = persent 1303 | } 1304 | }, 1305 | 1306 | // 根据class查找元素 1307 | getDomByClass: function(classInfo) { 1308 | var classInfo = classInfo || ''; 1309 | if(!typeof(document.getElementsByClassName) === 'function'){ 1310 | var result=[]; 1311 | var aEle=document.getElementsByTagName('*'); 1312 | /*正则模式*/ 1313 | var re=new RegExp("\\b" + classInfo + "\\b","g"); 1314 | for(var i=0;i 2 | 3 | 4 | 5 | Dvideo 6 | 7 | 76 | 77 | 78 |
79 |
80 |
81 | 点击全屏 82 | 播放 space 83 | 暂停 space 84 | 播放暂停 85 | 100的音量大小 up 86 | 30的音量大小 down 87 | 2.0的语速 88 | 正常的语速 89 | 快退 left 90 | 快进 right 91 | 显示进度信息 92 | 关闭进度信息 93 | 显示上下菜单且不自动关闭 94 | 立刻关闭上下菜单 95 | 显示菜单自动关闭 96 | 固定时间后自动关闭 97 | 设置宽720 高480 98 |
99 | 101 | github: https://github.com/IFmiss/Dvideo.js 102 | 103 |
104 | 105 | -------------------------------------------------------------------------------- /lib/d-video.js: -------------------------------------------------------------------------------- 1 | !function(e,t){"object"==typeof exports&&"object"==typeof module?module.exports=t():"function"==typeof define&&define.amd?define("d-video",[],t):"object"==typeof exports?exports["d-video"]=t():e["d-video"]=t()}(window,function(){return function(e){var t={};function i(o){if(t[o])return t[o].exports;var n=t[o]={i:o,l:!1,exports:{}};return e[o].call(n.exports,n,n.exports,i),n.l=!0,n.exports}return i.m=e,i.c=t,i.d=function(e,t,o){i.o(e,t)||Object.defineProperty(e,t,{configurable:!1,enumerable:!0,get:o})},i.r=function(e){Object.defineProperty(e,"__esModule",{value:!0})},i.n=function(e){var t=e&&e.__esModule?function(){return e.default}:function(){return e};return i.d(t,"a",t),t},i.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},i.p="",i(i.s=0)}({0:function(e,t,i){"use strict";Object.defineProperty(t,"__esModule",{value:!0});var o="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e},n=function(){function e(e,t){for(var i=0;i1&&void 0!==arguments[1]?arguments[1]:"视频加载中,请稍等 或者切换稍低的清晰度";e?(this.tipsInfo.innerText=t,this.tipsInfo.className="Dvideo-tips-info"):this.tipsInfo.className="Dvideo-tips-info hide"}},{key:"videoForward",value:function(e){this.videoEle.currentTime&&(this.currentT=this.currentT+10>this.durationT?this.durationT:this.currentT+10,this.videoEle.currentTime=this.currentT,this.updatePorgress())}},{key:"videoRewind",value:function(e){this.videoEle.currentTime&&(this.currentT=this.currentT-10<0?0:this.currentT-10,this.videoEle.currentTime=this.currentT,this.updatePorgress())}},{key:"initEvent",value:function(){var e=this;document.onkeydown=function(t){var i=t||window.event;32===(i.keyCode||i.which||i.charCode)&&(i.stopPropagation(),i.preventDefault(),e.videoPlayPause()),39===(i.keyCode||i.which||i.charCode)&&(i.stopPropagation(),i.preventDefault(),e.showTopBottomCtrl(),e.videoForward(10)),37===(i.keyCode||i.which||i.charCode)&&(i.stopPropagation(),i.preventDefault(),e.showTopBottomCtrl(),e.videoRewind(10)),38===(i.keyCode||i.which||i.charCode)&&(i.stopPropagation(),i.preventDefault(),e.showTopBottomCtrl(),e.volume=1*e.volume+.02>1?1:1*e.volume+.02,e.setVolume()),40===(i.keyCode||i.which||i.charCode)&&(i.stopPropagation(),i.preventDefault(),e.showTopBottomCtrl(),e.volume=1*e.volume-.02<0?0:1*e.volume-.02,e.setVolume())},e.screenChangeEvent()}},{key:"onPlaying",value:function(){this.opt.onPlaying(this.currentT)}},{key:"onPause",value:function(){this.opt.onPause()}},{key:"onLoadedMetaData",value:function(){this.opt.onLoadedMetaData()}},{key:"onTimeupdate",value:function(){this.opt.onTimeupdate(this.currentT)}},{key:"onEnded",value:function(){this.opt.onEnded()}},{key:"formartTime",value:function(e){var t=function(e){return(e=e.toString())[1]?e:"0"+e},i=Math.floor(e/60),o=Math.floor(e%60);return t(i)+":"+t(o)}},{key:"setVideoDefinition",value:function(e){this.showLoading(!0,"视频清晰度切换中,请稍等");var t=e.target.getAttribute("data-index"),i=e.target.getAttribute("data-type");this.currentT=this.videoEle.currentTime,this.opt.videoDefinition={activeIndex:t,definitionList:this.opt.videoDefinition.definitionList},this.videoDefinitionText.title=this.opt.videoDefinition.definitionList[t].name,this.videoDefinitionText.innerText=this.opt.videoDefinition.definitionList[t].name,this.setLStorage("D-videoDefinition",JSON.stringify(this.opt.videoDefinition)),this.getDomByClass("Dvideo-definition-list active")[0].className="Dvideo-definition-list",e.target.className="Dvideo-definition-list active",this.videoDefinitionC.style.display="none",this.opt.setVideoDefinition(i,e,this.currentT)}},{key:"setVideoInfo",value:function(e,t,i){var o=this;this.isLoadMate=!1,this.isPlaying=!1,this.videoEle.src=t||"",this.videoHeaderTitle.innerText=e||"这是一个title",this.videoHeaderTitle.title=e||"这是一个title";var n=setInterval(function(){o.isLoadMate&&(clearInterval(n),o.videoEle.currentTime=i||0),o.videoPlay()},500)}},{key:"setPlayBackRate",value:function(e){this.playbackR=this.opt.playbackRate.rateList[e],this.videoEle.playbackRate=this.playbackR,this.playbackRateText.title=this.playbackR.toFixed(1)+" x",this.playbackRateText.innerText=this.playbackR.toFixed(1)+" x",this.opt.playbackRate={activeIndex:e,rateList:this.opt.playbackRate.rateList},this.setLStorage("D-playbackRate",JSON.stringify(this.opt.playbackRate)),this.getDomByClass("Dvideo-playbackRate-list active")[0].className="Dvideo-playbackRate-list",this.getDomByClass("Dvideo-playbackRate-list")[e].className="Dvideo-playbackRate-list active",this.playbackRateC.style.display="none"}},{key:"updatePorgress",value:function(){if(arguments.length>0&&void 0!==arguments[0]&&arguments[0]){this.circleRange.style.left=this.dragProgressTo+"px",this.realProress.style.width=this.dragProgressTo+"px";var e=Math.floor(this.dragProgressTo/this.maxProgressWidth*this.durationT);this.textCurrentT.innerText=this.formartTime(e)}else this.currentP=Number(this.currentT/this.durationT*100),this.currentP=this.currentP>100?100:this.currentP,this.realProress.style.width=this.currentP+"%",this.circleRange.style.left=this.currentP+"%",this.textCurrentT.innerText=this.formartTime(this.videoEle.currentTime)}},{key:"nextVideo",value:function(){console.log("你点击了播放下一集 可使用实例化的对象调用nextVideo 方法实现播放下一集的效果"),"function"==typeof this.opt.nextVideoExtend&&this.opt.nextVideoExtend()}},{key:"setVolume",value:function(){var e=this.volume/1;this.updateVolume(e)}},{key:"createPlaybackRateList",value:function(){var e=this.opt.showPlayBackRateUnFull?"":"none",t=document.createDocumentFragment(),i=this.hasLStorage("D-playbackRate")?JSON.parse(this.getLStorage("D-playbackRate")):this.opt.playbackRate,o=Number(i.activeIndex),n=Number(i.rateList[o]);this.playbackRate=document.createElement("span"),this.playbackRate.className="Dvideo-playbackRate "+e,this.menuRightC.appendChild(this.playbackRate),this.playbackRateText=document.createElement("span"),this.playbackRateText.className="Dvideo-playbackRateText",this.videoEle.playbackRate=n,this.playbackRateText.title=n.toFixed(1)+" x",this.playbackRateText.innerText=n.toFixed(1)+" x",this.playbackRate.appendChild(this.playbackRateText),this.playbackRateC=document.createElement("div"),this.playbackRateC.className="Dvideo-playbackRate-content",this.playbackRate.appendChild(this.playbackRateC);for(var s=0;s0){for(var t=0,i=0;ie.durationT&&(t=e.durationT,console.log("缓冲完成"));var o=Math.floor(t/e.durationT*100);e.bufferedProress.style.width=o+"%"}else console.log("未缓冲");var n=new Date;e.videoEle.paused||(e.reduceTAfter=Date.parse(n)-Math.floor(1e3*e.currentT),console.log(e.reduceTAfter),e.reduceTAfter-e.reduceTBefore>1e3?e.showLoading(!0):e.showLoading(!1))},e.videoEle.onended=function(){e.onEnded()},e.videoEle.onwaiting=function(){e.showLoading(!0,"视频加载中,请稍等")}}},{key:"createVideoC",value:function(){this.videoC=document.createElement("div"),this.videoC.className="Dvideo-content",this.opt.ele.appendChild(this.videoC);var e=this;e.videoC.onmousemove=function(){e.showTopBottomCtrl(!0)};var t=0;e.videoC.onclick=function(){var i=(new Date).valueOf();i-t>500?e.isPlaying?e.videoPause():e.videoPlay():e.isFull?e.exitFullscreen():e.launchFullScreen(e.opt.ele),t=i}}},{key:"createCtrlC",value:function(){this.videoCtrl=document.createElement("div"),this.videoCtrl.className="Dvideo-ctrl",this.videoC.appendChild(this.videoCtrl),this.videoCtrlDetail=document.createElement("div"),this.videoCtrlDetail.className="Dvideo-detail",this.videoCtrl.appendChild(this.videoCtrlDetail);var e=this;e.videoCtrl.onmouseenter=function(){e.showProgressRange()},e.videoCtrl.onclick=function(e){e.stopPropagation()}}},{key:"createHeaderC",value:function(){this.videoHeader=document.createElement("div"),this.videoHeader.className="Dvideo-header",this.videoC.appendChild(this.videoHeader),this.videoHeaderTitle=document.createElement("p"),this.videoHeaderTitle.className="Dvideo-header-title",this.videoHeaderTitle.innerText=this.opt.title,this.videoHeaderTitle.title=this.opt.title,this.videoHeader.appendChild(this.videoHeaderTitle);this.videoHeader.onclick=function(e){e.stopPropagation()}}},{key:"createSelectVideoFull",value:function(){var e=this.isFull?"全屏":"取消全屏";this.fullscreenConfig=document.createElement("i"),this.fullscreenConfig.className="Dvideo-menu-fullscreenConfig icon-fullscreen",this.fullscreenConfig.title=e,this.menuRightC.appendChild(this.fullscreenConfig),this.updateFullScreenState(this.isFull);var t=this;t.fullscreenConfig.onclick=function(){t.isFull?t.exitFullscreen():t.launchFullScreen(t.opt.ele)}}},{key:"createvideoPlayState",value:function(){this.videoCtrlStateC=document.createElement("div"),this.videoCtrlStateC.className="Dvideo-ctrl-state",this.videoCtrlDetail.appendChild(this.videoCtrlStateC);var e=this.isPlaying?"icon-pause":"icon-play",t=this.isPlaying?"暂停 space":"播放 space";this.videoPlayPauseI=document.createElement("i"),this.videoPlayPauseI.className="Dvideo-ctrl-playPause "+e,this.videoPlayPauseI.title=t,this.videoCtrlStateC.appendChild(this.videoPlayPauseI);var i=this.opt.showNext?"inline-block":"none";this.videoNextI=document.createElement("i"),this.videoNextI.className="Dvideo-ctrl-next icon-nextdetail",this.videoNextI.title="下一集 next",this.videoNextI.style.display=i,this.videoCtrlStateC.appendChild(this.videoNextI);var o=this;o.videoNextI.onclick=function(){o.nextVideo()},o.videoPlayPauseI.onclick=function(){o.isPlaying?o.videoPause():o.videoPlay()}}},{key:"createVideoTips",value:function(){this.tipsInfo=document.createElement("div"),this.tipsInfo.className="Dvideo-tips-info",this.videoCtrl.appendChild(this.tipsInfo)}},{key:"createVideoDefinition",value:function(){var e=this.opt.showVideoDefinitionUnFull?"":"none",t=document.createDocumentFragment(),i=this.hasLStorage("D-videoDefinition")?JSON.parse(this.getLStorage("D-videoDefinition")):this.opt.videoDefinition,o=Number(i.activeIndex),n=(i.definitionList[o].type,i.definitionList[o].name);this.videoDefinition=document.createElement("span"),this.videoDefinition.className="Dvideo-definition "+e,this.menuRightC.appendChild(this.videoDefinition),this.videoDefinitionText=document.createElement("span"),this.videoDefinitionText.className="Dvideo-definitionText",this.videoDefinitionText.title=n,this.videoDefinitionText.innerText=n,this.videoDefinition.appendChild(this.videoDefinitionText),this.videoDefinitionC=document.createElement("div"),this.videoDefinitionC.className="Dvideo-definition-content",this.videoDefinition.appendChild(this.videoDefinitionC);for(var s=0;s0&&void 0!==arguments[0]?arguments[0]:"";if("function"===!o(document.getElementsByClassName)){for(var t=[],i=document.getElementsByTagName("*"),n=new RegExp("\\b"+e+"\\b","g"),s=0;s 2 | 3 | 4 | 5 | Dvideo 6 | 7 | 76 | 77 | 78 |
79 |
80 |
81 | 点击全屏 82 | 播放 space 83 | 暂停 space 84 | 播放暂停 85 | 100的音量大小 up 86 | 30的音量大小 down 87 | 2.0的语速 88 | 正常的语速 89 | 快退 left 90 | 快进 right 91 | 显示进度信息 92 | 关闭进度信息 93 | 显示上下菜单且不自动关闭 94 | 立刻关闭上下菜单 95 | 显示菜单自动关闭 96 | 固定时间后自动关闭 97 | 设置宽720 高480 98 |
99 | 101 | github: https://github.com/IFmiss/Dvideo.js 102 | 103 |
104 | 105 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "d-video", 3 | "version": "1.1.2", 4 | "description": "html5 video player just pc", 5 | "main": "/lib/d-video.js", 6 | "dependencies": { 7 | "hoek": "^5.0.3", 8 | "node-sass": "^4.9.4" 9 | }, 10 | "scripts": { 11 | "test": "echo \"Error: no test specified\" && exit 1", 12 | "build": "webpack --mode production", 13 | "dev": "webpack-dev-server --mode development --progress --colors", 14 | "watch": "webpack --progress --colors --watch" 15 | }, 16 | "repository": { 17 | "type": "git", 18 | "url": "https://www.github.com/ifmiss/Dvideo.js" 19 | }, 20 | "keywords": [ 21 | "video", 22 | "plugin" 23 | ], 24 | "author": "daiwei", 25 | "license": "ISC", 26 | "devDependencies": { 27 | "babel-core": "^6.26.0", 28 | "babel-loader": "^7.1.4", 29 | "babel-preset-es2015": "^6.24.1", 30 | "compass-mixins": "^0.12.10", 31 | "css-loader": "^0.28.10", 32 | "extract-text-webpack-plugin": "^4.0.0-beta.0", 33 | "html-webpack-plugin": "^3.0.6", 34 | "sass-loader": "^6.0.7", 35 | "style-loader": "^0.20.3", 36 | "stylus": "^0.54.5", 37 | "stylus-loader": "^3.0.2", 38 | "url-loader": "^1.0.1", 39 | "webpack": "^4.1.1", 40 | "webpack-cli": "^2.0.12", 41 | "webpack-dev-server": "^3.1.1", 42 | "randomatic": ">=3.0.0", 43 | "deep-extend": ">=0.5.1", 44 | "atob": ">=2.1.0", 45 | "url-parse": ">=1.4.3", 46 | "macaddress": ">=0.2.9" 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /src/commonjs/dom.js: -------------------------------------------------------------------------------- 1 | export function hasClass (el, className) { 2 | let reg = new RegExp('(^|\\s)' + className + '(\\s|$)') 3 | return reg.test(el.className) 4 | } 5 | 6 | export function addClass (el, className) { 7 | if (hasClass(el, className)) { 8 | return 9 | } 10 | 11 | let newClass = el.className.split(' ') 12 | newClass.push(className) 13 | el.className = newClass.join(' ') 14 | } 15 | 16 | export function removeClass (el, className) { 17 | if (hasClass(el, className)) { 18 | let newClass = el.className.split(' ') 19 | newClass.forEach((value, index, array) => { 20 | if (value === className) { 21 | newClass.splice(index, 1) 22 | } 23 | }) 24 | el.className = newClass 25 | } 26 | } 27 | 28 | export function getData (el, dataname, setValue) { 29 | var name = `data-`${dataname} 30 | if(setValue) { 31 | el.setAttribute(name, setValue) 32 | } else { 33 | el.getAttribute(name) 34 | } 35 | } -------------------------------------------------------------------------------- /src/commonjs/storage.js: -------------------------------------------------------------------------------- 1 | export const Storage = { 2 | // 设置Cookie 3 | // name: 为cookie的名字 4 | // value: 为对应的值 5 | // exp: 为过期时间 单位为毫秒 默认设置为2个小时的过期时间 6 | setCookie (name, value, exp = 60 * 60 * 2 * 1000) { 7 | let date = new Date() 8 | date.setTime(date.getTime() + exp) 9 | document.cookie = `${name}=${escape(value)};expires=${date.toGMTString()}` 10 | }, 11 | // 获取Cookie 12 | // name: 为cookie的名字 13 | getCookie (name) { 14 | if (name) { 15 | let reg = new RegExp(`(^| )${name}=([^;]*)(;|$)`) 16 | let arr = document.cookie.match(reg) 17 | if (arr) { 18 | // return arr[2] 19 | return arr[2] 20 | } else { 21 | return null 22 | } 23 | } else { 24 | let getAllCookies = [] 25 | if (document.cookie !== '') { 26 | let arrCookie = document.cookie.split('; ') 27 | for (let k in arrCookie) { 28 | getAllCookies.push({ 29 | name: `${unescape(arrCookie[k].split('=')[0])}`, 30 | value: `${unescape(arrCookie[k].split('=')[1])}` 31 | }) 32 | } 33 | return getAllCookies 34 | } else { 35 | return null 36 | } 37 | } 38 | }, 39 | // 删除 Cookie 40 | // name: 为cookie的名字 41 | deleteCookie (name) { 42 | let date = new Date() 43 | date.setTime(date.getTime() - 1) // 设置过期了 44 | if (name) { 45 | let cookieInfo = Storage.getCookie(name) 46 | if (cookieInfo !== null) { 47 | document.cookie = `${name}=${cookieInfo};expires=${date.toGMTString()}` 48 | } 49 | } else { 50 | let getAllCookies = Storage.getCookie() 51 | for (let k in getAllCookies) { 52 | document.cookie = `${getAllCookies[k].name}=${getAllCookies[k].value};expires=${date.toGMTString()}` 53 | } 54 | } 55 | } 56 | } -------------------------------------------------------------------------------- /src/commonjs/utils.js: -------------------------------------------------------------------------------- 1 | // 浏览器相关方法 2 | export const utils = { 3 | deviceVersion () { 4 | const u = navigator.userAgent 5 | const app = navigator.appVersion 6 | return { // 移动终端浏览器版本信息 7 | userAgent: u, 8 | appVersion: app, 9 | trident: u.includes('Trident'), // IE内核 10 | presto: u.includes('Presto'), // opera内核 11 | webKit: u.includes('AppleWebKit'), // 苹果、谷歌内核 12 | gecko: u.includes('Gecko') && !u.includes('KHTML'), // 火狐内核 13 | mobile: !!u.match(/AppleWebKit.*Mobile/i) || !!u.match(/MIDP|SymbianOS|NOKIA|SAMSUNG|LG|NEC|TCL|Alcatel|BIRD|DBTEL|Dopod|PHILIPS|HAIER|LENOVO|MOT-|Nokia|SonyEricsson|SIE-|Amoi|ZTE/), // 是否为移动终端 14 | ios: !!u.match(/\(i[^;]+;( U;)? CPU.+Mac OS X/), // ios终端 15 | android: u.includes('Android') || u.includes('Linux'), // android终端或者uc浏览器 16 | iPhone: u.includes('iPhone') || u.includes('Mac'), // 是否为iPhone或者QQHD浏览器 17 | iPad: u.includes('iPad'), // 是否iPad 18 | webApp: !u.includes('Safari'), // 是否web应该程序,没有头部与底部, 19 | language: (navigator.browserLanguage || navigator.language).toLowerCase() // 浏览器语言 20 | // audroidVersion: u.substr(u.indexOf('Android') + 8, 3), 21 | // iosVersion: u.substr(u.indexOf('ios') + 8, 3) 22 | } 23 | }, 24 | 25 | // 设置console 带有自定义美化的功能 26 | // text: 内容; 27 | // isOneLine: 是否一行显示(1行相当于3行log的高度 所以不能换行); 28 | // author:用户名称 ; 29 | setConsole (text = 'this is console!', isOneLine = 1, author = '未曾遗忘的青春') { 30 | if (isOneLine) { 31 | console.log('') 32 | console.log(`%c${text} --- ${author}`, `background-image: url('data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz4gPHN2ZyB2ZXJzaW9uPSIxLjEiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+PGRlZnM+PGxpbmVhckdyYWRpZW50IGlkPSJncmFkIiBncmFkaWVudFVuaXRzPSJvYmplY3RCb3VuZGluZ0JveCIgeDE9IjAuMCIgeTE9IjAuNSIgeDI9IjEuMCIgeTI9IjAuNSI+PHN0b3Agb2Zmc2V0PSIwJSIgc3RvcC1jb2xvcj0iIzY2Y2NjYyIvPjxzdG9wIG9mZnNldD0iMjAlIiBzdG9wLWNvbG9yPSIjMzM5OTk5Ii8+PHN0b3Agb2Zmc2V0PSI0MCUiIHN0b3AtY29sb3I9IiNjY2NjOTkiLz48c3RvcCBvZmZzZXQ9IjYwJSIgc3RvcC1jb2xvcj0iIzk5Y2NmZiIvPjxzdG9wIG9mZnNldD0iODAlIiBzdG9wLWNvbG9yPSIjY2NjY2ZmIi8+PHN0b3Agb2Zmc2V0PSIxMDAlIiBzdG9wLWNvbG9yPSIjZmY5OWNjIi8+PC9saW5lYXJHcmFkaWVudD48L2RlZnM+PHJlY3QgeD0iMCIgeT0iMCIgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0idXJsKCNncmFkKSIgLz48L3N2Zz4g');background-size: 100%;background-image: -webkit-gradient(linear, 0% 50%, 100% 50%, color-stop(0%, #66cccc), color-stop(20%, #339999), color-stop(40%, #cccc99), color-stop(60%, #99ccff), color-stop(80%, #ccccff), color-stop(100%, #ff99cc));background-image: -moz-linear-gradient(left, #66cccc 0%, #339999 20%, #cccc99 40%, #99ccff 60%, #ccccff 80%, #ff99cc 100%);background-image: -webkit-linear-gradient(left, #66cccc 0%, #339999 20%, #cccc99 40%, #99ccff 60%, #ccccff 80%, #ff99cc 100%);background-image: linear-gradient(to right, #66cccc 0%, #339999 20%, #cccc99 40%, #99ccff 60%, #ccccff 80%, #ff99cc 100%);padding:20px 40px;color:#fff;font-size:12px;`) 33 | console.log('') 34 | } else { 35 | console.log(`%c${text} --- ${author}`, `background-image: url('data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz4gPHN2ZyB2ZXJzaW9uPSIxLjEiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+PGRlZnM+PGxpbmVhckdyYWRpZW50IGlkPSJncmFkIiBncmFkaWVudFVuaXRzPSJvYmplY3RCb3VuZGluZ0JveCIgeDE9IjAuMCIgeTE9IjAuNSIgeDI9IjEuMCIgeTI9IjAuNSI+PHN0b3Agb2Zmc2V0PSIwJSIgc3RvcC1jb2xvcj0iIzY2Y2NjYyIvPjxzdG9wIG9mZnNldD0iMjAlIiBzdG9wLWNvbG9yPSIjMzM5OTk5Ii8+PHN0b3Agb2Zmc2V0PSI0MCUiIHN0b3AtY29sb3I9IiNjY2NjOTkiLz48c3RvcCBvZmZzZXQ9IjYwJSIgc3RvcC1jb2xvcj0iIzk5Y2NmZiIvPjxzdG9wIG9mZnNldD0iODAlIiBzdG9wLWNvbG9yPSIjY2NjY2ZmIi8+PHN0b3Agb2Zmc2V0PSIxMDAlIiBzdG9wLWNvbG9yPSIjZmY5OWNjIi8+PC9saW5lYXJHcmFkaWVudD48L2RlZnM+PHJlY3QgeD0iMCIgeT0iMCIgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0idXJsKCNncmFkKSIgLz48L3N2Zz4g');background-size: 100%;background-image: -webkit-gradient(linear, 0% 50%, 100% 50%, color-stop(0%, #66cccc), color-stop(20%, #339999), color-stop(40%, #cccc99), color-stop(60%, #99ccff), color-stop(80%, #ccccff), color-stop(100%, #ff99cc));background-image: -moz-linear-gradient(left, #66cccc 0%, #339999 20%, #cccc99 40%, #99ccff 60%, #ccccff 80%, #ff99cc 100%);background-image: -webkit-linear-gradient(left, #66cccc 0%, #339999 20%, #cccc99 40%, #99ccff 60%, #ccccff 80%, #ff99cc 100%);background-image: linear-gradient(to right, #66cccc 0%, #339999 20%, #cccc99 40%, #99ccff 60%, #ccccff 80%, #ff99cc 100%);padding:0;color:#fff;font-size:12px;`) 36 | } 37 | }, 38 | 39 | // 移动端rem的设计 40 | initRem () { 41 | var _self = {}; 42 | var _pdfwidth = 750 43 | var _minScreenWidth = 320 44 | var _maxScreenWidth = 768 45 | var _minScreenWidthP = _minScreenWidth / _pdfwidth 46 | var _maxScreenWidthP = _maxScreenWidth / _pdfwidth 47 | _self.resizeEvt = 'orientationchange' in window ? 'orientationchange' : 'resize'; 48 | _self.Html = document.getElementsByTagName("html")[0]; 49 | _self.widthProportion = function(){ 50 | var p = Number((document.body&&document.body.clientWidth || _self.Html.offsetWidth) / _pdfwidth).toFixed(3); 51 | return p > _maxScreenWidthP ? _maxScreenWidthP:p<0.426?0.426:p; 52 | }; 53 | _self.changePage = function(){ 54 | _self.Html.setAttribute("style","font-size:" + _self.widthProportion() * 100 + "px"); 55 | }; 56 | _self.changePage(); 57 | if (!document.addEventListener) return; 58 | window.addEventListener(_self.resizeEvt,_self.changePage,false); 59 | document.addEventListener('DOMContentLoaded', _self.changePage, false); 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /src/index.js: -------------------------------------------------------------------------------- 1 | import Dvideo from 'script/Dvideo.js' 2 | var video = new Dvideo({ 3 | width: '680px', 4 | height: '360px', 5 | nextVideoExtend: function () { 6 | alert('你点击了下一个视频'); 7 | }, 8 | setVideoDefinition: function (type, ele, currentT) { 9 | alert(`类型:${type}, ---- 事件:${ele}, ----- 当前时间:${currentT}`) 10 | } 11 | }) 12 | 13 | var _btns = document.querySelectorAll('.btn') 14 | _btns.forEach((item, index) => { 15 | item.onclick = () => { 16 | switch (index){ 17 | case 0: 18 | const videoWrap = document.getElementById('video') 19 | // 全屏 20 | video.launchFullScreen(videoWrap) 21 | break 22 | case 1: 23 | // 播放 24 | video.videoPlay() 25 | break 26 | case 2: 27 | // 暂停 28 | video.videoPause() 29 | break 30 | case 3: 31 | // 播放暂停 32 | video.videoPlayPause() 33 | break 34 | case 4: 35 | // 更新音量1 36 | video.updateVolume(1) 37 | break 38 | case 5: 39 | // 更新音量0.3 40 | video.updateVolume(0.3) 41 | break 42 | case 6: 43 | // 2.0语速 44 | video.setPlayBackRate(3) 45 | break 46 | case 7: 47 | // 原来的语速 48 | video.setPlayBackRate(1) 49 | break 50 | case 8: 51 | // 倒退10秒 52 | video.videoRewind(10) 53 | break 54 | case 9: 55 | // 快进10秒 56 | video.videoForward(10) 57 | break 58 | case 10: 59 | // 显示提示进度 60 | video.showLoading(true, 'hihihi,你好呀!!!') 61 | break 62 | case 11: 63 | // 关闭提示进度 64 | video.showLoading(false) 65 | break 66 | case 12: 67 | // 显示上下菜单且不自动关闭 68 | video.showTopBottomCtrl() 69 | break 70 | case 13: 71 | // 立刻关闭上下菜单 72 | video.hideTopBottomCtrl(true) 73 | break 74 | case 14: 75 | // 显示菜单自动关闭 76 | video.showTopBottomCtrl(true) 77 | break 78 | case 15: 79 | // 固定时间后自动关闭 80 | video.hideTopBottomCtrl() 81 | break 82 | case 16: 83 | // 设置宽720 高480 84 | video.updateVideoSize(720,480) 85 | break 86 | } 87 | } 88 | }) 89 | -------------------------------------------------------------------------------- /src/script/Dvideo.js: -------------------------------------------------------------------------------- 1 | import './../scss/Dvideo.scss' 2 | import './../../static/font-icon/style.css' 3 | class Dvideo { 4 | constructor (template) { 5 | let defaultOptions = { 6 | // video元素 7 | ele: '#video', 8 | 9 | // 地址 10 | src: 'http://www.daiwei.org/index/video/EnV%20-%20PneumaticTokyo.mp4', 11 | 12 | // ----- 封面 13 | // 是否显示封面 14 | isShowPoster: true, 15 | // 封面的地址 16 | poster: 'http://www.daiwei.org/vue/image/17-07-07/IMG_0330.jpg', 17 | 18 | 19 | // video的名称 20 | title: 'Hi EveryOne...', 21 | 22 | // video的宽度 23 | width: '420px', 24 | // video的高度 25 | height: '250px', 26 | 27 | // 是否显示下一个 按钮 28 | showNext: true, 29 | 30 | // 是否自动播放 31 | autoplay: true, 32 | 33 | // 控制条 关闭的时间 34 | ctrSpeedDuration: 3000, 35 | 36 | // 视频是否循环 37 | loop: false, 38 | 39 | 40 | // ------ 音量 41 | // 是否显示音量 42 | showVolume: true, 43 | // 音量大小 44 | volume: 0.8, 45 | // 在非全屏幕下是否显示音量调整条 46 | showVolumeUnFull: false, 47 | 48 | 49 | // ------ 语速 50 | // 是否显示设置语速菜单列表 51 | showPlayBackRate: true, 52 | // 是否在未全屏的情况下 显示语速 53 | showPlayBackRateUnFull: true, 54 | // 语速的设置 55 | playbackRate: { 56 | // 索引 57 | activeIndex: 1, 58 | // 选项 59 | rateList: [0.8,1,1.5,2] 60 | }, 61 | 62 | 63 | // ------ 清晰度 64 | // 是否显示清晰度 65 | showVideoDefinition: true, 66 | // 是否在未全屏幕的情况下 显示清晰度 67 | showVideoDefinitionUnFull: true, 68 | // 清晰度信息 69 | videoDefinition: { 70 | // 索引 71 | activeIndex: 1, 72 | // 选项 73 | definitionList: [ 74 | { 75 | // 类型 字符串标识 76 | type: '0', 77 | // 类型 展示效果标识 78 | name: '标清' 79 | }, 80 | { 81 | type: '1', 82 | name: '高清' 83 | }, 84 | { 85 | type: '2', 86 | name: '超清' 87 | } 88 | ] 89 | }, 90 | 91 | // ================ 暴露的方法 92 | // 可让用户自定义扩展 点击下一个视频的操作 93 | nextVideoExtend: () => {}, 94 | // 设置清晰度的操作 95 | setVideoDefinition: (type, event, currentT) => {}, 96 | // 暴露的视频time更新事件 97 | onTimeupdate: (currentT) => {}, 98 | // 暴露的视频Playing事件 99 | onPlaying: (currentT) => {}, 100 | // 暴露的视频暂停事件 101 | onPause: () => {}, 102 | // 暴露的视频结束事件(loop 不会执行end 事件) 103 | onEnded: () => {}, 104 | // 暴露视频初始化事件 元数据加载成功事件 105 | onLoadedMetaData: () => {}, 106 | } 107 | 108 | this.opt = Object.assign(defaultOptions, template) 109 | // ================= 以下为私有自定义方法 110 | // 全屏的状态信息 111 | this.isFull = false 112 | 113 | // 是否已经加载初始化元数据 114 | this.isLoadMate = false 115 | 116 | // 设置播放的状态 117 | this.isPlaying = false 118 | 119 | // 设置视频时长 120 | this.durationT = 0 121 | 122 | // 当前的播放时间 123 | this.currentT = 0 124 | 125 | // 这是鼠标移入显示控制菜单的timeout 126 | this.showCtrlT = '' 127 | 128 | // 进度百分比 129 | this.currentP = 0 130 | 131 | // 进度条是否可拖动 132 | this.isDrag = false 133 | 134 | // 快进快退事件 135 | this.onPress = false 136 | 137 | // 进度条的宽度 138 | this.maxProgressWidth = 0 139 | 140 | // 进度条拖动的位置 141 | this.dragProgressTo = 0 142 | 143 | // 音量大小 144 | this.volume = 1 145 | 146 | // 音量最大宽度 147 | this.maxVolumeWidth = 0 148 | 149 | // 音量拖动的位置 150 | this.dragVolumeTo = 0 151 | 152 | // 获取浏览器版本 153 | this.browserV = this.browserVersion() 154 | 155 | // 通过时间戳与当前时间的差值来判断是否需要加载 156 | this.reduceTBefore = 0 // 时间戳与当前时间的差值 (初始化) 157 | this.reduceTAfter = 0 // 时间戳与当前时间的差值 (执行中) 158 | 159 | this.isPlaying = this.autoplay 160 | // 判断传进来的是DOM还是字符串 161 | if ((typeof this.opt.ele) === "string") { 162 | this.opt.ele = document.querySelector(this.opt.ele) 163 | }else{ 164 | this.opt.ele = this.opt.ele 165 | } 166 | 167 | // 初始化 168 | this.initDom() 169 | // 显示菜单信息 170 | this.showTopBottomCtrl(true) 171 | } 172 | 173 | initDom() { 174 | this.opt.ele.style.width = this.opt.width 175 | this.opt.ele.style.height = this.opt.height 176 | 177 | // 创建组件的content区域 178 | this.createVideoC() 179 | 180 | // 创建Video 181 | this.createVideoEle() 182 | 183 | // 创建头部菜单信息 184 | this.createHeaderC() 185 | 186 | // 创建控制菜单 187 | this.createCtrlC() 188 | 189 | // 显示提示信息 190 | this.createVideoTips() 191 | 192 | // 音乐播放暂停 下一集 193 | this.createvideoPlayState() 194 | 195 | // 进度条 196 | this.createPcProgress() 197 | 198 | // 创建current / duration 时间显示 199 | this.createCurrentDurationText() 200 | 201 | // 菜单栏右侧信息 202 | this.menuRightC = document.createElement('div') 203 | this.menuRightC.className = 'Dvideo-menu-right-content' 204 | this.videoCtrlDetail.appendChild(this.menuRightC) 205 | 206 | // 音量拖动效果 207 | if (this.opt.showVolume) { 208 | this.createVolume() 209 | } 210 | 211 | // 语速选项的列表 212 | if (this.opt.showPlayBackRate) { 213 | this.createPlaybackRateList() 214 | } 215 | 216 | 217 | // 设置清晰度区域 218 | if (this.opt.showVideoDefinition) { 219 | this.createVideoDefinition() 220 | } 221 | 222 | 223 | // 全屏按钮 224 | this.createSelectVideoFull() 225 | 226 | // 初始化事件 227 | this.initEvent() 228 | } 229 | 230 | // 开启全屏 231 | launchFullScreen (element) { 232 | if((/IE9|IE10/i).test(this.browserV)) { 233 | this.launchFullScreenIE11L(); 234 | } else { 235 | // alert(screenChange) 236 | if (element.requestFullscreen) { 237 | element.requestFullscreen() 238 | } else if (element.mozRequestFullScreen) { 239 | element.mozRequestFullScreen() 240 | } else if (element.webkitRequestFullscreen) { 241 | element.webkitRequestFullscreen() 242 | } else if (element.msRequestFullscreen) { 243 | element.msRequestFullscreen() 244 | } 245 | this.launchFullScreenStyle(element) 246 | } 247 | this.updateFullScreenState(true) 248 | } 249 | 250 | // 全屏下视频的样式 251 | launchFullScreenStyle () { 252 | this.opt.ele.style.width = '100%' 253 | this.opt.ele.style.height = '100%' 254 | } 255 | 256 | // 全屏下IE 11 以下视频的样式 257 | launchFullScreenIE11L () { 258 | let cName = this.opt.ele.className 259 | this.opt.ele.className = cName + ' ie-fullscreen' 260 | } 261 | // 关闭全屏 262 | exitFullscreen () { 263 | if((/IE9|IE10/i).test(this.browserV)) { 264 | // this.isFull = true 265 | this.exitFullscreenIE11L(); 266 | } else { 267 | // this.exitFullScreenStyle() 268 | if (document.exitFullscreen) { 269 | document.exitFullscreen(); 270 | } else if (document.mozCancelFullScreen) { 271 | document.mozCancelFullScreen(); 272 | } else if (document.webkitExitFullscreen) { 273 | document.webkitExitFullscreen(); 274 | } else if (document.msExitFullscreen) { 275 | document.msExitFullscreen(); 276 | } 277 | } 278 | } 279 | 280 | // 关闭全屏IE 10及以下 281 | exitFullscreenIE11L () { 282 | this.updateFullScreenState(false) 283 | let cName = this.opt.ele.className 284 | this.opt.ele.className = cName.split(' ').slice(cName.split(' ').indexOf('ie-fullscreen'), 1) 285 | this.opt.ele.style.width = this.opt.width 286 | this.opt.ele.style.height = this.opt.height 287 | } 288 | 289 | // 关闭全屏的元素样式 290 | exitFullScreenStyle () { 291 | this.updateFullScreenState(false) 292 | this.opt.ele.style.width = this.opt.width 293 | this.opt.ele.style.height = this.opt.height 294 | } 295 | 296 | // 更新视频宽度 297 | updateVideoSize (width, height) { 298 | if (!(width && height)) { 299 | throw Error ('noneeleerror','请填写信息') 300 | return; 301 | } 302 | this.updateFullScreenState(false) 303 | this.opt.ele.style.width = width + 'px' 304 | this.opt.ele.style.height = height + 'px' 305 | this.opt.width = width + 'px' 306 | this.opt.height = height + 'px' 307 | } 308 | 309 | // 更新全屏状态 包括显示全屏图标样式 310 | updateFullScreenState (bool) { 311 | this.isFull = bool || false 312 | // 全屏图标样式 313 | let iconClassName = this.isFull ? 'Dvideo-menu-fullscreenConfig icon-canclefullscreen' : 'Dvideo-menu-fullscreenConfig icon-fullscreen' 314 | // 文案 315 | let title = this.isFull ? '取消全屏' : '全屏' 316 | this.fullscreenConfig.className = iconClassName 317 | this.fullscreenConfig.title = title 318 | // 设置页面是否全屏的class 319 | let videoClassName = this.isFull ? 'Dvideo-content full' : 'Dvideo-content' 320 | this.videoC.className = videoClassName 321 | } 322 | 323 | // 屏幕全屏模式改变事件 包括ie 11 以下 324 | screenChangeEvent (element) { 325 | let _this = this 326 | if((/IE11/i).test(this.browserV)) { 327 | document.onkeydown = function (e) { 328 | let keyNum = window.event ? e.keyCode : e.which 329 | if (keyNum === 27 && _this.isFull) { 330 | // ie退出全屏 这里针对的是IE11 331 | _this.exitFullScreenStyle() 332 | } 333 | } 334 | } 335 | else if ((/IE9|IE10/i).test(this.browserV)) { 336 | document.onkeydown = function (e) { 337 | let keyNum = window.event ? e.keyCode : e.which 338 | if (keyNum === 27 && _this.isFull) { 339 | // ie退出全屏 这里针对的是IE10 9 340 | _this.exitFullscreenIE11L() 341 | } 342 | } 343 | } 344 | else { 345 | let eventList = ['webkitfullscreenchange', 'mozfullscreenchange', 'fullscreenchange', 'msfullscreenchange'] 346 | for(let i = 0; i < eventList.length; i++) { 347 | document.addEventListener(eventList[i], function () { 348 | // 全屏显示的网页元素 349 | let fullscreenElement = document.fullscreenElement || document.mozFullScreenElement || document.webkitFullscreenElement || document.msFullscreenElement 350 | 351 | // 判断网页是否处于全屏状态下 352 | let isFullScreen = document.fullScreen || document.mozFullScreen || document.webkitIsFullScreen || document.msIsFullScreen 353 | 354 | if (fullscreenElement) { 355 | console.log('全屏') 356 | _this.launchFullScreenStyle(_this.opt.ele); 357 | } else { 358 | console.log('不是全屏') 359 | _this.exitFullScreenStyle() 360 | } 361 | }) 362 | } 363 | } 364 | } 365 | 366 | browserVersion () { 367 | let userAgent = navigator.userAgent, 368 | rMsie = /(msie\s|trident.*rv:)([\w.]+)/, 369 | rFirefox = /(firefox)\/([\w.]+)/, 370 | rOpera = /(opera).+version\/([\w.]+)/, 371 | rChrome = /(chrome)\/([\w.]+)/, 372 | rSafari = /version\/([\w.]+).*(safari)/; 373 | let browser; 374 | let version; 375 | let ua = userAgent.toLowerCase(); 376 | function uaMatch(ua){ 377 | let match = rMsie.exec(ua); 378 | if(match != null){ 379 | return { browser : "IE", version : match[2] || "0" }; 380 | } 381 | match = rFirefox.exec(ua); 382 | if (match != null) { 383 | return { browser : match[1] || "", version : match[2] || "0" }; 384 | } 385 | match = rOpera.exec(ua); 386 | if (match != null) { 387 | return { browser : match[1] || "", version : match[2] || "0" }; 388 | } 389 | match = rChrome.exec(ua); 390 | if (match != null) { 391 | return { browser : match[1] || "", version : match[2] || "0" }; 392 | } 393 | match = rSafari.exec(ua); 394 | if (match != null) { 395 | return { browser : match[2] || "", version : match[1] || "0" }; 396 | } 397 | if (match != null) { 398 | return { browser : "", version : "0" }; 399 | } 400 | } 401 | let browserMatch = uaMatch(userAgent.toLowerCase()); 402 | if (browserMatch.browser){ 403 | browser = browserMatch.browser; 404 | version = browserMatch.version; 405 | } 406 | return browser + version 407 | } 408 | 409 | // 显示上下菜单 disappearance 是否自动消失 410 | showTopBottomCtrl (disappearance) { 411 | clearTimeout(this.showCtrlT) 412 | this.videoCtrl.className = 'Dvideo-ctrl active' 413 | this.videoHeader.className = 'Dvideo-header active' 414 | if (disappearance) { 415 | this.hideTopBottomCtrl() 416 | } 417 | } 418 | 419 | // 关闭上下菜单 immediately 是否立刻关闭 420 | hideTopBottomCtrl (immediately) { 421 | clearTimeout(this.showCtrlT) 422 | let _this = this 423 | if (immediately) { 424 | this.videoCtrl.className = 'Dvideo-ctrl' 425 | this.videoHeader.className = 'Dvideo-header' 426 | this.hideProgressRange() 427 | } else { 428 | // 隐藏控制栏 429 | this.showCtrlT = setTimeout(function () { 430 | _this.videoCtrl.className = 'Dvideo-ctrl' 431 | _this.videoHeader.className = 'Dvideo-header' 432 | _this.hideProgressRange() 433 | }, _this.opt.ctrSpeedDuration) 434 | } 435 | } 436 | 437 | // 显示隐藏进度条小球 438 | showProgressRange () { 439 | this.videoProressC.className = 'Dvideo-progress-content active' 440 | } 441 | 442 | hideProgressRange () { 443 | this.videoProressC.className = 'Dvideo-progress-content' 444 | } 445 | 446 | videoPlay () { 447 | try{ 448 | this.videoEle.play(); 449 | this.isPlaying = true 450 | } catch (e) { 451 | console.log(e) 452 | } 453 | } 454 | 455 | videoPause () { 456 | try{ 457 | this.videoEle.pause(); 458 | this.isPlaying = false 459 | console.log(this.isPlaying + '222222') 460 | } catch (e) { 461 | console.log(e) 462 | } 463 | } 464 | 465 | videoPlayPause () { 466 | if (this.isPlaying) { 467 | this.videoPause(); 468 | } else { 469 | this.videoPlay(); 470 | } 471 | } 472 | 473 | showLoading (bool, text = '视频加载中,请稍等 或者切换稍低的清晰度') { 474 | if (bool) { 475 | this.tipsInfo.innerText = text 476 | this.tipsInfo.className = 'Dvideo-tips-info' 477 | } else { 478 | this.tipsInfo.className = 'Dvideo-tips-info hide' 479 | } 480 | } 481 | 482 | /** 483 | * 快进 484 | * @param { number } seconds 485 | */ 486 | videoForward(seconds = 10) { 487 | if (this.videoEle.currentTime) { 488 | this.currentT = this.currentT + seconds > this.durationT ? this.durationT : this.currentT + seconds 489 | this.videoEle.currentTime = this.currentT 490 | this.updatePorgress() 491 | } 492 | } 493 | 494 | /** 495 | * 快退 496 | * @param { number } seconds 497 | */ 498 | videoRewind (seconds = 10) { 499 | if (this.videoEle.currentTime) { 500 | this.currentT = this.currentT - seconds < 0 ? 0 : this.currentT - seconds 501 | this.videoEle.currentTime = this.currentT 502 | this.updatePorgress() 503 | } 504 | } 505 | 506 | /** 507 | * 跳转到某一个位置 508 | */ 509 | videoSeek (seconds) { 510 | if (seconds > this.durationT) return 511 | if (this.videoEle.currentTime) { 512 | this.videoEle.currentTime = seconds 513 | this.updatePorgress() 514 | } 515 | } 516 | 517 | /** 518 | * 音乐初始化事件 519 | */ 520 | initEvent () { 521 | let _this = this 522 | // 键盘事件 (ie 没有ctrl键) 523 | document.onkeydown = function (event) { 524 | let e = event || window.event 525 | if ((e.keyCode || e.which || e.charCode) === 32) { // 空格 暂停 526 | // console.log(e.ctrlKey + '------' + (e.keyCode || e.which || e.charCode)) 527 | e.stopPropagation(); 528 | e.preventDefault(); 529 | _this.videoPlayPause() 530 | } 531 | if ((e.keyCode || e.which || e.charCode) === 39) { // --> 快进 532 | e.stopPropagation(); 533 | e.preventDefault(); 534 | _this.showTopBottomCtrl() 535 | _this.videoForward(10) 536 | } 537 | if ((e.keyCode || e.which || e.charCode) === 37) { // <-- 快退 538 | e.stopPropagation(); 539 | e.preventDefault(); 540 | _this.showTopBottomCtrl() 541 | _this.videoRewind(10) 542 | } 543 | 544 | if ((e.keyCode || e.which || e.charCode) === 38) { // up 音量增加 545 | e.stopPropagation(); 546 | e.preventDefault(); 547 | _this.showTopBottomCtrl() 548 | _this.volume = _this.volume * 1 + 0.02 > 1 ? 1 : _this.volume * 1 + 0.02 549 | _this.setVolume() 550 | } 551 | 552 | if ((e.keyCode || e.which || e.charCode) === 40) { // down 音量降低 553 | e.stopPropagation(); 554 | e.preventDefault(); 555 | _this.showTopBottomCtrl() 556 | _this.volume = _this.volume * 1 - 0.02 < 0 ? 0 : _this.volume * 1 - 0.02 557 | _this.setVolume() 558 | } 559 | } 560 | 561 | // 添加监听是否改变窗口大小事件 562 | _this.screenChangeEvent() 563 | } 564 | 565 | // playIng事件 566 | onPlaying () { 567 | this.opt.onPlaying(this.currentT) 568 | } 569 | 570 | // 暂停事件 571 | onPause () { 572 | this.opt.onPause() 573 | } 574 | 575 | // 元数据加载事件 576 | onLoadedMetaData () { 577 | this.opt.onLoadedMetaData() 578 | } 579 | 580 | // 进度更新事件 581 | onTimeupdate () { 582 | this.opt.onTimeupdate(this.currentT) 583 | } 584 | 585 | // 播放结束事件 586 | onEnded () { 587 | this.opt.onEnded() 588 | } 589 | 590 | // 格式化时间 591 | formartTime (seconds) { 592 | let formatNumber = function (n) { 593 | n = n.toString() 594 | return n[1] ? n : '0' + n 595 | } 596 | let m = Math.floor(seconds / 60); 597 | let s = Math.floor(seconds % 60); 598 | return formatNumber(m) + ":" + formatNumber(s); 599 | } 600 | 601 | setVideoDefinition (e) { 602 | // 显示提示信息 603 | this.showLoading(true, '视频清晰度切换中,请稍等') 604 | 605 | // 获取索引 以及清晰度类型 606 | let index = e.target.getAttribute('data-index') 607 | let type = e.target.getAttribute('data-type') 608 | 609 | this.currentT = this.videoEle.currentTime 610 | 611 | // this.videoEle.currentTime = this.currentT 612 | // this.videoPlay() 613 | 614 | this.opt.videoDefinition = { 615 | activeIndex: index, 616 | definitionList: this.opt.videoDefinition.definitionList 617 | } 618 | 619 | // 文本显示 620 | this.videoDefinitionText.title = this.opt.videoDefinition.definitionList[index].name 621 | this.videoDefinitionText.innerText = this.opt.videoDefinition.definitionList[index].name 622 | // 存储至本地 623 | this.setLStorage('D-videoDefinition', JSON.stringify(this.opt.videoDefinition)) 624 | 625 | // 设置列表active状态 626 | this.getDomByClass('Dvideo-definition-list active')[0].className = 'Dvideo-definition-list' 627 | e.target.className = 'Dvideo-definition-list active' 628 | this.videoDefinitionC.style.display = 'none' 629 | 630 | 631 | this.opt.setVideoDefinition(type, e, this.currentT) 632 | } 633 | 634 | setVideoInfo(title, url, currentT) { 635 | let _this = this 636 | this.isLoadMate = false 637 | this.isPlaying = false 638 | // 地址 639 | this.videoEle.src = url || '', 640 | // title 641 | this.videoHeaderTitle.innerText = title || '这是一个title' 642 | this.videoHeaderTitle.title = title || '这是一个title' 643 | 644 | let loadProPlay = function () { 645 | if (_this.isLoadMate) { 646 | clearInterval(loadTime) 647 | _this.videoEle.currentTime = currentT || 0 648 | } 649 | _this.videoPlay(); 650 | } 651 | 652 | // 是否有currentT 653 | let loadTime = setInterval(function () { 654 | loadProPlay(); 655 | }, 500) 656 | 657 | } 658 | 659 | setPlayBackRate (index) { 660 | this.playbackR = this.opt.playbackRate.rateList[index] 661 | this.videoEle.playbackRate = this.playbackR 662 | this.playbackRateText.title = this.playbackR.toFixed(1) + ' x' 663 | this.playbackRateText.innerText = this.playbackR.toFixed(1) + ' x' 664 | 665 | 666 | this.opt.playbackRate = { 667 | activeIndex: index, 668 | rateList: this.opt.playbackRate.rateList 669 | } 670 | // 存储至本地 671 | this.setLStorage('D-playbackRate', JSON.stringify(this.opt.playbackRate)) 672 | 673 | // 设置列表active状态 674 | this.getDomByClass('Dvideo-playbackRate-list active')[0].className = 'Dvideo-playbackRate-list' 675 | this.getDomByClass('Dvideo-playbackRate-list')[index].className = 'Dvideo-playbackRate-list active' 676 | this.playbackRateC.style.display = 'none' 677 | } 678 | 679 | // 更新进度条位置 680 | updatePorgress (isDrag = false) { 681 | if (isDrag) { 682 | this.circleRange.style.left = this.dragProgressTo + 'px' 683 | this.realProress.style.width = this.dragProgressTo + 'px' 684 | let currentTime = Math.floor(this.dragProgressTo / this.maxProgressWidth * this.durationT) 685 | this.textCurrentT.innerText = this.formartTime(currentTime) 686 | } else { 687 | this.currentP = Number((this.currentT / this.durationT) * 100) 688 | this.currentP = this.currentP > 100 ? 100 : this.currentP 689 | this.realProress.style.width = this.currentP + '%' 690 | this.circleRange.style.left = this.currentP + '%' 691 | // 更改时间进度 692 | this.textCurrentT.innerText = this.formartTime(this.videoEle.currentTime) 693 | } 694 | } 695 | 696 | // 下一集的点击事件 697 | nextVideo () { 698 | console.log('你点击了播放下一集 可使用实例化的对象调用nextVideo 方法实现播放下一集的效果') 699 | if (typeof this.opt.nextVideoExtend === 'function') this.opt.nextVideoExtend() 700 | } 701 | 702 | // 设置音量大小 703 | setVolume () { 704 | // this.videoEle.volume = this.volume 705 | let persent = this.volume / 1 706 | this.updateVolume(persent) 707 | } 708 | 709 | // 创建PlaybackRateList 710 | createPlaybackRateList () { 711 | let showVClassName = this.opt.showPlayBackRateUnFull ? '' : 'none' 712 | let oFragment = document.createDocumentFragment(); 713 | // 语速数据 714 | let playbackrateData = this.hasLStorage('D-playbackRate') ? JSON.parse(this.getLStorage('D-playbackRate')) : this.opt.playbackRate 715 | 716 | // 当前active索引 717 | let playbackrateIndex = Number(playbackrateData.activeIndex) 718 | 719 | // 当前语速 720 | let playbackR = Number(playbackrateData.rateList[playbackrateIndex]) 721 | 722 | 723 | // 设置语速区域 724 | this.playbackRate = document.createElement('span') 725 | this.playbackRate.className = 'Dvideo-playbackRate ' + showVClassName 726 | this.menuRightC.appendChild(this.playbackRate) 727 | 728 | // 显示语速文本 729 | this.playbackRateText = document.createElement('span') 730 | this.playbackRateText.className = 'Dvideo-playbackRateText' 731 | this.videoEle.playbackRate = playbackR 732 | this.playbackRateText.title = playbackR.toFixed(1) + ' x' 733 | this.playbackRateText.innerText = playbackR.toFixed(1) + ' x' 734 | this.playbackRate.appendChild(this.playbackRateText) 735 | 736 | // 语速选项的内容 737 | this.playbackRateC = document.createElement('div') 738 | this.playbackRateC.className = 'Dvideo-playbackRate-content' 739 | this.playbackRate.appendChild(this.playbackRateC) 740 | 741 | 742 | for (let i = 0; i < playbackrateData.rateList.length; i++) { 743 | let playbackRateL = document.createElement('span') 744 | if (i === playbackrateIndex) { 745 | playbackRateL.className = 'Dvideo-playbackRate-list active' 746 | } else { 747 | playbackRateL.className = 'Dvideo-playbackRate-list' 748 | } 749 | playbackRateL.title = playbackrateData.rateList[i].toFixed(1) + 'x' 750 | playbackRateL.innerText = playbackrateData.rateList[i].toFixed(1) + 'x' 751 | playbackRateL.setAttribute('data-index', i) 752 | oFragment.appendChild(playbackRateL) 753 | } 754 | this.playbackRateC.appendChild(oFragment) 755 | 756 | let _this = this 757 | 758 | // ====================设置语速交互 759 | _this.playbackRate.onmouseenter = function (event) { 760 | _this.playbackRateC.style.display = 'block' 761 | } 762 | 763 | _this.playbackRate.onmouseleave = function (event) { 764 | _this.playbackRateC.style.display = 'none' 765 | } 766 | 767 | _this.playbackRateC.onclick = function (event) { 768 | let e = event || window.event 769 | let index = e.target.getAttribute('data-index') 770 | _this.setPlayBackRate(index) 771 | } 772 | } 773 | 774 | // 创建currentduration 775 | createCurrentDurationText () { 776 | let oFragment = document.createDocumentFragment(); 777 | // 显示当前时间和总时长 区域 778 | this.textVideoTimeC = document.createElement('div') 779 | this.textVideoTimeC.className = 'Dvideo-time-content' 780 | this.videoCtrlDetail.appendChild(this.textVideoTimeC) 781 | 782 | // 显示当前秒数 783 | this.textCurrentT = document.createElement('span') 784 | this.textCurrentT.className = 'Dvideo-text-current' 785 | this.textCurrentT.innerText = '--:-- ' 786 | oFragment.appendChild(this.textCurrentT) 787 | 788 | // 显示时长 789 | this.textDurationT = document.createElement('span') 790 | this.textDurationT.className = 'Dvideo-text-duration' 791 | this.textDurationT.innerText = ' --:--' 792 | oFragment.appendChild(this.textDurationT) 793 | this.textVideoTimeC.appendChild(oFragment) 794 | } 795 | 796 | // pc 端进度条 797 | createPcProgress () { 798 | // 进度条区域 799 | this.videoProressC = document.createElement('div') 800 | this.videoProressC.className = 'Dvideo-progress-content' 801 | this.videoCtrl.appendChild(this.videoProressC) 802 | 803 | // 进度条内容 (包涵进度条和缓冲条) videoProressDetail 804 | this.videoProressD = document.createElement('div') 805 | this.videoProressD.className = 'Dvideo-progress-detail' 806 | this.videoProressC.appendChild(this.videoProressD) 807 | 808 | // 缓冲条 809 | this.bufferedProress = document.createElement('div') 810 | this.bufferedProress.className = 'Dvideo-progress-buffered' 811 | this.videoProressD.appendChild(this.bufferedProress) 812 | 813 | // 播放进度条 814 | this.realProress = document.createElement('div') 815 | this.realProress.className = 'Dvideo-progress-real' 816 | this.videoProressD.appendChild(this.realProress) 817 | 818 | // 播放进度条圆形按钮 819 | this.circleRange = document.createElement('span') 820 | this.circleRange.className = 'Dvideo-circle-range' 821 | this.videoProressC.appendChild(this.circleRange) 822 | 823 | let _this = this 824 | 825 | // 点击进度条跳转 826 | _this.videoProressD.onclick = function (event) { 827 | // let e = event || window.event 828 | // let l = e.layerX 829 | // let w = _this.videoProressD.offsetWidth 830 | 831 | // _this.videoEle.currentTime = Math.floor(l / w * _this.durationT) 832 | // _this.currentT = _this.videoEle.currentTime 833 | // _this.updatePorgress() 834 | let e = event || window.event 835 | // alert(e.target.offsetLeft) 836 | let videoProgressCW = _this.videoProressD.offsetWidth 837 | let eW = e.offsetX 838 | _this.videoEle.currentTime = _this.currentT = Math.floor(eW / videoProgressCW * _this.durationT) 839 | _this.updatePorgress() 840 | } 841 | 842 | // 进度条拖动 (PC) 843 | _this.circleRange.onmousedown = function (event) { 844 | _this.isDrag = true 845 | let e = event || window.event 846 | let x = e.clientX 847 | let l = event.target.offsetLeft + 7 848 | e.stopPropagation() 849 | _this.maxProgressWidth = _this.videoProressD.offsetWidth 850 | _this.videoCtrl.onmousemove = function (event) { 851 | let e = event || window.event 852 | if (_this.isDrag) { 853 | let thisX = e.clientX 854 | _this.dragProgressTo = Math.min(_this.maxProgressWidth, Math.max(0, l + (thisX - x))) 855 | // update Time 856 | _this.updatePorgress(true) 857 | } 858 | } 859 | _this.videoCtrl.onmouseup = function (event) { 860 | let e = event || window.event 861 | e.stopPropagation() 862 | if (_this.isDrag) { 863 | _this.isDrag = false 864 | _this.videoEle.currentTime = Math.floor(_this.dragProgressTo / _this.maxProgressWidth * _this.durationT) 865 | } else { 866 | return 867 | } 868 | } 869 | 870 | _this.videoCtrl.onmouseleave = function (event) { 871 | let e = event || window.event 872 | e.stopPropagation() 873 | if (_this.isDrag) { 874 | _this.isDrag = false 875 | _this.videoEle.currentTime = Math.floor(_this.dragProgressTo / _this.maxProgressWidth * _this.durationT) 876 | } else { 877 | return 878 | } 879 | 880 | _this.hideTopBottomCtrl() 881 | } 882 | } 883 | } 884 | 885 | // 创建视频 886 | createVideoEle () { 887 | this.videoEle = document.createElement('video') 888 | this.videoEle.className = 'Dvideo-ele' 889 | this.videoEle.src = this.opt.src 890 | this.videoEle.loop = this.opt.loop 891 | this.videoEle.autoplay = this.opt.autoplay 892 | this.videoEle.poster = this.opt.poster 893 | this.videoC.appendChild(this.videoEle) 894 | 895 | let _this = this 896 | 897 | // 视频事件 898 | _this.videoEle.onloadstart = function () { 899 | _this.showLoading(true, '视频加载中,请稍等') 900 | } 901 | 902 | _this.videoEle.oncanplay = function () { 903 | _this.showLoading(false) 904 | } 905 | 906 | _this.videoEle.onplaying = function () { 907 | _this.isPlaying = true 908 | _this.videoPlayPauseI.className = 'Dvideo-ctrl-playPause icon-pause' 909 | _this.videoPlayPauseI.title = '暂停 space' 910 | let date = new Date () 911 | _this.reduceTBefore = Date.parse(date) - Math.floor(_this.videoEle.currentTime * 1000) 912 | _this.showLoading(false) 913 | _this.onPlaying() 914 | } 915 | _this.videoEle.onpause = function () { 916 | _this.isPlaying = false 917 | _this.videoPlayPauseI.className = 'Dvideo-ctrl-playPause icon-play' 918 | _this.videoPlayPauseI.title = '播放 space' 919 | _this.onPause() 920 | } 921 | 922 | // 视频元数据 (时长 尺寸 以及文本轨道) 923 | _this.videoEle.onloadedmetadata = function () { 924 | _this.isLoadMate = true 925 | _this.durationT = _this.videoEle.duration 926 | // 初始化视频时间 927 | _this.textDurationT.innerText = _this.formartTime(_this.durationT) 928 | _this.onLoadedMetaData() 929 | } 930 | 931 | // 绑定进度条 932 | _this.videoEle.ontimeupdate = function () { 933 | if (!_this.isDrag) { 934 | _this.currentT = _this.videoEle.currentTime 935 | _this.updatePorgress() 936 | let date = new Date () 937 | _this.reduceTBefore = Date.parse(date) - Math.floor(_this.currentT * 1000) 938 | } 939 | // console.log(2) 940 | _this.onTimeupdate() 941 | } 942 | _this.videoEle.onprogress = function () { 943 | if(_this.videoEle.buffered.length > 0) { 944 | let bufferedT = 0 945 | for (let i = 0; i < _this.videoEle.buffered.length; i++) { 946 | bufferedT += _this.videoEle.buffered.end(i) - _this.videoEle.buffered.start(i) 947 | if(bufferedT > _this.durationT) { 948 | bufferedT = _this.durationT 949 | console.log('缓冲完成') 950 | } 951 | } 952 | let bufferedP = Math.floor((bufferedT / _this.durationT) * 100) 953 | _this.bufferedProress.style.width = bufferedP + '%' 954 | } else { 955 | console.log('未缓冲') 956 | } 957 | 958 | let date = new Date () 959 | // console.log(_this.reduceTAfter + '-------------------------' + _this.reduceTBefore) 960 | if(!_this.videoEle.paused) { 961 | _this.reduceTAfter = Date.parse(date) - Math.floor(_this.currentT * 1000) 962 | // console.log(_this.reduceTAfter) 963 | if(_this.reduceTAfter - _this.reduceTBefore > 1000) { 964 | _this.showLoading(true) 965 | } else { 966 | _this.showLoading(false) 967 | } 968 | } else { 969 | return 970 | } 971 | } 972 | 973 | _this.videoEle.onended = function () { 974 | _this.onEnded(); 975 | } 976 | 977 | _this.videoEle.onwaiting = function () { 978 | _this.showLoading(true, '视频加载中,请稍等') 979 | } 980 | } 981 | 982 | createVideoC () { 983 | // video content 984 | this.videoC = document.createElement('div') 985 | this.videoC.className = 'Dvideo-content' 986 | this.opt.ele.appendChild(this.videoC) 987 | 988 | let _this = this 989 | // 鼠标事件 移动显示菜单 990 | _this.videoC.onmousemove = function () { 991 | _this.showTopBottomCtrl(true) 992 | } 993 | 994 | // 界面点击播放暂停 995 | let startTime = 0; 996 | _this.videoC.onclick = function () { 997 | let date = (new Date()).valueOf(); 998 | // > 1秒是播放暂停的操作 999 | if (date - startTime > 500) { 1000 | if (_this.isPlaying) { 1001 | _this.videoPause() 1002 | } else { 1003 | _this.videoPlay() 1004 | } 1005 | } else { 1006 | // 否则就是全屏的操作 1007 | if (_this.isFull) { 1008 | _this.exitFullscreen() 1009 | } else { 1010 | _this.launchFullScreen(_this.opt.ele) 1011 | } 1012 | } 1013 | startTime = date 1014 | } 1015 | } 1016 | 1017 | createCtrlC () { 1018 | // 底部控制条 1019 | this.videoCtrl = document.createElement('div') 1020 | this.videoCtrl.className = 'Dvideo-ctrl' 1021 | this.videoC.appendChild(this.videoCtrl) 1022 | 1023 | //除底部进度条信息之外 底部的所有内容 1024 | this.videoCtrlDetail = document.createElement('div') 1025 | this.videoCtrlDetail.className = 'Dvideo-detail' 1026 | this.videoCtrl.appendChild(this.videoCtrlDetail) 1027 | 1028 | let _this = this 1029 | // 移动显示粗的进度条 1030 | _this.videoCtrl.onmouseenter = function () { 1031 | _this.showProgressRange() 1032 | } 1033 | // 关闭两个菜单控制栏的冒泡事件 1034 | _this.videoCtrl.onclick = function (e) { 1035 | e.stopPropagation(); 1036 | } 1037 | } 1038 | 1039 | createHeaderC () { 1040 | // 头部的信息 1041 | this.videoHeader = document.createElement('div') 1042 | this.videoHeader.className = 'Dvideo-header' 1043 | this.videoC.appendChild(this.videoHeader) 1044 | // 头部的title 1045 | this.videoHeaderTitle = document.createElement('p') 1046 | this.videoHeaderTitle.className = 'Dvideo-header-title' 1047 | this.videoHeaderTitle.innerText = this.opt.title 1048 | this.videoHeaderTitle.title = this.opt.title 1049 | this.videoHeader.appendChild(this.videoHeaderTitle) 1050 | 1051 | let _this = this 1052 | 1053 | // 关闭两个菜单控制栏的冒泡事件 1054 | _this.videoHeader.onclick = function (e) { 1055 | e.stopPropagation(); 1056 | } 1057 | 1058 | } 1059 | 1060 | // 放大缩小 1061 | createSelectVideoFull () { 1062 | // 放大缩小功能 1063 | let iconFullScreenITitle = this.isFull ? '全屏' : '取消全屏' 1064 | this.fullscreenConfig = document.createElement('i') 1065 | this.fullscreenConfig.className = 'Dvideo-menu-fullscreenConfig icon-fullscreen' 1066 | this.fullscreenConfig.title = iconFullScreenITitle 1067 | this.menuRightC.appendChild(this.fullscreenConfig) 1068 | // 初始全屏效果 1069 | this.updateFullScreenState(this.isFull) 1070 | 1071 | let _this = this 1072 | // 点击切换全屏与非全屏状态 1073 | _this.fullscreenConfig.onclick = function () { 1074 | if (_this.isFull) { 1075 | _this.exitFullscreen() 1076 | } else { 1077 | _this.launchFullScreen(_this.opt.ele) 1078 | } 1079 | } 1080 | } 1081 | 1082 | // 播放暂停包括下一集 1083 | createvideoPlayState () { 1084 | this.videoCtrlStateC = document.createElement('div') 1085 | this.videoCtrlStateC.className = 'Dvideo-ctrl-state' 1086 | this.videoCtrlDetail.appendChild(this.videoCtrlStateC) 1087 | 1088 | // 播放按钮 1089 | let iconPlayPauseClass = this.isPlaying ? 'icon-pause' : 'icon-play' 1090 | let iconPlayPauseITitle = this.isPlaying ? '暂停 space' : '播放 space' 1091 | this.videoPlayPauseI = document.createElement('i') 1092 | this.videoPlayPauseI.className = 'Dvideo-ctrl-playPause ' + iconPlayPauseClass 1093 | this.videoPlayPauseI.title = iconPlayPauseITitle 1094 | this.videoCtrlStateC.appendChild(this.videoPlayPauseI) 1095 | 1096 | // 下一集控制区域 1097 | let displayStyle = this.opt.showNext ? 'inline-block' : 'none' 1098 | this.videoNextI = document.createElement('i') 1099 | this.videoNextI.className = 'Dvideo-ctrl-next icon-nextdetail' 1100 | this.videoNextI.title = '下一集 next' 1101 | this.videoNextI.style.display = displayStyle 1102 | this.videoCtrlStateC.appendChild(this.videoNextI) 1103 | 1104 | let _this = this 1105 | // 播放下一集 1106 | _this.videoNextI.onclick = function () { 1107 | _this.nextVideo () 1108 | } 1109 | 1110 | // 播放暂停按钮 1111 | _this.videoPlayPauseI.onclick = function () { 1112 | if (_this.isPlaying) { 1113 | _this.videoPause() 1114 | } else { 1115 | _this.videoPlay() 1116 | } 1117 | } 1118 | } 1119 | 1120 | // 创建提示信息 1121 | createVideoTips () { 1122 | this.tipsInfo = document.createElement('div') 1123 | this.tipsInfo.className = 'Dvideo-tips-info' 1124 | this.videoCtrl.appendChild(this.tipsInfo) 1125 | } 1126 | 1127 | // 创建切换视频清晰度效果 1128 | createVideoDefinition () { 1129 | let showVClassName = this.opt.showVideoDefinitionUnFull ? '' : 'none' 1130 | let oFragment = document.createDocumentFragment(); 1131 | // 获取的数据 本地存储或者初始化的清晰度 1132 | let videoDefinitionData = this.hasLStorage('D-videoDefinition') ? JSON.parse(this.getLStorage('D-videoDefinition')) : this.opt.videoDefinition 1133 | // active索引 1134 | let videoDefinitionIndex = Number(videoDefinitionData.activeIndex) 1135 | // active类型 0 标清 1 高清 2 超清 1136 | let videoDefinitionType = videoDefinitionData.definitionList[videoDefinitionIndex].type 1137 | // active名字 0 标清 1 高清 2 超清 1138 | let videoDefinitionName = videoDefinitionData.definitionList[videoDefinitionIndex].name 1139 | 1140 | // 设置清晰度区域 1141 | this.videoDefinition = document.createElement('span') 1142 | this.videoDefinition.className = 'Dvideo-definition ' + showVClassName 1143 | this.menuRightC.appendChild(this.videoDefinition) 1144 | 1145 | // 显示清晰度文本 1146 | this.videoDefinitionText = document.createElement('span') 1147 | this.videoDefinitionText.className = 'Dvideo-definitionText' 1148 | this.videoDefinitionText.title = videoDefinitionName 1149 | this.videoDefinitionText.innerText = videoDefinitionName 1150 | this.videoDefinition.appendChild(this.videoDefinitionText) 1151 | 1152 | // 清晰度选项的内容 1153 | this.videoDefinitionC = document.createElement('div') 1154 | this.videoDefinitionC.className = 'Dvideo-definition-content' 1155 | this.videoDefinition.appendChild(this.videoDefinitionC) 1156 | 1157 | 1158 | for (let i = 0; i < videoDefinitionData.definitionList.length; i++) { 1159 | let videoDefinitionL = document.createElement('span') 1160 | if (i === videoDefinitionIndex) { 1161 | videoDefinitionL.className = 'Dvideo-definition-list active' 1162 | } else { 1163 | videoDefinitionL.className = 'Dvideo-definition-list' 1164 | } 1165 | videoDefinitionL.title = videoDefinitionData.definitionList[i].name 1166 | videoDefinitionL.innerText = videoDefinitionData.definitionList[i].name 1167 | videoDefinitionL.setAttribute('data-index', i) 1168 | videoDefinitionL.setAttribute('data-type', videoDefinitionData.definitionList[i].type) 1169 | oFragment.appendChild(videoDefinitionL) 1170 | } 1171 | this.videoDefinitionC.appendChild(oFragment) 1172 | 1173 | let _this = this 1174 | 1175 | // ====================设置语速交互 1176 | _this.videoDefinition.onmouseenter = function (event) { 1177 | _this.videoDefinitionC.style.display = 'block' 1178 | } 1179 | 1180 | _this.videoDefinition.onmouseleave = function (event) { 1181 | _this.videoDefinitionC.style.display = 'none' 1182 | } 1183 | 1184 | _this.videoDefinition.onclick = function (event) { 1185 | let e = event || window.event 1186 | _this.setVideoDefinition(e) 1187 | } 1188 | } 1189 | 1190 | // 创建设置音量的效果 1191 | createVolume () { 1192 | let showVClassName = this.opt.showVolumeUnFull ? '' : 'none' 1193 | // 设置清晰度区域 1194 | this.videoVolumeC = document.createElement('div') 1195 | this.videoVolumeC.className = 'Dvideo-volume ' + showVClassName 1196 | this.menuRightC.appendChild(this.videoVolumeC) 1197 | 1198 | // 进度线条 1199 | this.videoVolumeP = document.createElement('div') 1200 | this.videoVolumeP.className = 'Dvideo-volume-P' 1201 | this.videoVolumeC.appendChild(this.videoVolumeP) 1202 | 1203 | // 事实的进度信息 1204 | this.videoVolumeR = document.createElement('div') 1205 | this.videoVolumeR.className = 'Dvideo-volume-R' 1206 | this.videoVolumeP.appendChild(this.videoVolumeR) 1207 | 1208 | // 可拖动的小圆点 1209 | this.videoVolumeRange = document.createElement('div') 1210 | this.videoVolumeRange.className = 'Dvideo-volume-range' 1211 | this.videoVolumeC.appendChild(this.videoVolumeRange) 1212 | 1213 | // 初始化音量 有本地存储 设置过就使用本地存储 1214 | this.initVolume (); 1215 | 1216 | let isDrag = false 1217 | 1218 | let _this = this 1219 | let persent = 0 1220 | // 进度条拖动 (PC) 1221 | _this.videoVolumeRange.onmousedown = function (event) { 1222 | isDrag = true 1223 | let e = event || window.event 1224 | let x = e.clientX 1225 | let l = event.target.offsetLeft + 6 1226 | e.stopPropagation() 1227 | _this.maxVolumeWidth = _this.videoVolumeC.offsetWidth 1228 | 1229 | _this.videoVolumeC.onmousemove = function (event) { 1230 | if(isDrag) { 1231 | let e = event || window.event 1232 | let thisX = e.clientX 1233 | _this.dragVolumeTo = Math.min(_this.maxVolumeWidth, Math.max(0, l + (thisX - x))) 1234 | persent = _this.dragVolumeTo / _this.maxVolumeWidth 1235 | _this.updateVolume(persent); 1236 | } 1237 | } 1238 | 1239 | _this.videoVolumeC.onmouseup = function (event) { 1240 | isDrag = false 1241 | e.stopPropagation() 1242 | e.preventDefault() 1243 | // 本地存储 1244 | _this.setLStorage('Dvideo-volume', persent) 1245 | return 1246 | } 1247 | 1248 | _this.videoVolumeC.onmouseleave = function (event) { 1249 | isDrag = false 1250 | e.stopPropagation() 1251 | e.preventDefault() 1252 | // 本地存储 1253 | _this.setLStorage('Dvideo-volume', persent) 1254 | return 1255 | } 1256 | } 1257 | 1258 | _this.videoVolumeP.onclick = function (event) { 1259 | let e = event || window.event 1260 | // alert(e.target.offsetLeft) 1261 | let videoVolumeCW = _this.videoVolumeP.offsetWidth 1262 | let eW = e.offsetX 1263 | // console.log(videoVolumeCW) 1264 | _this.updateVolume(eW / videoVolumeCW); 1265 | } 1266 | } 1267 | 1268 | // 更新音量界面显示以及音量调整 1269 | updateVolume (persent) { 1270 | this.videoVolumeRange.style.left = persent * 100 + '%' 1271 | this.videoVolumeR.style.width = persent * 100 + '%' 1272 | this.videoVolumeRange.setAttribute('data-volume', Math.round(persent * 100)) 1273 | this.volume = persent 1274 | this.videoEle.volume = persent 1275 | // 本地存储 1276 | this.setLStorage('Dvideo-volume', persent) 1277 | } 1278 | 1279 | // 初始化音量 1280 | initVolume () { 1281 | if(this.getLStorage('Dvideo-volume') === null) { 1282 | this.updateVolume(0.8) 1283 | this.volume = 0.8 1284 | } else { 1285 | let persent = this.getLStorage('Dvideo-volume') 1286 | this.updateVolume(persent) 1287 | this.volume = persent 1288 | } 1289 | } 1290 | 1291 | // 根据class查找元素 1292 | getDomByClass(classInfo = '') { 1293 | if(!typeof(document.getElementsByClassName) === 'function'){ 1294 | let result=[]; 1295 | let aEle=document.getElementsByTagName('*'); 1296 | /*正则模式*/ 1297 | let re=new RegExp("\\b" + classInfo + "\\b","g"); 1298 | for(let i=0;i