在交易下单的页面中,如产品过多则会影响页面展示,影响用户体验效果;所以通过对产品恰当归类与良好的用户交互,会给用户体验度带来大大的提升,而静态无刷新互动体验效果则更好;据说如果你的客户被吸引,久而久之,你客户的客户也会成为你的客户(有点虚J),不论是什么样的交易(B2C、C2C,抑或是纯DEMO的产品网站)。
本文通过示例详细描述客户端产品展示处理过程,主要以游戏产品充值下单为例,
技术实现:DIV +CSS + JS +JQUERY+XML
§、实现效果
1、shop.sdo.com
上面的仅仅为产品展示,相对简单一下。
2、pay.sdo.com
3、pay.sdo.com
§、分析设计
1、 Process Flow:
UI ------> Handler ------> XML
UI <------ Handler <------ XML
类似局部MVC,Handler为控制器、XML数据对象为模型、UI为视图
UI响应事件发送至Handler,由Handler负责与XML交互、组织数据结构,控制UI显示。
2、 根据输入自动过滤相关产品,且按字母排序
支持字母、汉字检索
3、 点击显示分类产品遮罩,按字母排序
4、 选中产品自动完成表单填充
账号类型、游戏区、服务器、服务组、充值方式、充值金额(线性、非线性)etc.
5、 弹出层需要遮罩高优先级对象:select、flash等
6、 自动记录点选产品历史
7、 支持回调,自定义代码处理片段
可根据不同的产品显示不同的公告
可自定义不同的产品、子产品、子项配置,创建不同的UI、特殊业务显示etc.
8、 不同浏览器的兼容性问题
9、父页面自适应处理
10、……
§、设计实现
将以上几部分,分类处理:
1、 用于支持JQUERY的辅助类:
主要处理兼容性、XMLDOM、元素优先级、其他扩展信息。
代码片段:
<span style="font-family:Microsoft YaHei;">var ItemDom;
(function($) { // hide the namespace
$.LoadXml = function(dname) {
try { //Internet Explorer
var xmlDoc;
if (window.ActiveXObject) {
xmlDoc = new ActiveXObject('Microsoft.XMLDOM');
xmlDoc.async = false;
xmlDoc.load(dname);
} else if (document.implementation && document.implementation.createDocument) {
var xmlhttp = new window.XMLHttpRequest();
xmlhttp.open("GET", dname, false);
xmlhttp.send(null);
// var xmlDoc = xmlhttp.responseXML.documentElement;
var xmlDoc = xmlhttp.responseXML;
} else {
return null;
}
return xmlDoc;
}
catch (e) {
//alert(e.message)
}
return (null);
};
//根据path,attribute name获得指定节点的属性值
$.GetXmlAttr = function(Xml, path, attr) {
var depositItemsDom;
if (typeof Xml == "object") {
depositItemsDom = Xml;
}
else {
depositItemsDom = this.LoadXml(Xml);
}
if (depositItemsDom != null) {
var record = depositItemsDom.selectNodes(path);
if (record && record[0]) {
return record[0].getAttribute(attr);
}
}
return null;
};
$.GetNameById = function(value) {
if (ItemDom == null) {
ItemDom = $.LoadXml("../Config/DepositItems.xml");
}
return $.GetXmlAttr(ItemDom, "//items/item[@id='" + $.trim(value) + "']", "name");
};
//根据充值项名称获得充值项ID
$.GetIdByName = function(value) {
if (ItemDom == null) {
ItemDom = $.LoadXml("../Config/DepositItems.xml");
}
return this.GetXmlAttr(ItemDom, "//items/item[@name='" + $.trim(value) + "']", "id");
};
/* common */
$.fn.addOption = function(text, value) {
if ($(this).length > 0) $(this).get(0).options.add(new Option(text, value));
};
$.Message = { Info: "", Error: "" };
$.extend({
getWidth: function(object) {
return object.offsetWidth;
},
getLeft: function(object) {
var go = object;
var oParent, oLeft = go.offsetLeft;
while (go.offsetParent != null) {
oParent = go.offsetParent;
oLeft += oParent.offsetLeft;
go = oParent;
}
return oLeft;
},
getTop: function(object) {
var go = object;
var oParent, oTop = go.offsetTop;
while (go.offsetParent != null) {
oParent = go.offsetParent;
oTop += oParent.offsetTop;
go = oParent;
}
return oTop;
}
});
})((jQuery));</span>
2、 行为交互类
点选、输入控件事件绑定
初始化配置化参数
XML、DOM分类处理
内部辅助方法
为减少HTTP连接数,将以上处理合并至一个文件中。
代码片段:
(function($) { // hide the namespace
$.Inputer = {
InitConfig: function(parameters) {
$.extend($.InitConfig, parameters || {});
cg.id = $.InitConfig.inputid;
cg.pmd = $.InitConfig.paymethod;
cg.cdiv = $.InitConfig.clickdiv;
cg.sdiv = $.InitConfig.selectdiv;
if ($("#" + cg.id).length == 0) { return; }; //alert('config is Invalid');
//绑定控件
IBindControl();
IBindBody();
if (cg.pmd == 90) $.InitConfig.paymethodcmd = 90;
else $.InitConfig.paymethodcmd = 60;
//页面初始化(bank首页服务端特殊处理)
if (cg.pmd != "60") PageRender.PageInit();
}
};
$.InitConfig = {
paymethod: '', //充值渠道
paytype: '', //充值类型:bindpay,bank
inputid: 'inputGame', //输入控件ID
imageid: 'imgGame', //下拉图片ID
selectdiv: 'SelectDiv', //用户输入字符时显示的DIV 默认
clickdiv: 'ClickDiv', //用户点击输入框时输入的DIV
CallBackEvent: function() { }, //触发自定义事件
configpath: '/Config',
clickcss: '',
selectcss: 'AllBrow',
isBindArea: true,
DisableItem: '', //不显示的充值项
PlayerTypeEvent: null,
ConsumeEvent: null,
paymethodcmd: 60
};
IBindControl = function() {
$("#" + $.InitConfig.imageid).bind("click", IClick);
$("#" + cg.id).bind("keyup", ISelect);
$("#" + cg.id).bind("focus", IFocus);
$("#" + cg.id).bind("blur", IBlur);
};
IClick = function() {
$("#popup").css("display", "none"); //热血传奇提示
if (cg.pmd == "60") PageRender.PageInit(); //bank首次为服务端,所以重新初始化
var obj = $("#" + cg.id).get(0);
if ($("#" + cg.cdiv).length == 0) {
var left = right = 0;
if ($.browser.msie && $.browser.version.search("7.0") != -1) { left = 25; right = 19; }
else if ($.browser.msie && $.browser.version.search("6.0") != -1) { left = 30; right = 12; }
else { left = 8; right = 18; }
$("<div id='" + cg.cdiv + "'></div>").appendTo($("body")).css({ left: $.getLeft(obj) - left + 'px', top: $.getTop(obj) + right + 'px', display: '' });
}
else { $("#" + cg.cdiv).show(); }
//hide select div
$("#" + cg.sdiv).hide();
//fill data
GetClickData();
};
ISelect = function(event) {
if (cg.pmd == "60") PageRender.PageInit();
$("#" + cg.id).val($.trim($("#" + cg.id).val()));
if ($("#" + cg.id).val() == '') return;
if ($("#" + cg.sdiv).length == 0) {
$("<div id='" + cg.sdiv + "' onkeydown='return PageRender.selectKeyDown(event)'></div>").appendTo($("body")).css({ left: $.getLeft(this) + 'px',
top: $.getTop(this) + 20 + 'px', display: ''
});
}
else { $("#" + cg.sdiv).show(); }
//hide click div
$("#" + cg.cdiv).hide();
//获取下拉数据
GetSelectData(event);
};
IFocus = function() {
$("#popup").css("display", "none"); //热血传奇提示
$("#" + cg.id).css({ color: '#000000' });
$("#" + cg.id).select();
};
IBlur = function() {
var str = "汉字| 拼音 |字母";
if ($(this).val() == "") $(this).val(str);
else if ($(this).val() == str) $(this).css({ color: '#a7a7a7' });
};
//异步获取点击数据
GetClickData = function() {
$("#" + cg.cdiv).show();
$(cg.cdiv).remove("iframe");
if ($(cg.cdiv).html() == "") return;
else $("#" + cg.cdiv).html(PageRender.createList());
$("#" + cg.cdiv).bgiframe();
};
//异步获取过滤数据
GetSelectData = function(e) {
$("#" + cg.sdiv).show();
PageRender.getFilterList(e);
$("#" + cg.sdiv).bgiframe();
};
IBindBody = function() {
$("body").bind("click",
function(event) {
var e = event || window.event;
var srcElement = e.srcElement || e.target;
if (srcElement.type != "name" && srcElement.tagName != "A"
&& srcElement.id == "") {
$("#" + cg.cdiv + ",#" + cg.sdiv).hide();
}
PageRender.AutoIframe();
}
);
};
$.Reset = function() {
Game = GameID = PlayerType = PlayerName = ConsumeMode = GameArea = GameAreaID = GameServer = GameServerID = ParValue = BankID = null;
};
$.IsNull = function(obj) {
if (!obj || obj == null || typeof obj == "undefined") return true;
return false;
};
})((jQuery))
var MyXml = {
ConsumesPath: function() {
return "//deposititem/paymethods/paymethod[@id='" + $.InitConfig.paymethodcmd + "']/consumes/consume";
},
//根据游戏ID获得游戏名称
GetNameById: function(value) {
if (DepositItemsDom == null) {
DepositItemsDom = this.GetDepositItem();
}
return $.GetXmlAttr(DepositItemsDom, "//items/item[@id='" + $.trim(value) + "']", "name");
},
//根据充值项名称获得充值项ID
GetIdByName: function(value) {
if (DepositItemsDom == null) {
DepositItemsDom = this.GetDepositItem();
}
return $.GetXmlAttr(DepositItemsDom, "//items/item[@name='" + $.trim(value) + "']", "id");
},
GetDefaultDom: function() {
return $.LoadXml($.InitConfig.configpath + "/Default.xml");
}
};
//----------------------------------- 页面输出 -----------------------------------//
var PageRender = {
//
};
§、调用
<span style="font-family:Microsoft YaHei;">$(document).ready(function() {
//配置绑定到页面控件、初始信息
$.Inputer.InitConfig({ paymethod: 60, inputid: 'inputGame', imageid: 'imgGame', selectdiv: 'SelectDiv', clickdiv: 'ClickDiv',
CallBackEvent: function(paras) { BindGameEvent(paras); Bulletin.SetDepositItemTip(paras); }
});
BankDeposit.PageInit();
Bulletin.SetDepositItemTip(GameID);
});
var SubmitOrder = {
PageInit: function() {
PageRender.setValue(GameID); //重置游戏项
}
};</span>
§、示例
http://download.youkuaiyun.com/download/webwalker/7470335
§、总结
当然产品展现方式有很多种,根据实际情况与特殊业务决定,除了以上的JS+XML的方式来实现,通过JS+JSON组织数据也是不错的选择。
总体实现下来,更多的复杂业务上实现,由于时间关系,这块并未有完全剥离,代码上也有并不到位之处:全局变量、样式配置etc.