目录
1.需求背景及重点需求和解决方式
2.效果实现
3.遇到的问题以及解决思路
需求背景:
需求的最终目的是为了让门店更了解参加活动的实时数据,通过可视化大屏的形式进行展现。此需求在两个项目上开发,唯一的区别就是门店端只会显示当前门店的数据信息,这篇博客我们主要介绍门店端的开发历程。
重点需求:
1.为了高效还原ui图,手写倒计时正计时组件,Switch组件;
2.订单金额没隔3位数加,号(可以参考我之前的博客);
3.二次封装组件,与后端建立长链接保持数据的实时通讯(大屏金额发生变化时数字跳 动效果&&实时弹幕);
4.使用rem布局适配大屏;
5.使用原生js实现屏幕百分百显示效果;
6.使用js完成一些特效;
效果实现:
1.手写组件
倒计时正计时组件:
<div class="active_nam">距离活动结束还剩</div>
<div class="countdown">
<div class="div-con">{{().padStart(2,0)}}</div><div class="div-dw">天</div>
<div class="div-con">{{().padStart(2,0)}}</div><div class="div-dw">时</div>
<div class="div-con">{{().padStart(2,0)}}</div><div class="div-dw">分</div>
<div class="div-con">{{().padStart(2,0)}}</div><div class="div-dw">秒</div>
</div>
<div class="diachronic">
活动历时 : {{().padStart(2,0)}}:{{().padStart(2,0)}}:{{().padStart(2,0)}}:{{().padStart(2,0)}}
</div>
js:
calculateTheTime(row) {
// 此处获取时间信息完成倒计时单位转换
let start = new Date() ? dayjs(new Date()).format("YYYY/MM/DD HH:mm:ss") :""; // 当前最新的时间
let begin = ? dayjs().format("YYYY/MM/DD HH:mm:ss") : "" // 开始时间
let end = ? dayjs().format("YYYY/MM/DD HH:mm:ss") : "" // 结束时间
let start_num = new Date((/-/g, "/"))
let end_num = new Date((/-/g, "/"))
let begin_num = new Date((/-/g, "/"))
if(end_num.getTime() > start_num.getTime()){
= parseInt(end_num.getTime() - start_num.getTime())
()
= parseInt(start_num.getTime() - begin_num.getTime())
const Duration = parseInt(end_num.getTime() - begin_num.getTime())
(,Duration)
}else{
= parseInt(end_num.getTime() - begin_num.getTime())
const Duration = parseInt(end_num.getTime() - begin_num.getTime())
(,Duration)
}
},
formatDuring(millisecond) { // 手写倒计时 倒计时时间为0000的时候清除计时器
= parseInt(millisecond / (1000 * 60 * 60 * 24));
= parseInt((millisecond % (1000 * 60 * 60 * 24)) / (1000 * 60 * 60));
= parseInt((millisecond % (1000 * 60 * 60)) / (1000 * 60));
= ((millisecond % (1000 * 60)) / 1000);
= setInterval(()=>{
if(>0){
--
}else if(>0){
= 59
--
}
else if(>0){
= 59
--
}
else if(>0){
= 23
--
}
else if(==0){
clearInterval()
}
},1000)
},
css:
.active_nam{
margin-top: 0.625rem;
font-size: 1.3125rem;
color: #FFF;
}
.countdown{
display: flex;
margin-top: 1.875rem;
.div-con{
font-size: 1.25rem;
font-weight: 600;
width: 2.8125rem;
height: 2.8125rem;
color: #20209D;
background-color: #FFF;
border-radius: 0.3125rem;
display: flex;
justify-content: center;
align-items: center;
}
.div-dw{
font-size: 1.3125rem;
color: #FFF;
width: 2.8125rem;
height: 2.8125rem;
border-radius: 0.3125rem;
display: flex;
justify-content: center;
align-items: center;
}
}
.diachronic{
margin-top: 1.25rem;
font-size: 1.3125rem;
color: #FFF;
}
Switch组件(主要借助伪元素实现效果):
<div class="switch-con" @click="barrageIsShow = !barrageIsShow">
<div class="outer">
<input type="checkbox" :checked="barrageIsShow">
<div class="slider"></div>
</div>
</div>
css:
.switch-con{
margin-top: 1rem;
width: 3.8rem;
height: 2rem;
border-radius: 1.5625rem;
padding: 0.187rem 0 0 0.125rem;
border: 0.0125rem solid transparent;
background-clip: padding-box, border-box;
background-origin: padding-box, border-box;
background-image: -webkit-gradient(linear, left top, left bottom, from(rgba(33, 31, 48, 0.58))), -webkit-gradient(linear, left top, right top, from(rgba(193, 99, 152, 0.44)), to(rgba(176, 175, 242, 0.58)));
.outer{
width:3.375rem;
height:1.5rem;
position: relative;
.slider{
position: absolute;
left:0;
top:0;
right:0;
bottom:0;
background:rgba(33, 31, 48, 0.58);
border-radius: 1.125rem;
transition: 0.4s;
cursor: default;
line-height: 1.625rem;
&::before{
content: '';
position: absolute;
width:1.62rem;
height:1.62rem;
left:0;
top:-0.09rem;
border-radius: 50%;
transition: 0.4s;
box-sizing: border-box;
border: 0.0625rem solid transparent;
background-clip: padding-box, border-box;
background-origin: padding-box, border-box;
background-image: -webkit-gradient(linear, left top, left bottom, from(#CF48A9)), -webkit-gradient(linear, left top, right top, from(rgba(116, 30, 79, 1)), to(rgba(255, 255, 255, 0.44)));
}
}
input{
display: none;
&:checked + .slider{
color: #fff;
box-sizing: border-box;
border: 0.0625rem solid transparent;
background-clip: padding-box, border-box;
background-origin: padding-box, border-box;
background-image: -webkit-gradient(linear, left top, left bottom, from(#F487CD)), -webkit-gradient(linear, left top, right top, from(rgba(61, 12, 31, 0.85)), to(rgba(255, 255, 255, 0.24)));
}
&:checked + .slider::before{
left: 1.75rem;
}
}
}
}
2.借助 countTo 和 vueBaberrage 组件实施数字跳动以及弹幕效果
关于这两个组件的使用就不过多介绍大家自行去搜索也很简单
重点在于建立长链接生成一个唯一key后在把key储存给后端完成链接后通过vux加上侦听器实时监听数据变化并完成css效果,一下是部分代码:
长链接的js文件中:
import client from "./client"
const push = client();
// 这里的client 需要借助 @stomp/stompjs
export function initKey(shopcode) {
let str = shopcode + "-" + ();
("pushkey", str);
("wss:///ws" , shopcode + "|" + str , async function (frame) {
let {webdata,memberBuyInfo} = (frame);
if(webdata)
("update/setTimely",webdata);
if(memberBuyInfo)
("update/setBuyInfo",memberBuyInfo);
}, function (frame) {
('disconnect', frame);
});
}
在要是用的组件中侦听:
"$": function () { // 获取vuex中数据并操作
// (this.$,'setTimely徐飞');
()
= this.$
= // 保证第二次变化的初始值
= ?:0
},
"$": function () { // 获取vuex中数据并操作
// (this.$,'memberBuyInfo徐飞');
let memberBuyInfo = this.$
(memberBuyInfo)
}
弹幕样式更改:
/*弹幕区域高度*/
/deep/ .baberrage-stage {
padding: 12.5rem 2rem;
width: 87.5rem;
height: 62.5rem;
}
/*弹幕消息框*/
/deep/ .baberrage-item .normal {
padding: 0 1.25rem;
background: none;
}
// /*头像*/
/deep/ .baberrage-item .normal .baberrage-avatar {
width: 2.875rem;
height: 2.875rem;
border-radius: 50%;
border: 0.0625rem solid transparent;
background-clip: padding-box, border-box;
background-origin: padding-box, border-box;
background-image: linear-gradient(rgba(193, 99, 152, 0.44)), linear-gradient(to right, rgba(193, 99, 152, 0.44), rgba(176, 175, 242, 0.58));
img{
width: 2.875rem;
height: 2.875rem;
border-radius: 50%;
}
}
// /*文字*/
/deep/ .baberrage-item .normal .baberrage-msg {
height: 2rem;
margin-top: 0.4375rem;
margin-left: -0.5rem;
font-size: 1.125rem;
line-height: 2rem;
background: rgba(0,0,0,0.2)!important;
border-radius:0 1.5625rem 1.5625rem 0;
border: 0.0563rem solid rgba(193, 99, 152, 0.44);
border-left: none;
padding: 0 1.25rem;
}
3.原生js实现大屏效果(并改变fontsize大小完成rem自适应):
handleFullScreen (params) {
// 实现全屏的方法
function requestFullScreen(element) {
var requestMethod = || //W3C
|| //Chrome
|| //FireFox
; //IE11
if (requestMethod) {
(element);
} else if (typeof !== "undefined") { //for Internet Explorer
var wscript = new ActiveXObject("");
if (wscript !== null) {
("{F11}");
}
}
}
requestFullScreen();
let doc = ('Content')[0]
let bgimg = ('bg-img')[0]
= 'fixed'
= 0
= 0
= '100vw'
= '100vh'
= function () {
let doc = ('Content')[0]
if (!doc) { return }
if () {
('进入全屏')
if( > 1430) // 徐飞对单页面进行rem适配
=/105+"px"
// (,'') // 太强了
} else {
// 退出全屏的时候恢复原来的样式
('退出全屏')
= 'relative'
= 'inherit'
= 'inherit'
= 'inherit'
= 'inherit'
= 'inherit'
}
};
},
exitFull() { //退出全屏 esc键和F11可以直接退出,
// 判断各种浏览器,找到正确的方法
var exitMethod = || //W3C
|| //FireFox
|| //Chrome等
; //IE11
if (exitMethod) {
(document);
} else if (typeof !== "undefined") { //for Internet Explorer
var wscript = new ActiveXObject("");
if (wscript !== null) {
("{F11}");
}
}
},
遇到的问题:
1.子组件使用v-show后里面调用弹幕组件会失效
解决办法:使用路由加载数据实时大屏。顺便解决了大屏之前f11后丑陋的问题
其他还好都解决了。