四核驱动的三维导航—淘宝新UI(设计篇)
前面有一篇博客说到了淘宝UWP的"四核驱动的三维导航—淘宝新UI(需求分析篇)",花了两周的时间实现了这个框架,然后又陆陆续续用了三周的时间完善它。
多窗口导航,与传统的导航方式的最大的不同点是:
- 需要指定目标窗口(target Frame)
- 维护上下文关系(context)
- Back Stack的维护
- 页面间的异步通信
- 适配Desktop和Mobile界面
- 支持Continuum(optional)
本篇博客先说一下前三个问题如何解决。
在从页面A跳到页面B时,单窗口模式下,很简单,只要在页面A中调用系统方法就可以了:
this.Frame.NavigateTo(typeof (PageB));
因为页面A使用的Frame和页面B使用的Frame相同。但是在多窗口(多Frame)时,你需要指定页面B使用那个Frame作为目标窗口。
比如,淘宝首页:

在点击了"淘抢购"频道的入口后,你想在什么地方显示淘抢购的主页面呢?在目前的Taobao UWP中,我们选择在主页的右侧显示(但是考虑到淘抢购的使用频率,我们可能会考虑在下一版中把它作为一个独立的Scenario来对待,也就是说可能要在目前的主页的位置显示)。于是,界面就会变成这样:

这就要求在导航方法中多一个参数来指定具体的位置。按照我们的设计,在Taobao UWP中有以下4个Frame承担具体的导航工作:

Home Frame:作为一个Scenario的首页,必须存在。
List Frame:显示商品列表,可以存在。有些Scenario,它的首页就是一个商品列表,就在Home Frame里显示了,List Frame可以不存在。
Detail Frame:详情页,必须存在。基本上所有的商品,都是要通过详情页来展示具体的商品信息的。当然,在别的Scenario中,如"我的淘宝"场景,可以用此Frame显示别的非商品内容。
Chat Frame:附加页,一般用于显示内置旺信聊天窗口,必须存在。
淘宝首页是显示在Home Frame中的,点击淘抢购入口后,code里都做了什么坏事儿呢?
Nav.To(NavToUrls.RushBuy_Home, mode: NavMode.List_Replace);
其中,Nav是我们自定义的一个导航帮助类,To()是它的静态方法,定义如下:
public static bool To(string url, object param = null, NavMode mode);
参数解释:
- string url:这个是必须的。我们把所有的页面都指定了一个URL,淘抢购的主页的URL定义如下:
public const string RushBuy_Home = "taobao://go/RushBuy/index";
- object param:指定页面间传递的参数。
- NavMode mode:指定导航模式,是一个枚举值,定义如下:
public enum NavMode
{
Default, // show page in scenario frame
Home_Add, // show page in scenario frame
List_Add, // show page in list frame, keep old page (if exists) in back history
List_Replace, // show page in list frame to replace the old page (clear old page in back history)
Detail_Replace, // show page in detail frame to replace the old page (clear old page in back history)
Detail_Replace_Clear, // same as above, also delete page in list frame
Chat_Add, // show page in chat frame, keep old page (if exists) in back history
Chat_Replace, // show page in chat frame to replace the old page (clear old page in back history)
Chat_Replace_Clear, // same as above, also delete pages in list/detail frame
}
每个枚举值都包含有两个信息:位置,方式。如List_Add,下划线前面的"List"表示位置,在List Frame中显示目标页面;下划线后面的"Add"是方式,一共有三种方式:
- Add:如果在目标Frame中已经有其它页面存在,则在已有页面基础上再做一次Navigation,也就是back stack历史中会多出一个记录。
- Replace:如果目标Frame中已有其它页面存在,则"删除"它,也就是在back stack中清空历史记录,然后做一次Navigation,最后back stack中只有最新的页面记录。
- Replace_Clear:同Replace,另外,如果前面的Frame中(除了Home Frame以外),如果有页面存在,则清除它们。
我们逐个解释一下这些参数的用法。
为什么需要Add/Replace方式?举个例子,在淘宝首页,假设用户先点击了天猫:

然后用户又在左侧首页上点击了淘抢购:

由于天猫和淘抢购都是在List Frame中显示,于是淘抢购把天猫覆盖了。此时用户按Back键,希望看到什么?显然不是要回天猫!于是,我们是这样指定淘抢购的导航方式的:
Nav.To(NavToUrls.RushBuy_Home, mode: NavMode.List_Replace);
它指定了淘抢购在List Frame中显示,用Replace方式,也就是清掉前面的天猫的痕迹。
何时用Add方式呢?比如用户在首页点了搜索:

右侧进入了搜索起始页面,用户输入搜索词后按回车,再进入搜索结果页面:

此时用户想改一下搜索的关键字为lumia 950 xl,点击一下搜索结果页上方的搜索框,就会回到搜索起始页。对于这个Scenario,我们需要这样使用导航方法:
1)在首次进入搜索起始页时,使用Replace方式来清空历史:
Nav.To(NavToUrls.Go_Search, mode: NavMode.List_Replace);
2)在进入搜索结果页时,使用Add方式附加搜索结果页:
Nav.To(NavToUrls.Search_Result, mode: NavMode.List_Add);
如此一来,当用户在搜索结果页按返回键,或者点击搜索框(等同于按返回键)时,就会在List Frame中调用Navigation Back方法,回到搜索起始页,因为此时搜索起始页一直在List Frame的历史stack中等候。
何时使用Replace_Clear这种方式呢?对于有些Scenario,有一些特殊的导航需求,主要是为了保证左右两侧窗口的上下文关系。比如店铺:

假设我们先看了店铺简介,现在左右两侧的窗口内容是有上下文关系的。此时,店铺首页在Home Frame中,店铺简介在List Frame中。我们用这个方法来显示店铺简介页:
Nav.To(NavToUrls.Shop_Brief, param: ViewModelData.ShopInfo?.ShopId, mode: NavMode.List_Replace);
现在,左右两侧的情况是:Home Frame <-> List Frame。然后用户在左侧的店铺首页上点击了一个商品,想看该商品的详情,页面就会变成这个样子:

此时左右两侧的情况是:Home Frame <-> Detail Frame。那么刚才的用于显示店铺简介的List Frame哪里去了呢?被清掉了!因为我们使用了这个方式来显示详情页:
Nav.To(data?.H5Url, mode: NavMode.Detail_Replace_Clear);
请大家注意第二个参数,使用了Detail_Replace_Clear方式,表示在Detail Frame中显示详情页,Replace该Frame中以前的内容,并且Clear掉List Frame中的所有页面。于是,店铺简介页面神奇地消失了,因为它不符合现在的上下文关系。当然,此时还需要其他一些手段来隐藏空白的List Frame,比如判断List Frame的Content是否为空。
写累了,喘口气。刚才在写博客做截图时,还发现了个Navigation的bug,顺手给fix了,是调用参数写错了,应该写成Detail_Replace_Clear,但是写成了Detail_Replace,导致现在线上的版本,在店铺页,先点击店铺简介,再在左侧点击全部宝贝,再点击任意商品,此时,随着窗口左滑,左侧是店铺简介,右侧是一个商品详情,上下文关系不对。
本篇博客只是简述了多窗口导航的原理和一些code片段,具体的实现可以根据个人应用场景的需求自己定制,尤其要注意多窗口之间的上下文关系。下次再说说页面间通信和屏幕适配吧,Continuum其实也是一种屏幕适配。
四核驱动的三维导航—淘宝新UI(设计篇)的更多相关文章
- “四核”驱动的“三维”导航 -- 淘宝新UI(需求分析篇)
前言 孔子说:"软件是对客观世界的抽象". 首先声明,这里的"三维导航"和地图没一毛钱关系,"四核驱动"和硬件也没关系,而是为了复杂的应用而 ...
- 魅族MX四核手机转让,二手淘宝上+hi-pda论坛结合使用成功已出
2013-3-14 内容存档在evernote,笔记名"魅族MX四核手机转让,二手淘宝上+hi-pda论坛结合使用成功已出"
- YY淘宝商品数据库设计
http://www.cnblogs.com/mmmjiang13/archive/2010/11/04/1868609.html 前言 这几个月都在做一个通过淘宝API线下管理淘宝店的系统,学习了很 ...
- JAVA爬虫实践(实践四:webMagic和phantomjs和淘宝爬虫)
webMagic虽然方便,但是也有它不适用的地方,比如定向的某个单页面爬虫,或者存在大量ajax请求,页面的跳转请求全都混淆在js里. 这时可以用webMagic结合phantomjs来真实模拟页面请 ...
- 淘宝(新浪)API获取IP地址位置信息
package com.parse; import java.io.BufferedReader; import java.io.DataOutputStream; import java.io.IO ...
- 基于Bootstrap仿淘宝分页控件实现
.header { cursor: pointer } p { margin: 3px 6px } th { background: lightblue; width: 20% } table { t ...
- 原生js仿淘宝手机购买选项代码
这是一款基于原生js实现仿淘宝手机信息购买选项效果源码,界面整体效果仿照淘宝购物选项设计,点击不同选项还可实时显示不同的价格计算结果,界面简洁大方.美观实用.可兼容目前最新的各类主流浏览器. 在线演示 ...
- Expression构建DataTable to Entity 映射委托 sqlserver 数据库里面金额类型为什么不建议用float,实例告诉你为什么不能。 sql server 多行数据合并成一列 C# 字符串大写转小写,小写转大写,数字保留,其他除外 从0开始用U盘制作启动盘装Windows10系统(联想R720笔记本)并永久激活方法 纯CSS打造淘宝导航菜单栏 C# Winform
Expression构建DataTable to Entity 映射委托 1 namespace Echofool.Utility.Common { 2 using System; 3 using ...
- 淘宝(阿里百川)手机客户端开发日记第十五篇 JSON解析(四)
解析一个从淘宝传递的JSON (大家如有兴趣可以测试下):{ "tae_item_detail_get_response": { "data": { " ...
随机推荐
- Notepad++正则表达式语法
\ 转义字符 如:要使用 “\” 本身, 则应该使用“\\” \t Tab制表符 注:扩展和正则表达式都支持 \r 回车符CR 注:扩展支持,正则表达式不支持 \n 换行符LF ...
- 【协议分析】Wireshark 过滤表达式实例
Wireshark 过滤表达式实例 1.wireshark基本的语法 字符 \d 0-9的数字 \D \d的补集(以所以字符为全集,下同),即所有非数字的字符 ...
- Linux IPTABLES端口转发
之前在Linux上用普通用户部署了一个Tomcat,然后将其server.xml中的端口配置为80端口,用普通用户运行就提示绑定端口失败(permission denied),google了一下,原来 ...
- 消息队列之ZeroMQ(C++)
ZMQ是什么? 这是个类似于Socket的一系列接口,他跟Socket的区别是:普通 的socket是端到端的(1:1的关系),而ZMQ却是可以N:M 的关系,人们对BSD套接字的了解较多的是点对点的 ...
- npm淘宝镜像cnpm
npm install -g cnpm --registry=https://registry.npm.taobao.org
- 【转】浅谈truncate的使用
delete 操作不会改变表的高水标记,因此如果我们对一个表插入1000万条数据,然后再回滚(对insert操作做回滚相当于相应地做delete操作),会使表的高水标记增长得很高,这时虽然我们操作的表 ...
- React生命周期
在react生命周期中,分2段执行,一个挂载的生命周期,一个是组件发生了数据变动,或者事件触发而引发的更新生命周期. 注:react生命周期很重要,对于很多组件场景的应用发挥重要作用,而且不熟悉生命周 ...
- 阅读jquery源码与js依赖加载的模块化!
阅读源码肯定是先下载有注释的源码 我也是醉了,10309 行代码,在陆续续的一个月之内,看完了,虽有收获但收获不大, 直到又一次看jquery的github,怎么会有cmd????没听过使用jquer ...
- jQuery中prop() , attr() ,css() 的区别
1. HTML属性是指页面标记中放在引号中的值,而DOM属性则是指通过JavaScript能够存取的值. (1)在jQuery中,prop()是操作DOM属性,attr()是操作HTML属性. HT ...
- js获取浏览器高度
常用: JS 获取浏览器窗口大小 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 // 获取窗口宽度 if (window.innerWidth) winWidth = ...