上上个礼拜公司的展销会活动需要一个展示在LED大屏幕的页面,顶部显示平台交易总金额,左右两边分别是厂家和买家实时交易记录,具体页面长下面这个样子

需求评审的时候产品说顶部的总金额要有一个数字滚动或者翻牌子的效果,我想着我有封装好的运动框架,加个效果应该不是问题,然后自告奋勇的跟我们技术老大说想做这个页面,结果就是没称好自己几斤几两掉进了自己挖的大坑!!!

第一个坑是分辨率问题,当时设计把页面给我的时候说的LED屏幕是9*5米,所以他设计图的比例也是9:5,我就照着设计图开发了,之前PC端的布局都是用px做单位,但是这个页面做的时候为了可以兼容多个屏幕,用rem做单位(我真不喜欢rem,虽然它确实做到了不同尺寸显示器的兼容)。等快上线的时候发现投到LED上的页面下面有一道还挺宽的白边。因为那边笔记本的分辨率是1024*768,我开发的笔记本的分辨率是1600*900,背景图我是整个切下来了一张大背景图,改了分辨率之后背景图和字都被压扁了,背景图上显示时间的框的位置也变了,只能再改css,勉强改的能看了,但是页面变得很丑很丑...

第二个坑是左右厂家和买家交易记录无缝滚动,之前只做过图片的无缝滚动,实现方式是克隆法(把要显示的元素内容复制一份,当显示到复制内容部分时再设置从头开始滚),但是因为数据是每隔10分钟从后台调取,其实也可以实现啦,不过总之后来用了裁剪法(ul滚完了就remove,同时后面再新生成一个ul追加),定义一个数据存放请求的数据,去重之后push进去,显示的时候呢就是根据每屏展示的条数轮循这个数组,实现数据滚动展示。

第三个坑是定时器,页面里左右滚动、定时请求数据、加上金额累计滚动特效,我用的全部都是setInterval,差不多开了七八个,哪个没清也搞晕了,结果换成setTimeout,递归调用自己,不用担心哪个定时器没有清了。

第四个坑是自己疏忽造成的bug,把差额(请求到的金额减去上一次的金额)分成60份,每一秒钟累计一次,然后又写了个setTimeout每分钟请求一次数据,结果导致这一次的金额还没累计完,请求到的新数据已经开始累计了,然后就出现了页面忘回跳的bug,改了之后就可以了。

总结一下这次的收获吧,这次最大的收获就是认识到自己技术还很烂!不像是有三年开发经验的人。

把这次开发的部分代码贴上来吧(很烂,自己读着都费劲)

总金额累计部分代码

请求数据

function getMoney(){
//请求数据
$.ajax({
url: Domain.webDomain+"/countTodayOrder/getOrderAmount",
type: "POST",
dataType: "jsonp",
jsonp: "callback",
success: function (rs) {
if (rs.success) {
var money = rs.data; //返回的金额
var cookieAmount = getCookie("totalAmount"); //获取cookie中上次请求的金额
if (!cookieAmount) {
cookieAmount = "0";
}
cookieAmount = parseInt(cookieAmount); if(money != "null"){ //不为空的情况下
if (money.lastIndexOf(".") > -1) {
money = parseInt(money.substring(0, money.lastIndexOf("."))); //把金额小数点及以后的数据清掉
} else {
money = parseInt(money);
}
moneyProcess(money, cookieAmount);
}else{
moneyProcess(cookieAmount, cookieAmount);
}
}
}
});
}

累计金额前的操作

function moneyProcess(money,cookieAmount){
var oldMoney = 0;
var balance = money - cookieAmount;
var newMoney = cookieAmount; if(balance > 0) { //请求到的金额一定要比上一次的金额大,否则视为异常
var avgMoney = parseInt(balance / 60); //一分钟请求一次,每分钟显示的钱数
if (avgMoney < 1) { //如果平均每分钟的金额少于1块钱,就按1块钱算
avgMoney = 1;
}
moneyChange();
function moneyChange(){
oldMoney = newMoney;
newMoney += avgMoney;
if (newMoney <= money) {
showMoney(newMoney.toString(), oldMoney.toString());
setTimeout(moneyChange,1000);
}else{
showMoney(money.toString(), money.toString());
setTimeout(function(){ //每隔一秒钟请求一次数据
getMoney();
},1000)
}
}
setCookie("totalAmount",money,1); //累计完成后把这次的总金额存到cookie
}else{
setTimeout(function(){
getMoney();
},60000);
showMoney(newMoney.toString(),newMoney.toString());
}
}

金额滚动效果

function showMoney(money,oldMoney){
var money2 = money.toString();
money = formatMoney(money.toString(),0);
oldMoney = formatMoney(oldMoney.toString(),0);
if(money.length > oldMoney.length){
oldMoney = money;
} var hid_comma_left = document.getElementById("hid-comma").offsetWidth || 61;
var hid_num_left = document.getElementById("hid-num").offsetWidth || 86;
var hid_sign_left = document.getElementById("hid-sign").offsetWidth || 130; var moneyBox = document.getElementById("money-box"); var l = 0;
moneyBox.innerHTML = "";
for (var i = 0; i < oldMoney.length; i++) {
var span = document.createElement("span");
if (oldMoney.charAt(i) == ",") {
span.className = "comma";
span.left = hid_comma_left;
span.style.bottom = 0;
} else if (oldMoney.charAt(i) == "¥") {
span.className = "sign";
span.left = hid_sign_left;
span.style.bottom = 0;
} else{
span.style.top = "0";
span.className ="num num" + oldMoney.charAt(i);
span.left = hid_num_left;
}
span.num = oldMoney.charAt(i);
span.style.left = l + "px";
l += span.left;
moneyBox.style.width = l + "px"; //动态设置moneyBox的宽度
moneyBox.appendChild(span);
}
var spanList = document.getElementsByClassName("num"); //旧金额显示之后,替换为新金额
var k = spanList.length - 1;
moneyReplace();
function moneyReplace(){
if (k < 0) {
return;
}
if(money != oldMoney) {
if(spanList[k]) {
if (money2.charAt(k) == spanList[k].num && money != oldMoney) {
spanList[k].style.top = "0px"
k--;
} else {
startMove(spanList[k], {top: "-183"}, 50, "easeOut", function () {
this.style.top = "183px";
this.className = "num" + money2.charAt(k);
startMove(this, {top: "0"}, 50, "easeOut");
k--;
});
}
}else{
k--;
}
}
setTimeout(moneyReplace,150);
}
}

左右厂家买家交易记录滚动代码

获取数据
//把请求的数据添加到数组
function getScrollData(typeId,dataArr){ var url = ""; if(typeId == 0) { //买家订单信息
url = Domain.webDomain+"/countTodayOrder/getBuyerAmount";
}else{
url =Domain.webDomain+"/countTodayOrder/getFactoryAmount";
}
$.ajax({
url:url,
dataType:"jsonp",
jsonp: "callback",
success:function(rs){
if(rs.success ){
var data = $.parseJSON(rs.data);
if(data.length > 0){
$.each(data,function(key,item){
var json = {};
if(typeId == 0){ //买家交易
json.key = item.userId.toString() + item.orderId.toString();
json.name = item.nickName;
json.amount = formatMoney(item.amount,0);
}else{
json.key = item.factoryId.toString() + item.orderId.toString();
json.name = item.factoryName;
json.amount = formatMoney(item.amount,0);
} //去重复数据
if(findInArr(dataArr,json.key)) { //重复订单不添加到数组
dataArr.push(json);
}
});
}
}
}
});
}
滚动代码
function scrollMove(id,arr){

    //获取滚动元素
var scrollObj = document.getElementById(id);
var parentNode = scrollObj.parentNode;
var speed = 1;
var t = 0;
var h = scrollObj.offsetHeight / 2 - 2; scrollObj.sub = 0;
scrollObj.scrollIndex = 0;
scrollObj.count = 0; time();
function time()
{
scroll();
setTimeout(time,30);
} function scroll(){
if(t >= parentNode.offsetHeight ){
//换数据
scrollDataGet(arr,scrollObj);
t = 0;
}
if(scrollObj.children.length < 2){
scrollDataGet(arr,scrollObj);
}
if( scrollObj.children.length>2 ){
scrollObj.removeChild(scrollObj.children[0]);
}
t += speed;
scrollObj.style.top = -t + 'px';
} }

循环数组
function scrollDataGet(dataArr,scrollObj){

    var arr = []; //定义一个数组存这一轮要显示的数据信息

    while(arr.length<scrollSize) {

        var startIndex = scrollObj.scrollIndex * scrollSize + scrollObj.sub ;  //本轮开始数据

        var endIndex = startIndex + scrollSize;  //每轮显示12条,结束数据为开始数据加显示条数

        scrollObj.sub = endIndex - dataArr.length;

        if(scrollObj.sub > 0){
endIndex = dataArr.length;
scrollObj.scrollIndex = 0; }else{
scrollObj.sub = 0;
scrollObj.scrollIndex ++;
} //把数据添加到显示数组里
for (var i = startIndex; i < endIndex; i++) {
arr.push(dataArr[i]);
}
if(arr.length < scrollSize) {
if (scrollObj.sub > 0) {
if (scrollObj.sub > dataArr.length) {
scrollObj.sub = dataArr.length;
}
for (var j = 0; j < scrollObj.sub; j++) { //补数据
arr.push(dataArr[j]);
}
scrollObj.sub = 0;
}
} }
scrollDataFill(arr,scrollObj);
}

填充数据
function scrollDataFill(arr,scrollObj){

    var className = "";

    var ul = document.createElement("ul");
ul.className = "info-list"; for(var i = 0; i < arr.length; i++ ){
if( i % 2 == 0){
className = "odd";
}else{
className = "even";
}
var str = '<li class="' + className + '" ><span class="info-name" style="width:3.2rem;">' + arr[i].name + '</span><span class="info-name" style="width: 1.64rem; text-align: center;">' + arr[i].amount + '</span></li>'; ul.innerHTML += str;
}
scrollObj.appendChild(ul);
}

开发LED屏幕页面遇到的问题的更多相关文章

  1. 使用 video.js 开发 HTML5 视频页面

    时间 2015-05-13 17:11:58 The GIS Guy 原文  http://thegisguy.tk/html5-video-using-video-js/ 主题 Video.js H ...

  2. ASP.NET Core 开发人员异常页面

    UseDeveloperExceptionPage 中间件 我们谈谈在 Startup 类的 Configure()方法中以下代码: public void Configure(IApplicatio ...

  3. chrome拓展开发实战:页面脚本的拦截注入

    原文请访问个人博客:chrome拓展开发实战:页面脚本的拦截注入 目前公司产品的无线站点已经实现了业务平台组件化,所有业务组件的转场都是通过路由来完成,而各个模块是通过requirejs进行统一管理, ...

  4. Android中使用ViewPager实现屏幕页面切换和页面切换效果

    之前关于如何实现屏幕页面切换,写过一篇博文<Android中使用ViewFlipper实现屏幕切换>,相比ViewFlipper,ViewPager更适用复杂的视图切换,而且Viewpag ...

  5. [课程设计]Scrum 3.2 多鱼点餐系统开发进度(页面优化&下单详细信息页面)

    Scrum 3.2 多鱼点餐系统开发进度(页面优化&下单详细信息页面)  1.团队名称:重案组 2.团队目标:长期经营,积累客户充分准备,伺机而行 3.团队口号:矢志不渝,追求完美 4.团队选 ...

  6. 实战使用Axure设计App,使用WebStorm开发(5) – 实现页面功能

    系列文章 实战使用Axure设计App,使用WebStorm开发(1) – 用Axure描述需求  实战使用Axure设计App,使用WebStorm开发(2) – 创建 Ionic 项目   实战使 ...

  7. 实战使用Axure设计App,使用WebStorm开发(4) – 实现页面UI

    系列文章 实战使用Axure设计App,使用WebStorm开发(1) – 用Axure描述需求  实战使用Axure设计App,使用WebStorm开发(2) – 创建 Ionic 项目   实战使 ...

  8. 实战使用Axure设计App,使用WebStorm开发(3) – 构建页面架构

    系列文章 实战使用Axure设计App,使用WebStorm开发(1) – 用Axure描述需求  实战使用Axure设计App,使用WebStorm开发(2) – 创建 Ionic 项目   实战使 ...

  9. Scrum 3.2 多鱼点餐系统开发进度(页面优化&下单详细信息页面)

    Scrum 3.2 多鱼点餐系统开发进度(页面优化&下单详细信息页面)  1.团队名称:重案组 2.团队目标:长期经营,积累客户充分准备,伺机而行 3.团队口号:矢志不渝,追求完美 4.团队选 ...

随机推荐

  1. C#反射发出System.Reflection.Emit学习

    一.System.Reflection.Emit概述 Emit,可以称为发出或者产生.与Emit相关的类基本都存在于System.Reflection.Emit命名空间下.反射,我们可以取得形如程序集 ...

  2. 利用rman自己主动备份转储spfile

    利用rman自己主动备份转储spfile [情景简单介绍] 生产环境丢失了server的參数文件,rman已开启自己主动备份设置. [操作过程简述] ----启动rman $rman target / ...

  3. Python:SMOTE算法——样本不均衡时候生成新样本的算法

    Python:SMOTE算法 直接用python的库, imbalanced-learn imbalanced-learn is a python package offering a number ...

  4. 你真的懂SDWebImage?

    SDWebImage已经到了用烂了的地步,对于一名优秀的开发者来说,会用只是最简单的一步,我们要能够研究到其底层的技术实现和设计思路原理.在网上偶然间看到了一篇文章,感觉不错,略作修改,批注,后面的内 ...

  5. handbook/CentOS/使用免费SSL证书让网站支持HTTPS访问.md

  6. struts2什么情况用#和EL表达示

    1:struts2标签使用中,什么时候用#,什么时候可以不用# 值栈中的对象的不使用#,非值栈中的对象使用#如果不理解值栈的作用,简单点理解:当前action,或者处于action链中的action所 ...

  7. [Swift通天遁地]三、手势与图表-(1)监听屏幕上触摸事件的各种状态

    ★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★➤微信公众号:山青咏芝(shanqingyongzhi)➤博客园地址:山青咏芝(https://www.cnblogs. ...

  8. max_allowed_packet设置问题

    最近在运行的项目出现了一个线上事故,有人反映商城的东西下不了单了,到后台看了一下,果然报了一个错 Cause: com.mysql.jdbc.PacketTooBigException: Packet ...

  9. 【BZOJ2565】最长双回文串 (Manacher算法)

    题目: BZOJ2565 分析: 首先看到回文串,肯定能想到Manacher算法.下文中字符串\(s\)是输入的字符串\(str\)在Manacher算法中添加了字符'#'后的字符串 (构造方式如下) ...

  10. Servlet访问路径的两种方式、Servlet生命周期特点、计算服务启动后的访问次数、Get请求、Post请求

    Servlet访问路径的两种方式: 1:注解 即在Servlet里写一个@WebServlet @WebServlet("/myServlet") 2:配置web.xml < ...