vue+node.js手把手教你搭建一个直播平台(三)

上一期,帅气的小羽给老铁们介绍了直播平台的项目的前端框架的搭建,这期就让小羽带大家切图,没错啦,就是老铁们心心念念的切图啦。

补充上期遗漏的内容

但是在正式开启这期内容前,先补充点上期的内容

配置全局less

在assets文件夹下新增style/common.less

@primary-color:#2d8cf0;
.live-line{
    height: 1px;
    background: #eeeeee;
}

修改vue.config.js如下

/*
 * @description: 
 * @author: 小羽
 * @github: https://github.com/lyff1006
 * @lastEditors: 小羽
 * @Date: 2019-10-09 21:55:04
 * @LastEditTime: 2020-09-12 10:53:30
 * @Copyright: 1.0.0
 */
const path = require("path")
function addStyleResource(rule) {
    rule.use('style-resource')
        .loader('style-resources-loader')
        .options({
            patterns: [path.resolve(__dirname, "./src/assets/style/common.less")]
        })
}

module.exports = {
    //eslint开关
    lintOnSave: false,
    //生成环境是否生成map文件
    productionSourceMap: false,
    devServer: {
        host: '0.0.0.0',
        //代理配置
        proxy: {
            '/webserve': {
                target: 'http://127.0.0.1:8512',
                ws: true,
                changeOrigin: true,
                pathRewrite: {
                    '^/webserve': ''
                }
            },
        },
    },
    chainWebpack: (config) => {
        //配置less
        const types = ['vue-modules', 'vue', 'normal-modules', 'normal']
        types.forEach(type => addStyleResource(config.module.rule('less').oneOf(type)))
    },
}

--------------------------------------------------------------------分割线-----------------------------------------------------------------------

好了,正式开启本期教程。

我们先来看下初步的成果图

首页

image-20200912112533926

直播房间页

image-20200912115745650

帅气的小伙伴们,有发现什么共同的特点了吗?

没错,就是它们的头部导航栏都是一样的,而vue中一个很重要的概念就是组件。什么是vue中的组件,小羽的个人理解就是一个小的功能模块,而这个功能模块可以拥有自己的方法和样式,并且可以引入到其他的页面中,成为其中的一部分。因此我们可以将头部导航提取出来,作为一个公共的组件。此外我们拥有两个页面,因此就需要创建相关的路由。

1.路由

1.1 编写路由表

这里主要是控制我们以后路由要跳转的地方。顺便添加一个坑,路由表中新增meta属性,meta中的noHeader用来控制我们的头部导航栏的显示隐藏。为啥要添加这的东西呢?因为待会我们的头部导航栏将会全局挂载,这样的话就不需要每个页面都单独引入,老铁们这样子是不是感觉方便了很多呢?但是这样又带来了另外一个问题,就是假如有某个页面突然不想要这个导航了,那可怎么办呢?所以我们先在这里添加一个坑,后面再解析怎么使用这个东西。

image-20200912121934386

/*
 * @description: 
 * @author: 小羽
 * @github: https://github.com/lyff1006
 * @lastEditors: 小羽
 * @Date: 2019-10-09 21:59:23
 * @LastEditTime: 2020-09-12 12:16:29
 * @Copyright: 1.0.0
 */
import Vue from 'vue'
import Router from 'vue-router'
import baseEnv from "@/assets/js/config.js"
Vue.use(Router)

export default new Router({
    mode:baseEnv.mode==="electron"?"hash":"history",
    routes: [
        {
            path: '/',
            redirect: {
                name: 'index'
            }
        },
        {
            path: '/index',
            name:"index",
            meta:{
                noHeader:false
            },
            component: () => import("@/views/home/roomList.vue"),
        },
        {
            path: "/room",
            name:"room",
            meta:{
                noHeader:false
            },
            component: () => import("@/views/live/room.vue")
        }
    ]
})

1.2 挂载路由

src下的main.js,通过import引入我们刚刚新建的路由表。然后直接在new Vue()中挂载。

/*
 * @description: 
 * @author: 小羽
 * @github: https://github.com/lyff1006
 * @lastEditors: 小羽
 * @Date: 2020-09-12 10:45:54
 * @LastEditTime: 2020-09-12 12:15:15
 * @Copyright: 1.0.0
 */
import Vue from 'vue'
import App from './App.vue'
import router from './router'

//引入iview
import ViewUI from 'view-design';
import 'view-design/dist/styles/iview.css';
Vue.use(ViewUI);

Vue.config.productionTip = false

//将baseEnv注入到vue原型中
import baseEnv from "@/assets/js/config.js"
Vue.prototype.$baseEnv = baseEnv;

//将common注入到vue原型中
import {common} from "@/assets/js/common.js"
Vue.prototype.$commonFunc = common

new Vue({
  router,
  render: h => h(App),
}).$mount('#app')

1.3 修改app.vue

修改src下的app.vue

<!--
 * @description: 
 * @author: 小羽
 * @github: https://github.com/lyff1006
 * @lastEditors: 小羽
 * @Date: 2019-10-09 21:41:17
 * @LastEditTime: 2020-09-12 12:11:56
 * @Copyright: 1.0.0
-->
<template>
  <div id="app">
    <keep-alive>     <!--使用keep-alive会将页面缓存-->
      <router-view v-if="$route.meta.keepAlive"></router-view>
    </keep-alive> 
    <router-view v-if="!$route.meta.keepAlive"></router-view>
  </div>
</template>

<script>
import {common} from "feather-common"
export default {
  name: 'app',
}
</script>

<style lang="less">
#app {
  font-family: 'Avenir', Helvetica, Arial, sans-serif;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  color: #2c3e50;
  min-width: 720px;
}

</style>

然后ctrl+s保存,然后准备美滋滋的打开页面。我靠,居然报错了!!!这怎么能忍?赶快掏出24k纯金的眼睛(小羽的是made in China的人眼,正牌的!老铁们中有没有内种,咳咳,钛合金狗眼呀?【乖巧】),查看一下报错信息。哦,原来是缺少路由相关的页面呀。小问题,待我们把它给加上去就好了。

image-20200912124451724

image-20200912124545168

roomList.vue

<!--
 * @description: 
 * @author: 小羽
 * @github: https://github.com/lyff1006
 * @lastEditors: 小羽
 * @Date: 2020-09-12 12:13:11
 * @LastEditTime: 2020-09-12 12:14:28
 * @Copyright: 1.0.0
-->
<template>
    <div>roomList</div>
</template>

room.vue

<!--
 * @description: 
 * @author: 小羽
 * @github: https://github.com/lyff1006
 * @lastEditors: 小羽
 * @Date: 2020-09-12 12:13:36
 * @LastEditTime: 2020-09-12 12:14:13
 * @Copyright: 1.0.0
-->
<template>
    <div>room</div>
</template>

修改完后再次运行npm run serve,然后我们可以修改最后一个单词来进行路由切换。

image-20200912124745721

image-20200912124843845

2.全局头部导航

2.1 全局头部导航栏的切图

这里就没啥好说了吧?都是这么聪明的老铁们,一看就懂。

image-20200912125242259

<!--
 * @description: 
 * @author: 小羽
 * @github: https://github.com/lyff1006
 * @lastEditors: 小羽
 * @Date: 2020-08-31 01:26:26
 * @LastEditTime: 2020-09-12 21:30:19
 * @Copyright: 1.0.0
-->
<template>
    <div class="live-header">
        <div class="live-header-logo" @click="gotoIndex">
            <img src="@/assets/images/logo.png"/>
        </div>
        <div class="live-header-center">
            <div class="live-header-center-list">
                <div class="live-header-center-item">直播</div>
                <div class="live-header-center-item">分类</div>
                <div class="live-header-center-item">赛事</div>
                <div class="live-header-center-item">视频</div>
            </div>
            <Input placeholder="输入相关的直播信息" v-model="searchInfo" />
            <Button type="primary" style="margin-left:20px">搜索</Button>
        </div>
        <div class="live-header-right">
            <section>
                <div class="live-header-right-user-loginbtn">登录/注册</div>
            </section>
        </div>
    </div>
</template>
<script>
export default {
    name:"liveHeader",
    data(){
        return {
            ipcRenderer:{},
            searchInfo:"",
        }
    },
    mounted(){
    },
    methods:{
        /**
         * @description: 跳转到主页
         * @Date: 2020-09-03 00:45:46
         * @author: 小羽
         * @param {type} 
         * @return {type} 
         */
        gotoIndex(){
            this.$router.push({path:"/index"})
        },
    }
}
</script>
<style lang="less" scoped>
    .live-header{
        background: #ffffff;
        min-height: 60px;
        //margin-bottom:10px;
        display: flex;
        align-items: center;
        justify-content: center;
        padding: 0 20px;
        box-sizing: border-box;
        position: relative;
        -webkit-app-region: drag;
        &-logo{
            font-size:32px;
            color: @primary-color;
            cursor: pointer;
            display: flex;
            align-items: center;
            -webkit-app-region: no-drag;
            img{
                height: 60px;
                width: 70px;
            }
        }
        &-center{
            color:#666;
            margin-left: 30px;
            display: flex;
            align-items: center;
            justify-content: center;
            -webkit-app-region: no-drag;
            &-list{
                display: flex;
                justify-content: center;
                align-items: center;
            }
            &-item{
                margin:10px;
                min-width: 40px;
                cursor: pointer;
                &:hover{
                    color: @primary-color;
                }
            }  
        }
        &-right{
            margin-left: 20px;
            display: flex;
            color: #666;
            -webkit-app-region: no-drag;
            &-user{
                display: flex;
                justify-content: flex-start;
                align-items: center;
                cursor: pointer;
                &-avatar{
                    display: flex;
                    align-items: center;
                    img{
                        height: 26px;
                        width: 26px;
                        border-radius: 50%;
                    }
                }
                &-name{
                    margin-left: 10px;
                    width: 70px;
                    overflow: hidden;
                }
                &-loginbtn{
                    width: 100px;
                    cursor: pointer;
                    &:hover{
                        color: @primary-color;
                    }
                }
            }
        }
        &-window{
            z-index: 999999;
            position: absolute;
            right: 0;
            top: 0;
            display: flex;
            justify-content: flex-end;
            -webkit-app-region: no-drag;
            &-minibtn{
                text-align: center;
                line-height: 20px;
                width: 30px;
                height: 20px;
                &:hover{
                    background: #eeeeee;
                }
            }
            &-maxbtn{
                text-align:center;
                line-height: 20px;
                width:30px;
                height: 20px;
                &:hover{
                    background: #eeeeee;
                }
            }
            &-closebtn{
                text-align: center;
                line-height: 20px;
                width:30px;
                height: 20px;
                &:hover{
                    color: #fff;
                    background: #f00;
                }
            }
        }
    }
</style>

然后这四个标签的话,小羽这边也不做处理了。后续由老铁们自由发挥。

image-20200912215845678

2.2 全局挂载头部导航栏

在1.1中我们有提到留了一个meta的坑,老铁们还记得吗?忘了的话可以回头去看看本期的1.1小节哦。就是那个控制头部导航是否显示的那个,我们也是在src下的app.vue中,通过v-if判断noHeader属性进行判断。

<!--
 * @description: 
 * @author: 小羽
 * @github: https://github.com/lyff1006
 * @lastEditors: 小羽
 * @Date: 2019-10-09 21:41:17
 * @LastEditTime: 2020-09-12 12:53:56
 * @Copyright: 1.0.0
-->
<template>
  <div id="app">
    <live-header v-if="!$route.meta.noHeader"></live-header>
    <keep-alive>     <!--使用keep-alive会将页面缓存-->
      <router-view v-if="$route.meta.keepAlive"></router-view>
    </keep-alive> 
    <router-view v-if="!$route.meta.keepAlive"></router-view>
  </div>
</template>

<script>
import {common} from "feather-common"
import liveHeader from "@/components/liveHeader"
export default {
  name: 'app',
  components: {
    liveHeader
  },
}
</script>

<style lang="less">
#app {
  font-family: 'Avenir', Helvetica, Arial, sans-serif;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  color: #2c3e50;
  min-width: 720px;
}

</style>

保存后即可看到头部导航栏出现了,当我们切换不同的路由时,头部导航也是存在的哦(未设置noHeader或者noHeader为空)!!!

3.首页切图

首页主要是分成左右两边的,所以直接flex布局。

接着,左边是直播类型的选项,这里的话也是flex布局。

而右边的值播放列表,所以还是flex布局进行切图。

然后现在的话暂时不接入api接口和vuex,先使用假的数据来进行页面的渲染。ctrl+s保存后就可以看到首页的切图状况啦。

image-20200912221327907

<!--
 * @description: 
 * @author: 小羽
 * @github: https://github.com/lyff1006
 * @lastEditors: 小羽
 * @Date: 2020-01-16 23:03:11
 * @LastEditTime: 2020-09-12 22:10:42
 * @Copyright: 1.0.0
-->
<template>
    <div class="home">
        <div class="type-list">
            <div class="type-list-box">
                <div class="type-list-box-title"> <Icon type="md-desktop" class="type-list-box-title-icon" />网游电竞</div>
                <section class="type-list-box-tap-list">
                    <div class="type-list-box-tap-item" v-for="(item,index) of roomType.online" :key="index+item" @click="searchType(item)">{{item}}</div>
                </section>
            </div>
            <div class="type-list-box">
                <div class="type-list-box-title"><Icon type="md-game-controller-b" class="type-list-box-title-icon" />单机热游</div>
                <section class="type-list-box-tap-list">
                    <div class="type-list-box-tap-item" v-for="(item,index) of roomType.offline" :key="index+item" @click="searchType(item)">{{item}}</div>
                </section>
            </div>
            <div class="type-list-box">
                <div class="type-list-box-title"><Icon type="md-phone-landscape" class="type-list-box-title-icon" />手游休闲</div>
                <section class="type-list-box-tap-list">
                    <div class="type-list-box-tap-item" v-for="(item,index) of roomType.mobile" :key="index+item" @click="searchType(item)">{{item}}</div>
                </section>
            </div>
        </div>
        <div class="room-list">
            <div class="room-box" v-for="(item,index) in roomList" :key="'room-'+index"  @click="goLivingRoom(item.id)">
                <div class="room-box-img">
                    <img :src="item.image"/>
                    <div class="room-box-img-type">{{item.type}}</div>
                </div>
                <div class="room-box-title">{{item.title}}</div>
                <!-- <div class="live-line"></div> -->
                <div class="room-box-user">
                    <img :src="item.avatar"/>
                    <div class="room-box-user-name">{{item.name}}</div>
                </div>
            </div>
        </div>
    </div>
</template>
<script>
export default {
    name:"roomList",
    data(){
        return {
            roomList:[],
            roomType:{
                online:["英雄联盟","云顶之弈","穿越火线","DNF","Valorant","炉石传说","DOTA2","坦克世界","CSGO","COD","问道","魔兽争霸"],
                offline:["绝地求生","主机游戏","我的世界","方舟","糖豆人","怀旧游戏","盗贼之海","拾遗记"],
                mobile:["王者荣耀","和平精英"]
            }
        }
    },
    computed:{
    },
    mounted(){
        //this.getRoomList()
        this.searchType()
    },
    methods:{

        /**
         * @description: 跳转到直播间
         * @Date: 2020-09-03 01:08:26
         * @author: 小羽
         * @param {type} 
         * @return {type} 
         */
        goLivingRoom(room_id){
            //window.open(`${window.location.origin}/live?room=${room_id}`,"_blank")
            this.$router.push({path:`/room?room=${room_id}`})
        },

        /**
         * @description: 根据类型搜索直播间
         * @Date: 2020-09-03 01:09:09
         * @author: 小羽
         * @param {type} 
         * @return {type} 
         */
        async searchType(data){
            this.roomList = [
                {
                    "id": "nyAKfoD13oSFBpTzm1pB4oQijMZjDyXn",
                    "user_id": "LNsKeo69KLCuGrbNg0nlg2jwQDQub28C",
                    "title": "快乐风男乱杀",
                    "name": "浪子彦",
                    "image":"https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1599929760369&di=65a88d74851368211d3a4f0c1424024e&imgtype=0&src=http%3A%2F%2Fpic4.zhimg.com%2F50%2Fv2-c7226ca005f2942d346e79bfc73aec92_hd.jpg",
                    "avatar":"https://ss0.bdstatic.com/70cFuHSh_Q1YnxGkpoWK1HF6hhy/it/u=2887790348,3598106364&fm=26&gp=0.jpg",
                    "type": "英雄联盟"
                },
                { 
                    "id": "nyAKfoD13oSFBpTzm1pB4oQijMZjDyXn",
                    "user_id": "LNsKeo69KLCuGrbNg0nlg2jwQDQub28C",
                    "title": "快乐风男乱杀",
                    "name": "浪子彦",
                    "image":"https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1599929760369&di=65a88d74851368211d3a4f0c1424024e&imgtype=0&src=http%3A%2F%2Fpic4.zhimg.com%2F50%2Fv2-c7226ca005f2942d346e79bfc73aec92_hd.jpg",
                    "avatar":"https://ss0.bdstatic.com/70cFuHSh_Q1YnxGkpoWK1HF6hhy/it/u=2887790348,3598106364&fm=26&gp=0.jpg",
                    "type": "英雄联盟"
                },
                {
                    "id": "nyAKfoD13oSFBpTzm1pB4oQijMZjDyXn",
                    "user_id": "LNsKeo69KLCuGrbNg0nlg2jwQDQub28C",
                    "title": "快乐风男乱杀",
                    "name": "浪子彦",
                    "image":"https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1599929760369&di=65a88d74851368211d3a4f0c1424024e&imgtype=0&src=http%3A%2F%2Fpic4.zhimg.com%2F50%2Fv2-c7226ca005f2942d346e79bfc73aec92_hd.jpg",
                    "avatar":"https://ss0.bdstatic.com/70cFuHSh_Q1YnxGkpoWK1HF6hhy/it/u=2887790348,3598106364&fm=26&gp=0.jpg",
                    "type": "英雄联盟"
                },
                { 
                    "id": "nyAKfoD13oSFBpTzm1pB4oQijMZjDyXn",
                    "user_id": "LNsKeo69KLCuGrbNg0nlg2jwQDQub28C",
                    "title": "快乐风男乱杀",
                    "name": "浪子彦",
                    "image":"https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1599929760369&di=65a88d74851368211d3a4f0c1424024e&imgtype=0&src=http%3A%2F%2Fpic4.zhimg.com%2F50%2Fv2-c7226ca005f2942d346e79bfc73aec92_hd.jpg",
                    "avatar":"https://ss0.bdstatic.com/70cFuHSh_Q1YnxGkpoWK1HF6hhy/it/u=2887790348,3598106364&fm=26&gp=0.jpg",
                    "type": "英雄联盟"
                },
                {
                    "id": "nyAKfoD13oSFBpTzm1pB4oQijMZjDyXn",
                    "user_id": "LNsKeo69KLCuGrbNg0nlg2jwQDQub28C",
                    "title": "快乐风男乱杀",
                    "name": "浪子彦",
                    "image":"https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1599929760369&di=65a88d74851368211d3a4f0c1424024e&imgtype=0&src=http%3A%2F%2Fpic4.zhimg.com%2F50%2Fv2-c7226ca005f2942d346e79bfc73aec92_hd.jpg",
                    "avatar":"https://ss0.bdstatic.com/70cFuHSh_Q1YnxGkpoWK1HF6hhy/it/u=2887790348,3598106364&fm=26&gp=0.jpg",
                    "type": "英雄联盟"
                },
                { 
                    "id": "nyAKfoD13oSFBpTzm1pB4oQijMZjDyXn",
                    "user_id": "LNsKeo69KLCuGrbNg0nlg2jwQDQub28C",
                    "title": "快乐风男乱杀",
                    "name": "浪子彦",
                    "image":"https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1599929760369&di=65a88d74851368211d3a4f0c1424024e&imgtype=0&src=http%3A%2F%2Fpic4.zhimg.com%2F50%2Fv2-c7226ca005f2942d346e79bfc73aec92_hd.jpg",
                    "avatar":"https://ss0.bdstatic.com/70cFuHSh_Q1YnxGkpoWK1HF6hhy/it/u=2887790348,3598106364&fm=26&gp=0.jpg",
                    "type": "英雄联盟"
                },
                {
                    "id": "nyAKfoD13oSFBpTzm1pB4oQijMZjDyXn",
                    "user_id": "LNsKeo69KLCuGrbNg0nlg2jwQDQub28C",
                    "title": "快乐风男乱杀",
                    "name": "浪子彦",
                    "image":"https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1599929760369&di=65a88d74851368211d3a4f0c1424024e&imgtype=0&src=http%3A%2F%2Fpic4.zhimg.com%2F50%2Fv2-c7226ca005f2942d346e79bfc73aec92_hd.jpg",
                    "avatar":"https://ss0.bdstatic.com/70cFuHSh_Q1YnxGkpoWK1HF6hhy/it/u=2887790348,3598106364&fm=26&gp=0.jpg",
                    "type": "英雄联盟"
                },
                { 
                    "id": "nyAKfoD13oSFBpTzm1pB4oQijMZjDyXn",
                    "user_id": "LNsKeo69KLCuGrbNg0nlg2jwQDQub28C",
                    "title": "快乐风男乱杀",
                    "name": "浪子彦",
                    "image":"https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1599929760369&di=65a88d74851368211d3a4f0c1424024e&imgtype=0&src=http%3A%2F%2Fpic4.zhimg.com%2F50%2Fv2-c7226ca005f2942d346e79bfc73aec92_hd.jpg",
                    "avatar":"https://ss0.bdstatic.com/70cFuHSh_Q1YnxGkpoWK1HF6hhy/it/u=2887790348,3598106364&fm=26&gp=0.jpg",
                    "type": "英雄联盟"
                },
                {
                    "id": "nyAKfoD13oSFBpTzm1pB4oQijMZjDyXn",
                    "user_id": "LNsKeo69KLCuGrbNg0nlg2jwQDQub28C",
                    "title": "快乐风男乱杀",
                    "name": "浪子彦",
                    "image":"https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1599929760369&di=65a88d74851368211d3a4f0c1424024e&imgtype=0&src=http%3A%2F%2Fpic4.zhimg.com%2F50%2Fv2-c7226ca005f2942d346e79bfc73aec92_hd.jpg",
                    "avatar":"https://ss0.bdstatic.com/70cFuHSh_Q1YnxGkpoWK1HF6hhy/it/u=2887790348,3598106364&fm=26&gp=0.jpg",
                    "type": "英雄联盟"
                },
                { 
                    "id": "nyAKfoD13oSFBpTzm1pB4oQijMZjDyXn",
                    "user_id": "LNsKeo69KLCuGrbNg0nlg2jwQDQub28C",
                    "title": "快乐风男乱杀",
                    "name": "浪子彦",
                    "image":"https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1599929760369&di=65a88d74851368211d3a4f0c1424024e&imgtype=0&src=http%3A%2F%2Fpic4.zhimg.com%2F50%2Fv2-c7226ca005f2942d346e79bfc73aec92_hd.jpg",
                    "avatar":"https://ss0.bdstatic.com/70cFuHSh_Q1YnxGkpoWK1HF6hhy/it/u=2887790348,3598106364&fm=26&gp=0.jpg",
                    "type": "英雄联盟"
                },
                {
                    "id": "nyAKfoD13oSFBpTzm1pB4oQijMZjDyXn",
                    "user_id": "LNsKeo69KLCuGrbNg0nlg2jwQDQub28C",
                    "title": "快乐风男乱杀",
                    "name": "浪子彦",
                    "image":"https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1599929760369&di=65a88d74851368211d3a4f0c1424024e&imgtype=0&src=http%3A%2F%2Fpic4.zhimg.com%2F50%2Fv2-c7226ca005f2942d346e79bfc73aec92_hd.jpg",
                    "avatar":"https://ss0.bdstatic.com/70cFuHSh_Q1YnxGkpoWK1HF6hhy/it/u=2887790348,3598106364&fm=26&gp=0.jpg",
                    "type": "英雄联盟"
                },
                { 
                    "id": "nyAKfoD13oSFBpTzm1pB4oQijMZjDyXn",
                    "user_id": "LNsKeo69KLCuGrbNg0nlg2jwQDQub28C",
                    "title": "快乐风男乱杀",
                    "name": "浪子彦",
                    "image":"https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1599929760369&di=65a88d74851368211d3a4f0c1424024e&imgtype=0&src=http%3A%2F%2Fpic4.zhimg.com%2F50%2Fv2-c7226ca005f2942d346e79bfc73aec92_hd.jpg",
                    "avatar":"https://ss0.bdstatic.com/70cFuHSh_Q1YnxGkpoWK1HF6hhy/it/u=2887790348,3598106364&fm=26&gp=0.jpg",
                    "type": "英雄联盟"
                },
                {
                    "id": "nyAKfoD13oSFBpTzm1pB4oQijMZjDyXn",
                    "user_id": "LNsKeo69KLCuGrbNg0nlg2jwQDQub28C",
                    "title": "快乐风男乱杀",
                    "name": "浪子彦",
                    "image":"https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1599929760369&di=65a88d74851368211d3a4f0c1424024e&imgtype=0&src=http%3A%2F%2Fpic4.zhimg.com%2F50%2Fv2-c7226ca005f2942d346e79bfc73aec92_hd.jpg",
                    "avatar":"https://ss0.bdstatic.com/70cFuHSh_Q1YnxGkpoWK1HF6hhy/it/u=2887790348,3598106364&fm=26&gp=0.jpg",
                    "type": "英雄联盟"
                },
                { 
                    "id": "nyAKfoD13oSFBpTzm1pB4oQijMZjDyXn",
                    "user_id": "LNsKeo69KLCuGrbNg0nlg2jwQDQub28C",
                    "title": "快乐风男乱杀",
                    "name": "浪子彦",
                    "image":"https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1599929760369&di=65a88d74851368211d3a4f0c1424024e&imgtype=0&src=http%3A%2F%2Fpic4.zhimg.com%2F50%2Fv2-c7226ca005f2942d346e79bfc73aec92_hd.jpg",
                    "avatar":"https://ss0.bdstatic.com/70cFuHSh_Q1YnxGkpoWK1HF6hhy/it/u=2887790348,3598106364&fm=26&gp=0.jpg",
                    "type": "英雄联盟"
                },
                {
                    "id": "nyAKfoD13oSFBpTzm1pB4oQijMZjDyXn",
                    "user_id": "LNsKeo69KLCuGrbNg0nlg2jwQDQub28C",
                    "title": "快乐风男乱杀",
                    "name": "浪子彦",
                    "image":"https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1599929760369&di=65a88d74851368211d3a4f0c1424024e&imgtype=0&src=http%3A%2F%2Fpic4.zhimg.com%2F50%2Fv2-c7226ca005f2942d346e79bfc73aec92_hd.jpg",
                    "avatar":"https://ss0.bdstatic.com/70cFuHSh_Q1YnxGkpoWK1HF6hhy/it/u=2887790348,3598106364&fm=26&gp=0.jpg",
                    "type": "英雄联盟"
                },
                { 
                    "id": "nyAKfoD13oSFBpTzm1pB4oQijMZjDyXn",
                    "user_id": "LNsKeo69KLCuGrbNg0nlg2jwQDQub28C",
                    "title": "快乐风男乱杀",
                    "name": "浪子彦",
                    "image":"https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1599929760369&di=65a88d74851368211d3a4f0c1424024e&imgtype=0&src=http%3A%2F%2Fpic4.zhimg.com%2F50%2Fv2-c7226ca005f2942d346e79bfc73aec92_hd.jpg",
                    "avatar":"https://ss0.bdstatic.com/70cFuHSh_Q1YnxGkpoWK1HF6hhy/it/u=2887790348,3598106364&fm=26&gp=0.jpg",
                    "type": "英雄联盟"
                },

                {
                    "id": "nyAKfoD13oSFBpTzm1pB4oQijMZjDyXn",
                    "user_id": "LNsKeo69KLCuGrbNg0nlg2jwQDQub28C",
                    "title": "快乐风男乱杀",
                    "name": "浪子彦",
                    "image":"https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1599929760369&di=65a88d74851368211d3a4f0c1424024e&imgtype=0&src=http%3A%2F%2Fpic4.zhimg.com%2F50%2Fv2-c7226ca005f2942d346e79bfc73aec92_hd.jpg",
                    "avatar":"https://ss0.bdstatic.com/70cFuHSh_Q1YnxGkpoWK1HF6hhy/it/u=2887790348,3598106364&fm=26&gp=0.jpg",
                    "type": "英雄联盟"
                },
                { 
                    "id": "nyAKfoD13oSFBpTzm1pB4oQijMZjDyXn",
                    "user_id": "LNsKeo69KLCuGrbNg0nlg2jwQDQub28C",
                    "title": "快乐风男乱杀",
                    "name": "浪子彦",
                    "image":"https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1599929760369&di=65a88d74851368211d3a4f0c1424024e&imgtype=0&src=http%3A%2F%2Fpic4.zhimg.com%2F50%2Fv2-c7226ca005f2942d346e79bfc73aec92_hd.jpg",
                    "avatar":"https://ss0.bdstatic.com/70cFuHSh_Q1YnxGkpoWK1HF6hhy/it/u=2887790348,3598106364&fm=26&gp=0.jpg",
                    "type": "英雄联盟"
                },
            ]
        }
    },
}
</script>
<style lang="less" scoped>
.home{
    display: flex;
    justify-content: flex-start;
}
.type-list{
    background: #2f3035;
    height: calc(100vh - 60px);
    width: 250px;
    min-width: 250px;
    color: #8d919a;
    padding-top:10px;
    &-box{
        &-title{
            font-size: 20px;
            &-icon{
                margin-left: 5px;
                margin-right: 10px;
            }
        }
        &-tap{
            &-list{
                display: flex;
                justify-content: flex-start;
                align-items: center;
                flex-wrap: wrap;
                margin:10px;
            }
            &-item{
                font-size: 14px;
                text-align: center;
                background: #38393e;
                padding: 3px 8px;
                margin: 2px;
                width: 72px;
                overflow-x: hidden;
                cursor: pointer;
                &:hover{
                    color: @primary-color;
                }
            }
        }
    }
}
.room-list{
    display: flex;
    flex-wrap: wrap;
    justify-content: flex-start;
    align-content: flex-start;
    .room-box{
        display: inline-block;
        width: 300px;
        height: 280px;
        background: #fff;
        border-radius: 10px;
        margin:10px;
        cursor: pointer;
        overflow: hidden;
        &-img{
            height: 200px;
            box-sizing: border-box;
            background: #eee;
            position: relative;
            &-type{
                position: absolute;
                right: 10px;
                top: 5px;
                background: rgba(0,0,0,0.5);
                color: #fff;
                padding: 2px 8px;
            }
            img{
                width:100%;
            }
        }
        &-title{
            margin: 5px 10px;
            &:hover{
                color: @primary-color;
            }
        }
        &-user{
            margin: 5px 10px;
            display: flex;
            justify-content: flex-start;
            align-items: center;
            img{
                width:26px;
                height: 26px;
                border-radius: 50%;
                border: 0.5px solid #ccc;
                margin-right: 5px;
            }
        }
        &:hover{
            box-shadow: 0 0 8px #bbb;
        }
    }
}
</style>

4.直播界面切图

直播页主要也是使用flex布局进行切图,其实这里也可以使用浮动或者定位来切图,不过小羽比较喜欢使用flex布局,就看大家的喜好把~

image-20200912223640796

image-20200912223415792

room.vue

<!--
 * @description: 
 * @author: 小羽
 * @github: https://github.com/lyff1006
 * @lastEditors: 小羽
 * @Date: 2020-01-16 23:02:22
 * @LastEditTime: 2020-09-12 22:28:44
 * @Copyright: 1.0.0
-->
<template>
  <div class="room">
    <section class="video-content">
      <div class="video-content-header">
        <div class="video-content-header-avatar">
          <img :src="roomDetail.avatar" />
        </div>
        <div>
          <div class="video-content-header-title">{{roomDetail.title}}</div>
          <div class="video-content-header-anchor">{{roomDetail.name}}</div>
        </div>
      </div>
      <div class="video-content-main">
        <video id="videoElement" width="100%" height="100%" controls></video>
      </div>
    </section>
    <section class="chat-content">
      <Barrage></Barrage>
    </section>
  </div>
</template>
<script>
//const flyjs = require("../../assets/js/flv");
import flvjs from "flv.js";
import { common } from "@/assets/js/common.js";
import Barrage from "./barrage.vue";

export default {
  data() {
    return {
      roomDetail: {},
    };
  },
  components: {
    Barrage,
  },
  created() {},
  async mounted() {
    //let urlData = common.getUrlParams();
    let urlData = this.$router.history.current.query;
    this.livingRoom = urlData.room;
    this.roomDetail = {
      title: "快乐风男乱杀",
      type: "英雄联盟",
      name: "浪子彦",
      id: "LNsKeo69KLCuGrbNg0nlg2jwQDQub28C",
      avatar:
        "https://ss0.bdstatic.com/70cFuHSh_Q1YnxGkpoWK1HF6hhy/it/u=2887790348,3598106364&fm=26&gp=0.jpg",
      room_id: "nyAKfoD13oSFBpTzm1pB4oQijMZjDyXn",
    };
    this.$nextTick(() => {
      if (flvjs.isSupported()) {
        var videoElement = document.getElementById("videoElement");
        this.flvPlayer = flvjs.createPlayer({
          type: "flv",
          url: `${this.$baseEnv.livingUrl}/${this.livingRoom}.flv`,
        });
        this.flvPlayer.attachMediaElement(videoElement);
        try {
          this.flvPlayer.load();
          this.flvPlayer.play();
        } catch {
          console.log("error");
        }
      }
    });
  },
};
</script>

<style lang="scss" scoped>
.room {
  margin-top: 10px;
  display: flex;
  flex-wrap: wrap;
  justify-content: space-between;
  height: 44vw;
  .video-content {
    box-sizing: border-box;
    height: 100%;
    width: calc(100vw - 360px - 40px);
    min-width: 300px;
    padding: 20px;
    background: #fff;
    position: relative;
    &-header {
      height: 60px;
      display: flex;
      justify-content: flex-start;
      &-avatar {
        width: 50px;
        height: 50px;
        margin-right: 10px;
        border-radius: 50%;
        overflow: hidden;
        img {
          width: 100%;
          height: 100%;
        }
      }
      &-title {
        font-size: 20px;
      }
      &-anchor {
        color: #999;
      }
    }
    &-main {
      position: relative;
      height: calc(100% - 60px);
    }
    .barrage-block {
      z-index: 1;
      position: absolute;
      height: 40px;
      //border-bottom: #fff 1px solid;
      width: calc(100% - 40px);
      color: #fff;
      &-item {
        position: absolute;
        animation: barrage 5s linear;
        animation-fill-mode: forwards;
      }
    }
    video {
      object-fit: fill;
    }
  }
  .chat-content {
    width: 360px;
    height: 100%;
    background: #fff;
    margin-right: 20px;
    box-sizing: border-box;
    padding: 20px 0;
  }
}

@keyframes barrage {
  from {
    left: 100%;
    transform: translateX(0);
  }
  to {
    left: 0;
    transform: translateX(-200%);
  }
}
</style>

barrage.vue

<!--
 * @description: 
 * @author: 小羽
 * @github: https://github.com/lyff1006
 * @lastEditors: 小羽
 * @Date: 2020-01-28 21:33:07
 * @LastEditTime: 2020-09-12 22:27:35
 * @Copyright: 1.0.0
-->
<template>
    <div class="barrage">
        <h3>弹幕列表</h3>
        <div class="live-line"></div>
        <section class="barrage-body" id="barrageList" ref="barrageList">
            <div v-for="(battage,battageIndex) in barrageMsgList" :key="battageIndex">
                {{battage.user}}:{{battage.msg}}
            </div>
        </section>
        <div class="live-line"></div>
        <section class="barrage-msg">
            <Input v-model="battageMsg" maxlength="20" show-word-limit placeholder="请输入弹幕" style="width: 200px" @on-enter="chatLiveRoom"/>
            <Button type="primary" style="margin-left:20px;width:80px" @click="chatLiveRoom">发送</Button>
        </section>
    </div>
</template>
<script>
//import {sock,socket} from "@/assets/api/socket.js"
import {common} from "@/assets/js/common.js"
import bus from "@/assets/js/bus.js"

export default {
    data(){
        return {
            battageMsg:"",
            livingRoom:"",
            barrageMsgList:[]
        }
    },
    mounted(){
        //this.livingRoom=common.getUrlParam("room")
    },
    methods:{
        //发送弹幕
        chatLiveRoom(){
            console.log(this.currentUser)
        }
    }
}
</script>

<style lang="less">
.barrage{
    height: 100%;
    h3{
        padding: 0 10px;
    }
    &-body{
        height: calc(100% - 60px);
        overflow-y: auto;
        padding: 0 20px;
        box-sizing: border-box;
    }
    &-msg{
        margin-top: 10px;
        padding: 0 20px;
        box-sizing: border-box;
    }
}

</style>

修改一下全局的背景色

public下的index.html修改如下

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width,initial-scale=1.0">
    <link rel="icon" href="<%= BASE_URL %>favicon.ico">
    <title>小羽直播</title>
    <style>
      body{
        background-color: #f2f2f2 !important;
      }
    </style>
  </head>
  <body>
    <noscript>
      <strong>We're sorry but <%= htmlWebpackPlugin.options.title %> doesn't work properly without JavaScript enabled. Please enable it to continue.</strong>
    </noscript>
    <div id="app"></div>
    <!-- built files will be auto injected -->
  </body>
</html>

小结

本期小羽主要给大家介绍了直播平台的前端页面的初步切图和路由的相关配置。然后关于直播平台的系列文,没有意外的话,小羽肯定会给老铁们更完,所以可以放心阅读。但是小羽平常也是需要工作的,众所周知程序猿的工作都是比较忙的,经常需要加班。小羽写这个教程都是在每天下班后,尽量抽出一部分时间来写的,所以就不要催更啦,大家都不容易呢~

觉得小羽教得还阔以得话就来波点赞和关注呗~

ps:纯原创,转载请标明出处

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值