vue+node.js手把手教你搭建一个直播平台(四)
上一期,帅气的小羽给老铁们介绍了直播平台的项目的前端页面的初步切图,这期就让小羽带大家接入直播相关的api接口。敲黑板!敲黑板!敲黑板!重点来啦~1.api接口相关在src目录下个新建api文件夹,api下新建modules文件夹和index.js文件。其中index.js是我们api的统一入口文件,modules中则是存放我们各个api接口。在index.js中统一收集所有的api接口,然后再m
上一期,帅气的小羽给老铁们介绍了直播平台的项目的前端页面的初步切图,这期就让小羽带大家接入直播相关的api接口。敲黑板!敲黑板!敲黑板!重点来啦~
1.api接口相关
在src目录下个新建api文件夹,api下新建modules文件夹和index.js文件。其中index.js是我们api的统一入口文件,modules中则是存放我们各个api接口。在index.js中统一收集所有的api接口,然后再main.js中将api接口挂载到vue的原型上,以后再所有的.vue文件下,我们都可以直接通过this.$api来直接调用api接口。老铁们是不是感觉挺方便的呀~
main.js中加入如下代码
//将api注入到vue原型中
import api from "@/api/index.js"
Vue.prototype.$api = api
livingRoom.js
/*
* @description: 直播间接口
* @author: 小羽
* @lastEditors: 小羽
* @Date: 2020-08-31 15:39:16
* @LastEditTime: 2020-09-18 00:11:47
* @Copyright: 1.0.0
*/
import baseEnv from "@/assets/js/config.js"
import axios from "@/assets/js/http.js"
class LivingRoom{
/**
* @description: 获取直播间列表
* @Date: 2020-08-31 16:08:17
* @author: 小羽
* @param {type}
* @return {type}
*/
getRoomList(params){
if(params&¶ms.type){
//通过类型进行搜索
return axios.get(`${baseEnv.webUrl}/livingRoom/roomListByType`,{params:params}).then(res=>{
return res.data.data
})
}else{
//通过输入的信息进行搜索
return axios.get(`${baseEnv.webUrl}/livingRoom/roomList`,{params:params}).then(res=>{
return res.data.data
})
}
}
/**
* @description: 获取直播间详情
* @Date: 2020-09-10 23:25:34
* @author: 小羽
* @param {type}
* @return {type}
*/
getRoomDetail(params){
return axios.get(`${baseEnv.webUrl}/livingRoom/roomDetail`,{params:params}).then(res=>{
return res.data.data
})
}
/**
* @description: 新增直播间
* @Date: 2020-09-03 00:42:05
* @author: 小羽
* @param {type}
* @return {type}
*/
addRoom(params){
return axios.get(`${baseEnv.webUrl}/livingRoom/addRoom`,params).then(res=>{
return res.data
})
}
/**
* @description: 编辑直播间
* @Date: 2020-09-03 00:42:17
* @author: 小羽
* @param {type}
* @return {type}
*/
editRoom(params){
return axios.post(`${baseEnv.webUrl}/livingRoom/editRoom`,params).then(res=>{
return res.data
})
}
}
const livingRoom = new LivingRoom()
export default livingRoom
index.js
/*
* @description:
* @author: 小羽
* @github: https://github.com/lyff1006
* @lastEditors: 小羽
* @Date: 2020-09-17 23:45:35
* @LastEditTime: 2020-09-18 00:06:12
* @Copyright: 1.0.0
*/
import livingRoomApi from "./modules/livingRoom"
const apiObj = {
livingRoomApi
}
export default apiObj
2.配置vuex相关
vuex是一个统一的状态管理器,简单的来说就是保存在vuex中的数据是全局统一的。
src目录下新建store文件夹,store下新建modules文件夹和index.js文件。其中index.js是我们vuex的统一入口文件,modules中则是存放我们各个模块中的数据。
index.js
/*
* @description: vuex统一入口
* @author: 小羽
* @lastEditors: 小羽
* @Date: 2020-09-01 13:41:36
* @LastEditTime: 2020-09-18 00:29:39
* @Copyright: 1.0.0
*/
import Vue from 'vue'
import Vuex from 'vuex'
import room from "./modules/room"
Vue.use(Vuex)
export default new Vuex.Store({
modules:{
room
}
})
modules/room.js
/*
* @description:
* @author: 小羽
* @github: https://github.com/lyff1006
* @lastEditors: 小羽
* @Date: 2020-09-03 00:52:35
* @LastEditTime: 2020-09-18 00:28:08
* @Copyright: 1.0.0
*/
import api from "@/api/index.js"
const state = {
roomList:[]
}
const actions = {
async setRoomList({commit},data){
let res = await api.livingRoomApi.getRoomList(data)
commit("updateRoomList",res)
}
}
const mutations = {
updateRoomList(state,data){
state.roomList = data
}
}
const getters = {}
export default {
namespace:"livingRoom",
state,
actions,
mutations,
getters
}
修改main.js
import store from "./store/index"
new Vue({
router,
store,
render: h => h(App),
}).$mount('#app')
可能这时候就会有老哥问上面部署了一堆vuex相关的配置,到底有什么用呀?而且为啥要把api接口的丢到vuex中的actions呢?直接发起api请求它不香吗?有这些疑问就对了,小羽当初刚学vue的时候也是有这些疑问的。
为啥我们要把数据丢到vuex中呢?主要是当我们可能有几个页面都会用到相同的数据,总不能每打开一次页面就发起一次请求吧?如果使用了vuex之后,我们的单页面应用就只需要发起一次请求,接着将得到的数据存放在vuex中,以后我们的页面都可以直接读取vuex中的数据,而不用一直发起api请求。
此外,vuex有一个很重要的特点,就是响应式的。当我们修改vuex中的数据时,我们的页面也是会跟随着变化的。因此,我们可以直接将api接口封装到vuex中,以后就直接调用action的方法,然后再action中发起api请求,将得到的数据再commit到mutation中。然后就会响应式的更新我们的前端页面
3.接入直播列表
好了,终于配置好上面的一大堆东西了,是时候展现真正的技术,咳咳,是时候接入前端页面啦。
3.1 首页接入
views/home/roomList.vue中
使用vuex中的语法糖——mapstate,引入roomList
computed:{
...mapState({
roomList:state=>state.room.roomList
})
},
使用vuex中的语法糖——mapActions,引入action中的方法
...mapActions([
"setRoomList"
]),
我们上一期的切图中是使用假数据进行切图的,那我们现在就需要把假的数据删除,然后接入api接口。
1.删除data(){}中的roomList。
2.重写methods中的searchType方法
/**
* @description: 根据类型搜索直播间
* @Date: 2020-09-03 01:09:09
* @author: 小羽
* @param {type}
* @return {type}
*/
async searchType(data){
let params = {}
if(data){
params.type = data
}
this.setRoomList(params)
}
然后这是当前的roomList.vue中的script部分代码
<script>
import {mapActions,mapMutations,mapGetters,mapState} from "vuex"
export default {
name:"roomList",
data(){
return {
roomType:{
online:["英雄联盟","云顶之弈","穿越火线","DNF","Valorant","炉石传说","DOTA2","坦克世界","CSGO","COD","问道","魔兽争霸"],
offline:["绝地求生","主机游戏","我的世界","方舟","糖豆人","怀旧游戏","盗贼之海","拾遗记"],
mobile:["王者荣耀","和平精英"]
}
}
},
computed:{
...mapState({
roomList:state=>state.room.roomList
})
},
mounted(){
//this.getRoomList()
this.searchType()
},
methods:{
...mapActions([
"setRoomList"
]),
/**
* @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){
let params = {}
if(data){
params.type = data
}
this.setRoomList(params)
}
},
}
</script>
3.2 顶部栏接入
顶部栏的话我们只需要接入一个vuex中的setRoomList方法就可以了
src/components/liveHeader.vue
import {mapActions,mapMutations,mapGetters,mapState} from "vuex"
export default {
//省略。。。
methods:{
...mapActions([
"setRoomList"
]),
/**
* @description: 跳转到主页
* @Date: 2020-09-03 00:45:46
* @author: 小羽
* @param {type}
* @return {type}
*/
gotoIndex(){
this.$router.push({path:"/index"})
},
}
//省略。。。
}
接入vuex
在搜索按钮中绑定setRoomList方法
<Button type="primary" style="margin-left:20px" @click="setRoomList({keyword:searchInfo})">搜索</Button>
保存之后我们就可以发现我们首页的左侧列表和搜索功能都是正常的了,也可以点击进入直播的房间,但是房间的信息却不对。别着急,我们现在就接入房间详情。
4.接入直播房间相关
修改src/views/live/room.vue中的mounted,主要是将this.roomDetail中的虚拟数据替换为api接口中获取的数据。此时,我们切换房间后,房间的相关信息也能正常显示了。
然后就是重点啦,在nextTick()中我们将会对直播的视频进行初始化渲染。
async mounted() {
let urlData = this.$router.history.current.query;
this.livingRoom = urlData.room;
this.roomDetail = await this.$api.livingRoomApi.getRoomDetail({id:this.livingRoom})
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");
}
}
});
},
修改src/assets/js/config.js中的baseUrl(理论上127.0.0.1和localhost是一样的,但是小羽使用127.0.0.1的时候无法获取到视频流,原因未知)
const baseUrl = env.NODE_ENV==="development"?"http://localhost":"https://www.example.com"
5.开始直播
其实到这里我们的核心功能——直播基本完成啦~~~
老铁们是不是有点点小激动!!!【手动狗头】
直播走起!
打开obs,进行相关的设置。然后点击开始推流。打开对应的直播间就阔以看到我们的直播啦,是不是成就感满满的~
6.埋坑
但是我们这个直播还是有一点问题的,因为我们的直播是通过直播间的id进行推流的,只要知道我们的直播间id就可以随便直播了,所以这点是不合理的。
因此,小羽的设想是新增主播的直播密钥,然后在中间用node.js再添加一个反向代理层,当用户进入直播间后通过直播间的id进入到node.js,接着反向代理到主播通过直播密钥推流的视频。
这样一来用户就无法知道主播的密钥,但是却可以正常的看视频。
小羽这边由于知识所限,暂时无法实现http代理到stream流。如果各位看官老爷们有好的想法,也可以告诉小羽,先谢过啦~【乖巧】
小结
本期小羽主要给大家介绍了直播平台的vuex和api接口的接入,初步完成了核心功能——直播搜索和视频直播功能。
觉得小羽教得还阔以得话就来波点赞和关注呗~
ps:纯原创,转载请标明出处
更多推荐
所有评论(0)