tuy

杭州市民卡微信2.4版本上线总结

一:前言

2015年12月25日,微信2.3版本成功上线,后台Struts,前端jsp。关注用户数突破50万。

2016年4月29日,微信2.4版本成功上线,后台Struts,前端HTML视图模板,请求全部ajax异步完成,页面真正实现无刷新。

二:心路历程

2015年有一次去恒生电子跟学长(7年前端从业经验)交流HTML5时,两人针对是否自主开发维护前端控件展开了讨论,学长一直建议学习使用现成的成熟控件,拿来主义;我却沉浸在自己写一些小控件的世界里面。其实市面上的前端框架品类非常多,我们根本来不及一一学习,从早期的prototype,mootools,YUI,到后来的jquery,requireJs,seaJs,angularJs,bootstrap等等真的好多好多,每个框架都有各自的优点。跟学长讨论下来,我也慢慢认可他的观点了,在学习认知阶段确实应该尝试封装控件,学习底层原理,毕竟每个框架都是基础语法封装而成,当从业4~5年之后应该要考虑控件稳定性和维护成本,以我们的自己封装的控件虽然轻量,但是需要投入比较大的维护成本,而且是你个人或者小团队产出,这样难免会有未曾考虑到的场景。所以直接学习使用社区成熟的控件可以大大提高产品稳定性,遇到问题也方便到git或者社区里面参与讨论寻求答案,不过使用的同时也不能忘记学习,因为控件都离不开基础的知识,当我们控件用久了之后,肯定会碰到边缘冷门问题,相信我,肯定会遇到,这时候如果基础扎实就能大大提高定位问题解决问题的速度。结束前学长向我推荐了Framework7(F7)前端框架,恒生电子现在有一款新的金融app已经开始采用这套框架进行尝试开发,并展示了这款半成品的native应用,机型是iphone5s,测试下来,功能点的页面切换非常流畅,并且得知,这套框架在ios下面操作无卡顿,在Android低版本手机会出现卡顿,考虑到目前市面的Android手机一般性能都不会太低,于是他们采用了F7框架。

其实当时学长演示的时候,我就在脑海里琢磨这套框架效果逼近native,如果用到自己公司的杭州市民卡微信会怎么样,效果当然非常炫酷,我自己盲目的肯定了它。为了肯定这份盲目,于是2015年下半年开始抽空学习F7框架。F7框架最初是由国外idangero团队出品,后来淘宝对其官网进行翻译,当然里面一些冷门的API还没有翻译。

时间马上到2015年11月份,启动微信2.3版本开发,此时考虑到后台小伙伴工作比较繁忙而且自己对F7的实战还偏少,于是直到微信2.3成功上线之后,我才联系部门经理和产品经理一起提出自己关于微信2.4前端彻底改版的想法,希望采用MVC的前端框架,让用户感觉我们的微信公众号跟app的体验类似,抛弃现行的jsp页面,使用HTML+AJAX异步模式,视图用静态HTML,数据全部通过json传递,前端的业务控制全部放在js里,后台单纯负责接受参数,返回数据。并把前段时间自己的一些F7的实践和利弊一并抛出来,产品比较关心适配性,并表示Android中高端机型不卡顿就可以接受,部门经理也非常支持我,决定调动后台一起全力配合改版微信2.4,好了,一切就绪,就等结果啦!!

经过整个团队2个月的辛勤加班加点,修改完成128个bug,终于在2016年4月29日成功上线全新的微信2.4版本,看着F7框架在线上稳定的运行,自己内心也充满了成就感。这个版本出来以后,意味着以后只要后台逻辑不变,前端表现层的更新升级,都可以在HTML视图模板上进行,彻底解耦!

bug统计图如下:


三:F7框架小结

1:在前端渲染引擎上不需要单独引入juice或者其它框架,F7自身集成了template7前端引擎,让我们在组织json数据的时候非常方便,使用方法类似普通引擎,但功能更加强大,具体详见官网地址:http://idangero.us/template7/

2:添加主视图时,设置domCache:true,可以对二级以上页面进行缓存,大大减少服务器请求,提升用户返回速度。

3:框架默认对a标签的href做了处理,所有地址全部默认采用ajax载入载入,如果特殊页面需要跳出框架,API告诉我们只要给a标签加上class=external即可。但是在微信2.4中我没有用到external,使用这个样式名之后整个页面会被刷新,之前缓存的DOM片段会被清空,当我们返回的时候,DOM将需要重新请求。于是自己使用事件代理封装了一个iframe的跳转,当a标签含有class=frame_detail时,让它默认跳转到一张iframe的视图,然后把url里面的外链地址传到iframe的src属性中。截止目前,资讯详情、地图详情、协议详情这三个跳转都是iframe方式,保留DOM片段,大大提高用户返回速度。

4:因为公司配备专业的UI工程师,很多F7框架里面的控件需要样式覆盖,这时候新建一个screen.css来进行样式重载,不要去修改F7的自身样式,上线的时候再用grunt把所有css和js压缩合并,切记合并css的时候一定是F7自身css在先,自定义的css在后。

5:载入ajax数据和滑动翻页使用比较频繁,自己在原先框架基础上针对市民卡项目特性,又封装了ajaxGetData、ajaxNextPage两个方法,分别是拿到数据渲染和翻页功能,暴露合理参数,方便各个页面场景调用。

方法代码:

//ajaxGetData
		app.ajaxGetData = function(config){
			var a = new Date();
			b = a.getTime().toString(),
			date = b.slice(0,-3),
			data = config.data || function(){return{}},
			url = config.url,
			view = config.view,
			fn = config.callback || function(){},
			el = '.page[data-page="' + config.target + '"]',
			el = $$(el),	
			current = el.find('input.currentPage'),
			currentPage = parseInt( current.val() || 0),
			max = el.find('input.maxPage'),
			pageno = config.pageno || 'pageno',//请求页码字段
			wrap = config.wrap || $$(el).find('.list-block ul'),
			data = data();
			if(AJAXDATE == date){ //设置全局变量,当滚动惯性的时候,点击切换标签,不进行数据加载,把毫秒转换成秒,同一秒只发送一次请求。
				fn();
				return
			}	
			AJAXDATE = date;
			if( data.currentPage ){
				data[pageno] = data.currentPage; 
			}
			else{
				data[pageno] = ++currentPage;
			}
			$$.ajax({ //ajax回调完成之后,再把返回的数据填进去
				  async:true, //异步请求
				  method:'GET',	
				  url: url+'?'+date, //增加随机数防止请求缓存
				  data: data, //模拟传递参数
				  dataType:'json',
				  success:function (data) {
						// 生成新条目的HTML
						var html = '';						
						current.val(data['pageno']);
						max.val(data['totalpage']);	
						html = SMK.templates[view](data);
						// 添加新条目
						wrap.append(html);
						fn();
				 }
			}); 
		}
		
		//ajaxNextPage
		app.ajaxNextPage = function (config){
			var data = config.data || function(){return{}},
				url = config.url,
				view = config.view,
				tips = config.tips || '已经没有更多了~',
				loading = false,
				el = '.page[data-page="' + config.target + '"]',
				el = $$(el),
				current = el.find('input.currentPage'), 
				max = el.find('input.maxPage'),
				// 注册'infinite'事件处理函数
				$$(el).find('.infinite-scroll').on('infinite', function () {
				  // 上次加载的序号
				  var currentPage = parseInt(current.val() || 1),
				  // 最多可加载的条目
				  maxPage = parseInt(max.val() || 2);	
				  // 如果正在加载,则退出
				  if (loading) return;
				  // 设置flag
				  loading = true;
				  // 模拟200ms的加载过程
				  //setTimeout(function () {
					if (currentPage >= maxPage) {
					  // 加载完毕,则注销无限加载事件,以防不必要的加载
					  myApp.detachInfiniteScroll($$('.infinite-scroll'));
					  loading = false;
					  // 删除加载提示符
					  $$(el).find('.infinite-scroll-preloader').remove();
					  $$(el).find('.infinite-scroll').append('<p class="tips_nomore" >' + tips + '</p>');
					  return;
					}
				    app.ajaxGetData({
						target:config.target,//当前点击的对象 String
						view:view,
						data:data, // 传递给后台的数据 Object
						wrap:config.wrap || $$(el).find('.list-block ul'),
						callback:function(){loading = false;},//loading传值进入ajaxGetData之后不能反向映射到外面来,所以使用回调函数
						url:url, //请求地址 String
						pageno:config.pageno || 'pageno',//请求页码字段
					});	

				  // }, 200);
				});   		
		}

5、上述都是个人的一些理解,欢迎正在使用F7框架的小伙伴不吝指正。

四:参考资料: framework7-cn-bbsframework7英文官网framework7淘宝团队翻译

码字很辛苦,转载请注明来自tuy博客《杭州市民卡微信2.4版本上线总结》

评论