Skip to content

年会祝福+抽奖程序前端设计 #5

Open
@Alexis374

Description

@Alexis374

贵司2016年年会抽奖的任务分派给我了,需求如下:

  • 现场会有人从内部聊天工具发送祝福语,服务端提供http接口,前端取得数据进行展示,类似人人墙的效果。
  • 给定参会人员抽奖名单,从中抽取一等奖,二等奖,三等奖等奖项,并展示效果。

需求看起来简单,但是经不住需求人员反反复复变更的需求啊,直到上线前一天,还否定了之前的设计,重新找人设计了图,更不用说抽奖规则之类的了。。。
接到需求之后,我认真研究了一下,具体需要注意以下几点:

  1. 时效性短,应用范围窄。仅需一台电脑打开网页,展示页面,然后投放到大屏幕上,不用考虑浏览器兼容性问题;
  2. 需要考虑安全性问题。后台的接口是不做任何过滤的,如果有人恶意地注入js脚本,比如弹个框什么的,阻塞页面展示,直接GG。
  3. 抽奖工作在浏览器端做,应该在页面加载的时候就一次性做好,而不应等到点击按钮时再做,否则会出现卡顿的情况。
  4. 对抽奖人员名单要做好去重处理,已经中过一次奖的人不能再次中奖。

我列出的技术方案如下:
1. 用Vue.js做前端MVVM框架,展示页面
2. 用lodash做列表筛选,随机选择指定的人数,作为中奖人员,且进行去重处理。
3. 用xss.js做xss过滤
4. 抽奖页面和显示中奖结果页面是两个页面,抽奖的计算是在抽奖页面,在这个页面计算后,存入localStorage里面,中奖结果页面从中取出结果并显示。
5. 祝福页面,需要定期清理已经展示过的祝福语,减少浏览器性能损耗。不过用了Vue之后,将要显示的数据和Model层双向绑定,清除过期数据只需更改代表数据的数组即可。

具体实施过程以及部分注意事项:

  1. 表情包解析:
  • 所发祝福里面可以含有表情,类似“/:snbye”,这种形式,对应一个文件名,需要解析出文件名,拼接出地址,请求出图片。有个表情和图片名称对应的关系,是xml格式的。前台js不方便解析xml,我首先用python将这种对应关系转成json形式的。主要用了BeautifulSoup解析xml,再写入json文件。
  • 页面加载时,在初始化Vue对象时在生命周期的compile阶段将这些json文件的内容请求并缓存为改model的emotion_list对象。
  • 对于每一条信息,遍历emotion_list,截取出表情,转成文件名,并拼接出img标签。这一步写成了filter形式,可以直接在模板中调用。
  • 需要注意的是虽然Vue默认会过滤html标签,但因为img标签是动态生成的,必须动态插入,会留下安全隐患。因此,这一步可以借助xss.js的白名单机制,只允许img标签的src属性,生成过滤规则,应用在动态生成的img上。
  • 获取祝福语并展示
  • 因为页面上只展示3,4条数据,展示过的数据需要删除,而一次请求20条数据。我设置了两个数组,people数组一个与页面上的模板绑定,用于显示数据,另一个是tmp数据,作为取得数据的缓冲。
  • 当tmp内有数据时,将tmp的数据插入到people头部,但当people的长度大于4时,则将后面的people[4]后的所有数据清除。 当tmp的length小于40时,向服务器获得新数据
  • 以上策略需要两秒钟展示一次新数据,所以需要循环2s执行。但setInterval长时间执行后,间隔就会越来越失真,所以我利用setTimeout改写如下:
        function interval(lastId){

        var flag = setTimeout(function(){
            clearTimeout(flag);
            //长度大于40 直接展示页面
            if(vm.tmp.length>40){
                callback.call(vm,2);
            }
            //请求数据 展示页面
            else{
                request(lastId,callback,function(err){console.log(err);}) 
            }
        },2000)
        }

然后在callback里再次调用interval函数,以实现间隔调用

  • 为防止系统出现错误刷新后又从第一条开始显示,我将每次请求的lastId保存在localStorage里,以保证下次请求从这个id开始。
  • callback里做的事情主要是判断tmp长度,大于40直接展示,或者不足40时,根据请求到的数据,往tmp里添加
  • 在实践过程中,我首先用了Vue的vue-resource库发送jsonp请求,但在请求次数多了以后,vue-resource虽然能发送成功数据,但是无法调用回调,一直处于pending状态,可能是实现上有bug。不得已换用jquery的ajax,没有出过问题
  • 动画效果
    动画效果前期折磨了我好长时间。如果直接用jquery操作DOM的话,那么写动画效果很简单的。但是现在模型层和模板绑定,people的第一个元素就是模板li的
    第一个子元素,而且由上可知,新数据是由tmp插入people的第一个元素,然后原本是第一个的数据现在变成第二个,以此类推。而再向其应用动画效果,很容易
    导致错乱。经过多次尝试,我利用了Vue的过渡系统,在过渡开始的时候找到元素,及其兄弟元素,应用jquery在1s内改变其top值。刚好能达到效果。但这次算是
    误打误撞地成功了,因为改变时间间隔,又会导致动画错位。若因为动画的原因不能成功,那么只能放弃使用Vue,而是老老实实直接操作DOM
  • 抽奖
    抽奖完成的操作主要是筛选,去重等。lodash封装了各种对象,数组操作的方法,很容易就实现了所需的功能。如_.sampleSize,_.differenceWith等。

总结:
这个项目是我将Vue应用于实战的第一个项目,并没有用到高大上的组件等功能。从这次项目中我体会到了只看文档是永远停留在纸上谈兵的阶段,唯有真刀真枪应用于实战,才能提高自己的水平。
同时,没有哪种技术是万能的,要根据自己的需求选择合适的技术。这就需要涉猎各种技术的同时,能够取其精华,分辨其应用场景。
ps: 因为做了这个,给了个正激励200,啊哈哈。。。

Metadata

Metadata

Assignees

No one assigned

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions