uniapp做直播+可拖动弹幕
项目需求:用uniapp开发微信小程序,直播界面做可拖动弹幕。一、直播页面,微信小程序的<live-player>组件就是用来搭建直播的。我的项目需求是从上一个页面点击后直接跳转进对应的直播间,所以这个界面一开始就需要是全屏播放的。1.<live-player>的全屏.<live-playerid="liveplayer"src="https://domain/pul
项目需求:用uniapp开发微信小程序,直播界面做可拖动弹幕。
一、直播页面,微信小程序的<live-player>
组件就是用来搭建直播的。
我的项目需求是从上一个页面点击后直接跳转进对应的直播间,所以这个界面一开始就需要是全屏播放的。
1.<live-player>
的全屏.
<live-player
id="liveplayer"
src="https://domain/pull_stream"
mode="live"
:autoplay="true"
orientation="vertical"
object-fit="fillCrop"
@statechange="statechange"
@error="error"
>
</live-player>
其中一个必不可少的属性就是id,这个id之后会用来在JS代码中获取live-player的上下文。
// 创建直播流对象,获取live-player的上下文。
let player = uni.createLivePlayerContext('liveplayer', this);
拿到这个上下文之后就可以通过调用方法实现全屏和退出全屏
// 直播流对象全屏
player.requestFullScreen();
//退出全屏
player.exitFullScreen();
2.直播弹幕区
有了全屏的直播后,需要在这个直播上放一个弹幕区域和按钮等。由于 map、video、canvas、camera、live-player、live-pusher都是原生组件,层级比前端组件高,即便使用了z-index前端组件也是无法覆盖到原生组件上的。所以采用官方提供的`<cover-view>`进行覆盖,这里注意,`<cover-view/> 内只能嵌套 <cover-view/> <cover-image/> <button/> <navigator/> <ad/>,其他标签的子节点树在真机上都会被忽略。`
有了这些限制,无法用<scroll-view>
做一个可上下拖动的弹幕。所以采用以下的方法。
官方文档中,给cover-view提供了一个css的属性overflow-y: scroll;(官网上写的是overflow: scroll;试过了没有用),配合:scroll-top=“scrollTop+‘px’” 或 :scroll-top=" '"这两段代码让设定了高度的区域在内容溢出后实现可拖动,我这里使用了前者,因为后面在发送弹幕后还要实现自动定位到最后一行。
<!-- 弹幕 -->
<cover-view class="barrage" id="message-items" :scroll-top="scrollTop+'px'">
<cover-view class="barrageItem" v-for="(item,index) in msgList" :key="index">
<cover-view class="barrageIcon" :class="item.barrageIcon == '铁粉'? 'ironBarrageIcon' : 'newBarrageIcon'">{{item.barrageIcon}}</cover-view>
<cover-view class="barrageName">{{item.barrageName}}:</cover-view>
<cover-view class="barrageContent">{{item.barrageContent}}</cover-view>
</cover-view>
</cover-view>
.barrage{
width:380rpx;
height:440rpx;
margin: 0 0 20px 0;
overflow-y: scroll;
.barrageItem{
line-height: 21px;
margin: 5px 0;
.barrageIcon{
display: inline-block;
color: rgba(255, 255, 255, 1);
font-size: 14px;
border-radius: 5px;
text-align: center;
line-height: 21px;
width: 37px;
height: 21px;
}
.newBarrageIcon{
background-color: rgba(0, 186, 173, 1);
}
.ironBarrageIcon{
background-color: rgba(255, 141, 26, 1);
}
.barrageName{
display: inline-block;
margin-left: 6px;
color: rgba(255, 255, 255, 1);
font-size: 12px;
}
.barrageContent{
display: inline-block;
color: rgba(229, 229, 229, 1);
font-size: 12px;
}
}
}
到这里弹幕就搭建好了,现在需要在页面加载完成后 以及 发送完弹幕后,弹幕区域自动定位在最后一行。写JS代码。
// 弹幕滚动到底部,每次发送弹幕后需调用
letBarrageToButtom(){
var _this = this;
const query = uni.createSelectorQuery().in(this);
query.select('.barrageItem').boundingClientRect(rect => {
//这里的逻辑就是,把每条弹幕的高度x弹幕的条数,再加上每条弹幕之间的距离,margin值,这个10根据自己的样式调整
var toTop = (_this.msgList.length*rect.height+(rect.height*10));
// _this.setData({scrollTop:toTop});
this.scrollTop = toTop;
}).exec();
},
其中 uni.createSelectorQuery() 和 .select(’ ').boundingClientRect 都是官方提供的方法,地址随后贴上来。
3.input输入框的伪代码
现在有了可拖动的弹幕区域,就需要有个可以发送弹幕的input框,但是在<scroll-view>
中不能嵌套input框,否则在真机上会被隐藏。好消息是,虽然input框被隐藏了,但是依旧可以通过方法获取焦点并获取到用户输入的内容。
HTML
<!-- 弹幕输入框 -->
<cover-view class="barrageInput" @tap='tapInput'>
<cover-view class='text' :class="inputInfo == '写评论……'? 'placeholder' : ''">{{inputInfo}}</cover-view>
<input class='input' v-model="inputModel" focus='inputFocus' @input='inputing' @blur='blurInput' type="text" confirm-type="send" @confirm="sendBarrage"></input>
</cover-view>
css
.barrageInput{
width: 280px;
height: 35px;
line-height: 35px;
background-color: rgba(0, 0, 0, 0.4);
border-radius: 18px;
.placeholder{
color: rgba(229, 229, 229, 1);
font-size: 13px;
letter-spacing: 2px;
}
.text{
height: 35px;
line-height: 35px;
color: white;
margin: 0 15px;
}
.input{
height: 35px;
line-height: 35px;
color: white;
margin: 0 15px;
/* margin-top为text的高度,保持视觉上一致 */
margin-top: -35px;
}
}
JS
// 将焦点给到 input(在真机上不能获取input焦点)
tapInput() {
//在真机上将焦点给input
this.inputFocus = true,
//初始占位清空
this.inputInfo = ''
},
// input 输入时将 input 的输入内容给到cover-view
inputing(e){
this.inputInfo = e.detail.value;
},
// input失焦时还原占位符
blurInput(e) {
this.inputInfo = '写评论……';
this.inputModel = '';
},
// 点击键盘右下角发送,发送弹幕
sendBarrage(){
// 先判断要发送的信息是否为空,避免向后台发送无用信息
if(this.inputInfo != ''){
let barrage = {
id:20,
barrageIcon: '新粉',
barrageName: '新的弹幕',
barrageContent:this.inputInfo,
barrageMoreContent:''
}
barrage = this.getNewline(barrage);
this.msgList.push(barrage);
this.inputModel = '';
this.inputInfo = '写评论……';
this.inputFocus = false;
this.letBarrageToButtom();
}else{
return;
}
}
到此,弹幕的发送功能也完成了。
4.弹幕的换行。
在做测试的时候发现,当弹幕字数较多时,并不会自动换行,而是超出部分直接隐藏了。这是因为<scroll-view>
默认的样式有 white-space: nowrap; line-height: 1.2; display: block;
所以在需要换行的地方加了一行white-space:pre-wrap;虽然可以换行,但是content部分在块内换行,(弹幕内容区独自换行,前面的徽标和名字不动,样式有问题。)这里解决了好久,因为业务原因没有找到合适的方法,于是选择了手动裁切弹幕内容。
<!-- 弹幕 -->
<cover-view class="barrage" id="message-items" :scroll-top="scrollTop+'px'">
<cover-view class="barrageItem" v-for="(item,index) in msgList" :key="index">
<cover-view class="barrageIcon" :class="item.barrageIcon == '铁粉'? 'ironBarrageIcon' : 'newBarrageIcon'">{{item.barrageIcon}}</cover-view>
<cover-view class="barrageName">{{item.barrageName}}:</cover-view>
<cover-view class="barrageContent">{{item.barrageContent}}</cover-view>
<cover-view class="barrageMoreContent" v-if="item.barrageMoreContent">{{item.barrageMoreContent}}</cover-view>
</cover-view>
</cover-view>
css
.barrageMoreContent{
color: rgba(229, 229, 229, 1);
font-size: 12px;
width: 100%;
// 文字换行
white-space:pre-wrap;
//下面两行用于纯数字弹幕的换行,由于一串数字在计算机看来是一个长单词,如果不手动设置,是不会在单词内换行的,导致超出部分依旧被隐藏而不是换行。
word-wrap: break-word;
word-break: break-all;
}
JS
// 裁切数字换行
getNewline(list){
let _listMsg = list.barrageContent;
if(list.barrageName.length + list.barrageContent.length > 11){
list.barrageContent = _listMsg.slice(0,11 - list.barrageName.length);
list.barrageMoreContent = _listMsg.slice(11 - list.barrageName.length);
}
return list;
}
这段代码在初始化弹幕和发送弹幕后调用即可。个人感觉不是好的解决办法,以后有了更好的来更换代码。
最后效果图如下:
更多推荐
所有评论(0)