编程知识 cdmana.com

Build a Vue configurable video player component from 0 to 1 (NPM released)

Preface

Don't talk much , This article is mainly about how to learn from 0 To 1 Build a model for Vue.js Custom configuration of video player . We usually PC When watching a video on a web site , You'll see a lot of rich video players , And we wrote it ourselves video The label style is so ugly . In fact, websites like these are all based on native video Tag development , It just needs to be properly processed , It's the beautiful video player we see .

Development

Before specific development , We need to be clear about what we need to do ?

  1. Package a configurable video player ;

  2. Apply to Vue.js;

  3. be applied to PC End site ;

  4. Common functions of video player must have ;

  5. Publish to Npm;

good , After making the above points clear , So we started typing the code .

One 、 Build a foundation for UI Components

there UI Component you can understand as we build a static page , It's a simple way to build a video player , There's a basic model .

`<template>    <div      class="video-box"    >      <video        class="video-player"      ></video>      <div class="bottom-tool">        <div class="pv-bar">          <div class="pv-played"></div>          <div class="pv-dot"></div>        </div>        <div class="pv-controls">          <div class="pc-con-l">            <div class="play-btn">              <i class="iconfont icon-bofang"></i>              <i class="iconfont icon-zanting hide"></i>            </div>            <div class="pv-time">              <span class="pv-currentTime">00:00:00</span>              <span>/</span>              <span class="pv-duration">00:00:00</span>            </div>          </div>          <div class="pc-con-r">            <div class="pv-listen ml">              <div class="pv-yl">                <p class="pv-ol"></p>                <p class="pv-bg"></p>              </div>              <div class="pv-iconyl">                <i class="iconfont icon-yinliang"></i>                <i class="iconfont icon-jingyin hide"></i>              </div>            </div>            <div class="pv-speed ml">              <p class="pv-spnum">1x</p>              <ul class="selectList">                <li>0.5x</li>                <li>1x</li>                <li>1.25x</li>                <li>1.5x</li>                <li>2x</li>              </ul>            </div>            <div class="pv-screen ml">              <i class="iconfont icon-quanping"></i>              <i class="iconfont icon-huanyuan hide"></i>            </div>            <div class="pv-screens ml">              <i class="iconfont icon-shipinquanping"></i>              <i class="iconfont icon-tuichuquanping hide"></i>            </div>          </div>        </div>      </div>    </div>  </template>  <script>  export default {    name: "VamVideo"  };  </script>  <style scoped>  @import "./css/iconfont/iconfont.css";  @import "./css/index.css";  </style>  `

I won't show the style file here , I will give the source address at the end of the article .

Two 、 Development logic execution file

The most critical part is the logic file , The way I use constructors here .

``// eslint-disable-next-line no-unused-vars  function VamVideo(vp, attrObj, styleObj) {    //  initialization     this.timer = null;    this.disX = 0;    this.disL = 0;    this.isPageFullScreen = false;    //  Processing video properties     for (const key in attrObj) {      if (Object.hasOwnProperty.call(attrObj, key) && key !== "controls") {        $(".video-player").setAttribute(key, attrObj[key]);      }    }    //  Dealing with video styles     for (const key in styleObj) {      if (Object.hasOwnProperty.call(styleObj, key)) {        $(".video-box").style[`${key}`] = styleObj[key];        key === "width"          ? (this.vbw = styleObj.width)          : (this.vbw = vp.offsetWidth);        key === "height"          ? (this.vbh = styleObj.height)          : (this.vbh = vp.offsetHeight);      }    }    //  Encapsulate get element node     function $(el) {      return document.querySelector(el);    }    //  Processing the current time     function nowTime() {      $(".pv-currentTime").innerHTML = changeTime($(".video-player").currentTime);      let scale = $(".video-player").currentTime / $(".video-player").duration;      let w = $(".pv-bar").offsetWidth - $(".pv-dot").offsetWidth;      $(".pv-dot").style.left = scale * w + "px";      $(".pv-played").style.width = scale * w + "px";    }    //  Processing time, minutes and seconds     function changeTime(iNum) {      let iN = parseInt(iNum);      const iH = toZero(Math.floor(iN / 3600));      const iM = toZero(Math.floor((iN % 3600) / 60));      const iS = toZero(Math.floor(iN % 60));      return iH + ":" + iM + ":" + iS;    }    //  repair 0    function toZero(num) {      if (num <= 9) {        return "0" + num;      } else {        return "" + num;      }    }    //  Element display     this.showEl = function (el) {      $(el).style.display = "block";    };    //  Hidden elements     this.hideEl = function (el) {      $(el).style.display = "none";    };    //  Set video width and height dynamically     this.setVp = function (w, h) {      const _w = String(w).indexOf("px") != -1 ? w : w + "px";      const _h = String(h).indexOf("px") != -1 ? h : h + "px";      $(".video-player").style.width = _w;      $(".video-player").style.height = _h;      $(".video-box").style.width = _w;      $(".video-box").style.height = _h;      $(".pv-bar").style.width = _w;    };    //  Bottom control bar ( Show / hide )    this.bottomTup = function () {      $(".bottom-tool").style.bottom = "0px";    };    this.bottomTdow = function () {      $(".bottom-tool").style.bottom = "-45px";    };    //  Play / Pause     this.usePlay = function () {      if ($(".video-player").paused) {        $(".video-player").play();        this.hideEl(".icon-bofang");        this.showEl(".icon-zanting");        nowTime();        this.timer = setInterval(nowTime, 1000);      } else {        $(".video-player").pause();        this.showEl(".icon-bofang");        this.hideEl(".icon-zanting");        clearInterval(this.timer);      }    };    this.isplay = function () {      this.usePlay();    };    //  Total duration     this.useOnplay = function () {      $(".pv-duration").innerHTML = changeTime($(".video-player").duration);    };    //  End of play     this.useEnd = function () {      this.showEl(".icon-bofang");      this.hideEl(".icon-zanting");    };    //  Mute     this.useVolume = function () {      if ($(".video-player").muted) {        $(".video-player").volume = 1;        this.hideEl(".icon-jingyin");        this.showEl(".icon-yinliang");        $(".video-player").muted = false;      } else {        $(".video-player").volume = 0;        this.showEl(".icon-jingyin");        this.hideEl(".icon-yinliang");        $(".video-player").muted = true;      }    };    //  Full screen     this.pageFullScreen = function () {      const w = document.documentElement.clientWidth || document.body.clientWidth;      const h =        document.documentElement.clientHeight || document.body.clientHeight;      this.isPageFullScreen = !this.isPageFullScreen;      if (this.isPageFullScreen) {        this.setVp(w, h);        this.hideEl(".icon-quanping");        this.showEl(".icon-huanyuan");        this.hideEl(".pv-screens");      } else {        this.setVp(this.vbw, this.vbh);        this.showEl(".icon-quanping");        this.hideEl(".icon-huanyuan");        this.showEl(".pv-screens");      }    };    //  Window full screen     this.fullScreen = function () {      const el = $(".video-box");      const isFullscreen =        document.fullScreen ||        document.mozFullScreen ||        document.webkitIsFullScreen;      if (!isFullscreen) {        this.showEl(".icon-tuichuquanping");        this.hideEl(".icon-shipinquanping");        this.hideEl(".pv-screen");        (el.requestFullscreen && el.requestFullscreen()) ||          (el.mozRequestFullScreen && el.mozRequestFullScreen()) ||          (el.webkitRequestFullscreen && el.webkitRequestFullscreen()) ||          (el.msRequestFullscreen && el.msRequestFullscreen());      } else {        this.showEl(".icon-shipinquanping");        this.hideEl(".icon-tuichuquanping");        this.showEl(".pv-screen");        document.exitFullscreen          ? document.exitFullscreen()          : document.mozCancelFullScreen          ? document.mozCancelFullScreen()          : document.webkitExitFullscreen          ? document.webkitExitFullscreen()          : "";      }    };    //  Play progress bar     this.useTime = function (ev) {      let ev1 = ev || window.event;      this.disX = ev1.clientX - $(".pv-dot").offsetLeft;      document.onmousemove = (ev) => {        let ev2 = ev || window.event;        let L = ev2.clientX - this.disX;        if (L < 0) {          L = 0;        } else if (L > $(".pv-bar").offsetWidth - $(".pv-dot").offsetWidth) {          L = $(".pv-bar").offsetWidth - $(".pv-dot").offsetWidth;        }        $(".pv-dot").style.left = L + "px";        let scale = L / ($(".pv-bar").offsetWidth - $(".pv-dot").offsetWidth);        $(".video-player").currentTime = scale * $(".video-player").duration;        nowTime();      };      document.onmouseup = function () {        document.onmousemove = null;      };      return false;    };    //  Volume control     this.useListen = function (ev) {      let ev1 = ev || window.event;      this.disL = ev1.clientX - $(".pv-ol").offsetLeft;      document.onmousemove = (ev) => {        let ev2 = ev || window.event;        let L = ev2.clientX - this.disL;        if (L < 0) {          L = 0;        } else if (L > $(".pv-yl").offsetWidth - $(".pv-ol").offsetWidth) {          L = $(".pv-yl").offsetWidth - $(".pv-ol").offsetWidth;        }        $(".pv-ol").style.left = L + "px";        let scale = L / ($(".pv-yl").offsetWidth - $(".pv-ol").offsetWidth);        $(".pv-bg").style.width = $(".pv-ol").offsetLeft + "px";        if ($(".pv-ol").offsetLeft !== 0) {          this.showEl(".icon-yinliang");          this.hideEl(".icon-jingyin");        } else {          this.showEl(".icon-jingyin");          this.hideEl(".icon-yinliang");        }        $(".video-player").volume = scale;      };      document.onmouseup = function () {        document.onmousemove = null;      };      return false;    };    //  Broadcasting speed     this.useSpnum = function (e) {      let ev = e || window.event;      $(".pv-spnum").innerText = ev.target.innerText;      const value = ev.target.innerText.replace("x", "");      $(".video-player").playbackRate = value;    };  }  //  export   export default VamVideo;  ``

3、 ... and 、 Integrate component logic

To develop the UI Components and logical components , So we're going to combine the two .

`<template>    <div      class="video-box"      @mouseenter="vp.bottomTup()"      @mouseleave="vp.bottomTdow()"    >      <video        class="video-player"        @canplay="vp.useOnplay()"        @ended="vp.useEnd()"        @click="vp.isplay()"      ></video>      <div class="bottom-tool">        <div class="pv-bar">          <div class="pv-played"></div>          <div class="pv-dot" @mousedown="vp.useTime()"></div>        </div>        <div class="pv-controls">          <div class="pc-con-l">            <div class="play-btn" @click="vp.usePlay()">              <i class="iconfont icon-bofang"></i>              <i class="iconfont icon-zanting hide"></i>            </div>            <div class="pv-time">              <span class="pv-currentTime">00:00:00</span>              <span>/</span>              <span class="pv-duration">00:00:00</span>            </div>          </div>          <div class="pc-con-r">            <div class="pv-listen ml">              <div class="pv-yl">                <p class="pv-ol" @mousedown="vp.useListen()"></p>                <p class="pv-bg"></p>              </div>              <div class="pv-iconyl" @click="vp.useVolume()">                <i class="iconfont icon-yinliang"></i>                <i class="iconfont icon-jingyin hide"></i>              </div>            </div>            <div class="pv-speed ml">              <p class="pv-spnum">1x</p>              <ul class="selectList" @click="vp.useSpnum()">                <li>0.5x</li>                <li>1x</li>                <li>1.25x</li>                <li>1.5x</li>                <li>2x</li>              </ul>            </div>            <div class="pv-screen ml" @click="vp.pageFullScreen()">              <i class="iconfont icon-quanping"></i>              <i class="iconfont icon-huanyuan hide"></i>            </div>            <div class="pv-screens ml" @click="vp.fullScreen()">              <i class="iconfont icon-shipinquanping"></i>              <i class="iconfont icon-tuichuquanping hide"></i>            </div>          </div>        </div>      </div>    </div>  </template>  <script>  import VamVideo from "./vp.js";  export default {    name: "VamVideo",    data: () => ({      vp: null,      defaultStyle: {        width: "1200px",        height: "600px",      },    }),    props: {      properties: {        type: Object,      },      videoStyle: {        type: Object,      },    },    mounted() {      this.vp = new VamVideo(        document.querySelector(".video-box"),        this.properties,        Object.keys(this.videoStyle).length === 0          ? this.defaultStyle          : this.videoStyle      );    },  };  </script>  <style scoped>  @import "./css/iconfont/iconfont.css";  @import "./css/index.css";  </style>  `

First of all, we introduce the logic file that we developed before vp.js, And then in mounted Method for class VamVideo instantiate , Assign to this.vp. The parameters passed to the class are The outermost node Video properties Video style .props Attribute properties For video properties ,videoStyle For video style .

Four 、 Release components

Completed the development of the above steps , We need to publish our finished components to Npm On .

1. initialization

Create an empty folder , We can call it v-vamvideo. Type the command... In this folder :

`npm init -y  `

Because we still need to modify , So create... Directly package.json file .

`{    "name": "vue-vam-video",    "version": "1.0.0",    "description": "Vue.js Custom video components",    "main": "index.js",    "author": "maomincoding",    "keywords": ["video"],    "license": "ISC",    "private": false  }  `
  • name: Component name

  • author:Npm user name

  • main: Entrance file

  • version: Version number , This field is required to update the component

  • description: describe

  • license According to the above

  • keywords by : Search keywords

  • private Set to false, Open source, so you need to change this field to false

2. Import components

Copy our previously packaged components to v-vamvide In this folder , The following figure is the component file directory that we packaged before .

3. Create an entry file

We're going to post it to Npm You need an entry file on , We are v-vamvide Create an entry file in the root directory , We call it index.js.

`//  Import components   import VamVideo from "./VamVideo/vamvideo.vue";  //  Components need to be added name attribute , Represents the registered component name   VamVideo.install = (Vue) => Vue.component(VamVideo.name, VamVideo); // Certified components   export default VamVideo;  `

4. Create a documentation

Publish to Npm On , Users need to know what this component does ? How to use it? ? We are v-vamvide Create a document in the root directory , named README.md

``# vue-vamvideo  > Vue.js Custom video components  ## Using documents  1. Introducing components  2. configuration parameter  - `properties`: Video properties.  - `videoStyle`: Video style.  These two parameters need to be set separately.  ***  <template>    <div id="app">   <vam-video :properties="videoOption.properties" :videoStyle="videoOption.videoStyle"></vam-video>    </div>  </template>  <script>  export default {    name: "Index",    data: () => ({   videoOption: {   properties: {   poster: require("./img/bg.png"),   src:   "https://mos-vod-drcn.dbankcdn.cn/P_VT/video_injection/A91343E9D/v3/9AB0A7921049102362779584128/MP4Mix_H.264_1920x1080_6000_HEAAC1_PVC_NoCut.mp4",   preload: "auto",   loop: "loop",   // autoplay:"autoplay",   // muted:true,   // controls:"controls"   },   videoStyle: {   // width: "1200px",   // height: "600px",   },   },    })  };  </script>  ***  ``

We are very close to success , So thank you for reading this . Source code address :https://github.com/maomincoding/vue-vam-video

5. Release

Before you begin the following steps , You need to switch the command line to the project root ( That's what we have here v-vamvide This folder ).

  1. Check whether the login source is http://registry.npmjs.org
`npm config get registry  `

If not , Switch login source .

`npm config set registry=http://registry.npmjs.org  `
  1. Sign in Npm
`npm login  `

Enter the user name one after the other 、 password 、 mailbox . Enter appears Logged in as maomincoding on http://registry.npmjs.org, So the login is successful .

  1. Upload and publish to Npm
`npm publish  `

5、 ... and 、 Installation of components

Now that we've published it Npm On , We can go Npm See the effect on the website .

`https://www.npmjs.com/package/vue-vam-video  `

The component was released successfully , So we put it in Vue Test it in engineering .

  1. Installation of components
`npm i vue-vam-video  `
  1. Certified components

Global registration

`import Vue from 'vue'  import App from './App.vue'  //  Global registration   import VamVideo from "vue-vam-video";  Vue.use(VamVideo);  Vue.config.productionTip = false  new Vue({    render: h => h(App),  }).$mount('#app')  `

`




`

** Partial registration **

`




`

```

  1. effect Be accomplished !

Conclusion

Thank you for reading , If it works , Don't forget to press the button three times ~

  • Welcome to my official account. The road ahead

  • Reply key words e-book , Can get 12 This front-end hot e-book .

  • Reply key words Red Treasure Book No 4 edition , Get the latest 《JavaScript Advanced programming 》( The Fourth Edition ) e-book .

  • After the official account , Click the menu below to add me wechat , I've drawn a lot of IT bosses , Created a technology exchange 、 Article sharing group , Looking forward to your joining .

  • author :Vam The golden bean road

  • WeChat official account : The road ahead

- END -

This article is from the official account of WeChat The road ahead original https://www.helloworld.net/redirect?target=https://mp.weixin.qq.com/s/vrHGiurc0gIJXG7n9oUDGQ, If there is any infringement , Please contact to delete .

版权声明
本文为[Jacquelyn38]所创,转载请带上原文链接,感谢
https://cdmana.com/2021/05/20210525010153319B.html

Scroll to Top