Notes for a front-end developer, esyou.net

0%

个性化HTML5中的VIDEO,打造属于自己的HTML5视频播放器

本文使用的都是CSS3以及html5中的video实现的播放器,在PC与手机端都可以完美播放,目前还未实现播放进度条的拖移功能,后续会增加这个功能。
demo效果查看地址:https://king2088.github.io/html5-vPlayer/
先看效果图:

首先我们要了解一下html5中的media事件以及属性

html5 Media api

*loadstart
*progress
*suspend
*abort
*error
*emptied
*stalled
*loadedmetadata
*loadeddata
*canplay
*canplaythrough
*playing
*waiting
*seeking
*seeked
*ended
*durationchange
*timeupdate
*play
*pause
*ratechange
*resize
*volumechange

Media properties

[ “error”, “src”, “srcObject”, “currentSrc”, “crossOrigin”, “networkState”, “preload”, “buffered”, “readyState”, “seeking”, “currentTime”, “duration”, “paused”, “defaultPlaybackRate”, “playbackRate”, “played”, “seekable”, “ended”, “autoplay”, “loop”, “controls”, “volume”, “muted”, “defaultMuted”, “audioTracks”, “videoTracks”, “textTracks”, “width”, “height”, “videoWidth”, “videoHeight”, “poster” ]
3、CSS部分代码

1
*,
2
html,
3
body,
4
video {
5
  margin: 0;
6
  padding: 0;
7
}
8
* #vPlayer,
9
html #vPlayer,
10
body #vPlayer,
11
video #vPlayer {
12
  width: 100%;
13
  background: #000;
14
  position: relative;
15
  overflow: hidden;
16
}
17
* #playerContent,
18
html #playerContent,
19
body #playerContent,
20
video #playerContent {
21
  width: 100%;
22
  background: #000;
23
  display: block;
24
}
25
* #playerControler,
26
html #playerControler,
27
body #playerControler,
28
video #playerControler {
29
  width: 100%;
30
  z-index: 99999999;
31
  position: absolute;
32
  bottom: 2px;
33
  left: 0;
34
  padding: 4px 0;
35
  opacity: 1;
36
}
37
* #playerControler:after,
38
html #playerControler:after,
39
body #playerControler:after,
40
video #playerControler:after {
41
  content: '';
42
  display: block;
43
  height: 0;
44
  clear: both;
45
}
46
* #playerControler .playButtonWrap,
47
html #playerControler .playButtonWrap,
48
body #playerControler .playButtonWrap,
49
video #playerControler .playButtonWrap {
50
  width: 24px;
51
  height: 24px;
52
  border-radius: 14px;
53
  border: 2px #ccc solid;
54
  margin-left: 8px;
55
  float: left;
56
}
57
* #playerControler .playButtonWrap .playButton,
58
html #playerControler .playButtonWrap .playButton,
59
body #playerControler .playButtonWrap .playButton,
60
video #playerControler .playButtonWrap .playButton {
61
  margin: 4px 0 0 8px;
62
  width: 0;
63
  height: 0;
64
  border-bottom: 8px solid transparent;
65
  border-top: 8px solid transparent;
66
  border-left: 10px solid #ccc;
67
}
68
* #playerControler .playButtonWrap .pauseButton,
69
html #playerControler .playButtonWrap .pauseButton,
70
body #playerControler .playButtonWrap .pauseButton,
71
video #playerControler .playButtonWrap .pauseButton {
72
  margin: 6px 0 0 8px;
73
  width: 5px;
74
  height: 12px;
75
  border-left: 2px #ccc solid;
76
  border-right: 2px #ccc solid;
77
  display: none;
78
}
79
* #playerControler #vplayerTimeLine,
80
html #playerControler #vplayerTimeLine,
81
body #playerControler #vplayerTimeLine,
82
video #playerControler #vplayerTimeLine {
83
  color: #ccc;
84
  line-height: 30px;
85
  font-size: 12px;
86
  float: left;
87
  margin-left: 2%;
88
}
89
* #playerControler .vPlayVolumeWrap,
90
html #playerControler .vPlayVolumeWrap,
91
body #playerControler .vPlayVolumeWrap,
92
video #playerControler .vPlayVolumeWrap {
93
  float: right;
94
  margin: 6px 10% 0 0;
95
  width: 25%;
96
}
97
* #playerControler .vPlayVolumeWrap #volumeIcon,
98
html #playerControler .vPlayVolumeWrap #volumeIcon,
99
body #playerControler .vPlayVolumeWrap #volumeIcon,
100
video #playerControler .vPlayVolumeWrap #volumeIcon {
101
  width: 0px;
102
  height: 0px;
103
  padding: 5px 3px;
104
  border-width: 5px 10px 5px 0px;
105
  border-color: transparent #ccc transparent transparent;
106
  border-style: solid;
107
/*喇叭效果*/
108
  -webkit-box-shadow: inset 15px 0 #666;
109
  -moz-box-shadow: inset 15px 0 #666;
110
  box-shadow: inset 15px 0 #666;
111
  float: left;
112
  display: inline-block;
113
}
114
* #playerControler .vPlayVolumeWrap #vPlayVolume,
115
html #playerControler .vPlayVolumeWrap #vPlayVolume,
116
body #playerControler .vPlayVolumeWrap #vPlayVolume,
117
video #playerControler .vPlayVolumeWrap #vPlayVolume {
118
  width: 70%;
119
  height: 2px;
120
  background: #ccc;
121
  position: relative;
122
  float: left;
123
  margin: 10px 0 0 10px;
124
  display: inline-block;
125
}
126
* #playerControler .vPlayVolumeWrap #vPlayVolume #dragBar,
127
html #playerControler .vPlayVolumeWrap #vPlayVolume #dragBar,
128
body #playerControler .vPlayVolumeWrap #vPlayVolume #dragBar,
129
video #playerControler .vPlayVolumeWrap #vPlayVolume #dragBar {
130
  width: 8px;
131
  height: 8px;
132
  border-radius: 4px;
133
  background: #369;
134
  position: absolute;
135
  top: -3px;
136
  left: 0;
137
  cursor: pointer;
138
}
139
* #playerControler .vPlayVolumeWrap #vPlayVolume #dragMask,
140
html #playerControler .vPlayVolumeWrap #vPlayVolume #dragMask,
141
body #playerControler .vPlayVolumeWrap #vPlayVolume #dragMask,
142
video #playerControler .vPlayVolumeWrap #vPlayVolume #dragMask {
143
  position: absolute;
144
  left: 0;
145
  top: 0;
146
  background: #369;
147
  width: 0;
148
  height: 2px;
149
}
150
* #playerControler #fullScreen,
151
html #playerControler #fullScreen,
152
body #playerControler #fullScreen,
153
video #playerControler #fullScreen {
154
  width: 24px;
155
  height: 24px;
156
  float: right;
157
  margin: 5px 2% 0 0;
158
  display: block;
159
  background: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAA/UlEQVRIS91V2w3CMAy8qP0HNoAJoOrtQ9mgI8AEiAlgBAZxJEaADWCBGqUqUktbkSAVAfmMH+ezk7PBwMcMnB+fB7DW5kVRLI0xixq7K8lJna2IXAGMandnVT3GcbxJksTZytNg4JKr6rajbTeS4xcAD/OOZN4JICInAHNjzCpN00PIfGrFnUnO+gDUGUi+NRsRacU3EnU5hLD4CoBy+s8D9WVRvaxG/Fu99gVsPdOQQF/fP2NQDUmfZcG3HV3x//cPBpeKUuwA5CR3vr13ftbaTFX3AC4kp6Fy7bMPXst1VYnbCVnF5BHksw8uAI5RFK17F05IS3x9f/8n3wFQDZcZDw/gGQAAAABJRU5ErkJggg==") no-repeat center;
160
}
161
* #progressBar,
162
html #progressBar,
163
body #progressBar,
164
video #progressBar {
165
  width: 100%;
166
  background: #333;
167
  height: 2px;
168
  position: absolute;
169
  bottom: 0;
170
  display: block;
171
}
172
* #progressBar .reloadProgress,
173
html #progressBar .reloadProgress,
174
body #progressBar .reloadProgress,
175
video #progressBar .reloadProgress {
176
  width: 0;
177
  height: 2px;
178
  background: #ccc;
179
  position: relative;
180
  left: 0;
181
  top: 0;
182
  z-index: 999;
183
}
184
* #progressBar .reloadProgress .progress,
185
html #progressBar .reloadProgress .progress,
186
body #progressBar .reloadProgress .progress,
187
video #progressBar .reloadProgress .progress {
188
  width: 0;
189
  height: 2px;
190
  background: #008b8b;
191
  position: absolute;
192
  left: 0;
193
  top: 0;
194
  z-index: 9999;
195
}
196
* .fadeIn,
197
html .fadeIn,
198
body .fadeIn,
199
video .fadeIn {
200
  animation-name: fadeIn;
201
}
202
* .fadeOut,
203
html .fadeOut,
204
body .fadeOut,
205
video .fadeOut {
206
  animation-name: fadeOut;
207
}
208
@-moz-keyframes fadeIn {
209
  from {
210
    opacity: 0;
211
  }
212
  to {
213
    opacity: 1;
214
  }
215
}
216
@-webkit-keyframes fadeIn {
217
  from {
218
    opacity: 0;
219
  }
220
  to {
221
    opacity: 1;
222
  }
223
}
224
@-o-keyframes fadeIn {
225
  from {
226
    opacity: 0;
227
  }
228
  to {
229
    opacity: 1;
230
  }
231
}
232
@keyframes fadeIn {
233
  from {
234
    opacity: 0;
235
  }
236
  to {
237
    opacity: 1;
238
  }
239
}
240
@-moz-keyframes fadeOut {
241
  from {
242
    opacity: 1;
243
  }
244
  to {
245
    opacity: 0;
246
  }
247
}
248
@-webkit-keyframes fadeOut {
249
  from {
250
    opacity: 1;
251
  }
252
  to {
253
    opacity: 0;
254
  }
255
}
256
@-o-keyframes fadeOut {
257
  from {
258
    opacity: 1;
259
  }
260
  to {
261
    opacity: 0;
262
  }
263
}
264
@keyframes fadeOut {
265
  from {
266
    opacity: 1;
267
  }
268
  to {
269
    opacity: 0;
270
  }
271
}
272
video::-webkit-media-controls,
273
video::-moz-media-controls,
274
video::-webkit-media-controls-enclosure {
275
  display: none !important;
276
}
277
video::-webkit-media-controls-panel,
278
video::-webkit-media-controls-panel-container,
279
video::-webkit-media-controls-start-playback-button {
280
  display: none !important;
281
  -webkit-appearance: none;
282
}

4、html部分代码

1
<!DOCTYPE html>
2
<html lang="en">
3
<head>
4
    <meta charset="UTF-8">
5
    <meta name="viewport" content="width=device-width, initial-scale=1, user-scalable=no">
6
    <title>vPlayer</title>
7
    <link rel="stylesheet" href="css/style.css">
8
9
</head>
10
<body>
11
    <div id="vPlayer">
12
        <video id="playerContent">
13
            <!--<source src="http://media.w3.org/2010/05/sintel/trailer.webm" type='video/webm;codecs="vp8, vorbis"'/>-->
14
            <source src="http://media.w3.org/2010/05/bunny/movie.mp4" type='video/mp4;codecs="avc1.42E01E, mp4a.40.2"'/>
15
        </video>
16
        <div id="playerControler">
17
            <div class="playButtonWrap">
18
                <div id="play" class="playButton"></div>
19
                <div id="pause" class="pauseButton"></div>
20
            </div>
21
            <div id="vplayerTimeLine"></div>
22
            <div id="fullScreen"></div>
23
            <div class="vPlayVolumeWrap">
24
                <div id="volumeIcon"></div>
25
                <div id="vPlayVolume">
26
                    <div id="dragBar"></div>
27
                    <div id="dragMask"></div>
28
                </div>
29
            </div>
30
31
        </div>
32
        <div id="progressBar">
33
            <div class="reloadProgress">
34
                <div class="progress"></div>
35
            </div>
36
        </div>
37
    </div>
38
    <script src="js/man.js"></script>
39
</body>
40
</html>

5、javascript部分代码

1
"use strict"
2
window.onload = function () {
3
    var vPlayer = document.getElementById('vPlayer')
4
    var playerContent = document.getElementById('playerContent')
5
    var playerControl = document.getElementById('playerControler')
6
    var play = document.getElementById('play')
7
    var pause = document.getElementById('pause')
8
    var reloadProgressDOM = document.getElementById('progressBar')
9
    var progressTimeShowDOM = document.getElementById('vplayerTimeLine')
10
    var volumeIconDOM = document.getElementById('volumeIcon')
11
    var vPlayVolumeDOM = document.getElementById('vPlayVolume')
12
    var dragBarDOM = document.getElementById('dragBar')
13
    var dragMaskDOM = document.getElementById('dragMask')
14
    var fullscreen = document.getElementById('fullScreen')
15
    var _playerControlHidden,_playTime
16
17
    var isSupportTouch = 'ontouchend' in document ? true : false;
18
    // console.log('isSupportTouc',isSupportTouch)
19
    playerContent.controls = false
20
    playerContent.preload = 'auto'
21
22
    //3000ms hidden player
23
    playerControlHidden()
24
    //play
25
    play.onclick = function () {
26
        vPlayerPlay()
27
    }
28
    // play.ontouchstart = function () {
29
    //     vPlayerPlay()
30
    // }
31
32
    //pause
33
    pause.onclick = function () {
34
        vPlayerPause()
35
    }
36
    // pause.ontouchstart = function () {
37
    //     vPlayerPause()
38
    // }
39
    //show player control
40
    if(!isSupportTouch){
41
        playerContent.addEventListener('mouseover',playerControlShow)
42
    }else{
43
        playerContent.addEventListener('touchstart',playerControlShow)
44
    }
45
46
    //hidden player control
47
    if(!isSupportTouch){
48
        playerContent.addEventListener('mouseleave',playerControlHidden)
49
    }else{
50
        playerContent.addEventListener('touchend',playerControlHidden)
51
    }
52
53
    function vPlayerPlay() {
54
        progressBar()
55
        playerContent.play()
56
        play.style.display = 'none';
57
        pause.style.display = 'block';
58
    }
59
60
    function vPlayerPause() {
61
        if(_playTime){
62
            clearInterval(_playTime)
63
        }
64
        playerContent.pause()
65
        pause.style.display = 'none';
66
        play.style.display = 'block';
67
    }
68
69
    function playerControlShow() {
70
        // console.log('start')
71
        if(_playerControlHidden){
72
            clearTimeout(_playerControlHidden)
73
        }
74
        if(!playerControl.style.opacity) return
75
        playerControl.style.display = 'block'
76
        playerControl.style.animation = 'fadeIn 1s'
77
        playerControl.style.opacity = 1
78
    }
79
80
    function playerControlHidden() {
81
        // console.log('hidden')
82
        _playerControlHidden = setTimeout(function () {
83
            playerControl.style.animation = 'fadeOut 1s'
84
            playerControl.style.opacity = 0
85
            playerControl.style.display = 'none'
86
        },3000)
87
    }
88
89
    function progressBar() {
90
        _playTime = setInterval(function () {
91
            // console.log(playerContent.buffered.end(0))
92
            //reload progress time (加载的时间/总时间)*100 = 加载的百分比
93
            var reloadProgressTime = (playerContent.buffered.end(0) / playerContent.duration) * 100
94
            reloadProgressDOM.children[0].style.width = reloadProgressTime + '%'
95
96
            //progress time = (playerContent.currentTime/playerContent.duration)*100
97
            var progressTime = playerContent.currentTime
98
            reloadProgressDOM.children[0].children[0].style.width = (progressTime / playerContent.duration) * 100 + '%'
99
100
            //progress time show
101
            progressTimeShowDOM.innerText = secToTime(progressTime)+' | '+secToTime(playerContent.duration)
102
            // console.log(playerContent.duration,playerContent.currentTime,playerContent.buffered.end(0))
103
            if(playerContent.currentTime === playerContent.duration){
104
                clearInterval(_playTime)
105
                vPlayerPause()
106
                reloadProgressDOM.children[0].children[0].style.width = 0
107
            }
108
        },1)
109
    }
110
111
    //volume drag control
112
    playerContent.volume = 0.5
113
    dragMaskDOM.style.width = '50%'
114
    dragBarDOM.style.left = '50%'
115
116
    if(!isSupportTouch) {
117
        dragBarDOM.onmousedown = function (event) {
118
            drag(event, this)
119
        }
120
    }else {
121
        dragBarDOM.ontouchstart = function (event) {
122
            console.log(event)
123
            drag(event, this)
124
        }
125
    }
126
127
    /**
128
     * drag element
129
     * @param event event
130
     * @param ele element
131
     */
132
    function drag(event,ele) {
133
        var event = event || window.event;
134
        var lengthX
135
        if(!isSupportTouch){
136
            lengthX = event.clientX - ele.offsetLeft;
137
        }else {
138
            lengthX = event.touches[0].clientX - ele.offsetLeft;
139
        }
140
141
        if(!isSupportTouch) {
142
            document.onmousemove = function (event) {
143
                dragMove(event,ele,lengthX)
144
            }
145
        }else{
146
            document.ontouchmove = function (event) {
147
                dragMove(event,ele,lengthX)
148
            }
149
        }
150
    }
151
152
    /**
153
     * drag move volume: volume+ volume-
154
     * @param event event
155
     * @param ele element
156
     * @param x lengthX:clientX
157
     */
158
    function dragMove(event,ele,x) {
159
        var event = event || window.event;
160
        var barleft
161
        if(!isSupportTouch) {
162
            barleft = event.clientX - x;
163
        }else {
164
            barleft = event.touches[0].clientX - x;
165
        }
166
        if(barleft < 0)
167
            barleft = 0;
168
        else if(barleft > vPlayVolumeDOM.offsetWidth - dragBarDOM.offsetWidth)
169
            barleft = vPlayVolumeDOM.offsetWidth - dragBarDOM.offsetWidth;
170
        dragMaskDOM.style.width = barleft +'px' ;
171
        ele.style.left = barleft + 'px';
172
        var volumeValue = barleft/(vPlayVolumeDOM.offsetWidth-dragBarDOM.offsetWidth)
173
        // console.log(volumeValue)
174
        playerContent.volume = parseFloat(volumeValue)
175
        //防止选择内容--当拖动鼠标过快时候,弹起鼠标,bar也会移动,修复bug
176
        window.getSelection ? window.getSelection().removeAllRanges() : document.selection.empty();
177
    }
178
179
    document.onmouseup = function(){
180
        document.onmousemove = null; //移除事件
181
    }
182
    document.ontouchend = function () {
183
        document.ontouchstart = null
184
        document.ontouchmove = null
185
    }
186
187
    volumeIconDOM.onclick = function () {
188
        if(playerContent.volume != 0){
189
            playerContent.volume = 0
190
            dragMaskDOM.style.width = '0'
191
            dragBarDOM.style.left = '0'
192
        }else{
193
            playerContent.volume = 0.5
194
            dragMaskDOM.style.width = '50%'
195
            dragBarDOM.style.left = '50%'
196
        }
197
    }
198
199
    //video fullscreen
200
    fullscreen.onclick = function () {
201
        if(playerContent.webkitRequestFullScreen){
202
            playerContent.webkitRequestFullScreen()
203
        }else if(playerContent.mozRequestFullScreen){
204
            playerContent.mozRequestFullScreen()
205
        }else {
206
            playerContent.requestFullscreen()
207
        }
208
    }
209
    console.log('networkState',playerContent.networkState)
210
211
    /**
212
     * format second to hh:mm:ss
213
     * @param second second
214
     * @returns {*} format time to 00:00:00
215
     */
216
    var secToTime = function (second) {
217
        var t
218
        if(second > -1){
219
            var hour = Math.floor(second/3600)
220
            var min = Math.floor(second/60) % 60
221
            var sec = second % 60
222
            if(hour < 10) {
223
                t = '0'+ hour + ":"
224
            } else {
225
                t = hour + ":"
226
            }
227
            if(min < 10){t += "0"}
228
            t += min + ":"
229
            if(sec < 10){t += "0"}
230
            t += sec.toFixed(0)
231
        }
232
        return t
233
    }
234
}

整个项目很简单,希望能够帮助到准备进入video事件以及视频处理的同学,此项目已经上传到github,如果你喜欢,请记得给我加星哦!
github:https://github.com/king2088/html5-vPlayer