app在一些手机上显示在一些手机上加appstore下载不了软件出来前端怎么改

HTML5如何打开手机本地其他app,不懂原生安卓
[问题点数:26分]
HTML5如何打开手机本地其他app,不懂原生安卓
[问题点数:26分]
不显示删除回复
显示所有回复
显示星级回复
显示得分回复
只显示楼主
2013年8月 Web 开发大版内专家分月排行榜第一2010年2月 Web 开发大版内专家分月排行榜第一
2013年7月 Web 开发大版内专家分月排行榜第二2013年6月 Web 开发大版内专家分月排行榜第二
2015年7月 Web 开发大版内专家分月排行榜第三
匿名用户不能发表回复!|注册 | 登录
愿意作一名产品扫地僧。
产品经理入行宝典,12周特训,22名产品大牛全程带班,200+名企内推,100%保障就业!
推荐语:初入开发和设计的同学的福利,移动端详细的设计干货。
初涉移动端设计和开发的同学们,基本都会在尺寸问题上纠结好一阵子才能摸到头绪。我也花了很长时间才弄明白,感觉有必要写一篇足够通俗易懂的教程来帮助大家。从原理说起,理清关于尺寸的所有细节。由于是写给初学者的,所以不要嫌我啰嗦。
首先说现象,大家都知道移动端设备屏幕尺寸非常多,碎片化严重。尤其是Android,你会听到很多种分辨率:480×800, 480×854, 540×960, 720××1920,而且还有传说中的2K屏。近年来iPhone的碎片化也加剧了:640×960, 640×××2208。
不要被这些尺寸吓倒。实际上大部分的app和移动端网页,在各种尺寸的屏幕上都能正常显示。说明尺寸的问题一定有解决方法,而且有规律可循。
  要知道,屏幕是由很多像素点组成的。之前提到那么多种分辨率,都是手机屏幕的实际像素尺寸。比如480×800的屏幕,就是由800行、480列的像素点组成的。每个点发出不同颜色的光,构成我们所看到的画面。而手机屏幕的物理尺寸,和像素尺寸是不成比例的。最典型的例子,iPhone 3gs的屏幕像素是320×480,iPhone 4s的屏幕像素是640×960。刚好两倍,然而两款手机都是3.5英寸的。
所以,我们要引入最重要的一个概念:像素密度,也就是PPI(pixels per inch)。这项指标是连接数字世界与物理世界的桥梁。
  Pixels per inch,准确的说是每英寸的长度上排列的像素点数量。1英寸是一个固定长度,等于2.54厘米,大约是食指最末端那根指节的长度。像素密度越高,代表屏幕显示效果越精细。Retina屏比普通屏清晰很多,就是因为它的像素密度翻了一倍。
倍率与逻辑像素
  再用iPhone 3gs和4s来举例。假设有个邮件列表界面,我们不妨按照PC端网页设计的思维来想象。3gs上大概只能显示4-5行,4s就能显示9-10行,而且每行会变得特别宽。但两款手机其实是一样大的。如果照这种方式显示,3gs上刚刚好的效果,在4s上就会小到根本看不清字。
  在现实中,这两者效果却是一样的。这是因为Retina屏幕把2×2个像素当1个像素使用。比如原本44像素高的顶部导航栏,在Retina屏上用了88个像素的高度来显示。导致界面元素都变成2倍大小,反而和3gs效果一样了。画质却更清晰。
在以前,iOS应用的资源图片中,同一张图通常有两个尺寸。你会看到文件名有的带@2x字样,有的不带。其中不带@2x的用在普通屏上,带@2x的用在Retina屏上。只要图片准备好,iOS会自己判断用哪张,Android道理也一样。
由此可以看出,苹果以普通屏为基准,给Retina屏定义了一个2倍的倍率(iPhone 6plus除外,它达到了3倍)。实际像素除以倍率,就得到逻辑像素尺寸。只要两个屏幕逻辑像素相同,它们的显示效果就是相同的。
  Android的解决方法类似,但更复杂一些。因为Android屏幕尺寸实在太多,分辨率高低跨度非常大,不像苹果只有那么几款固定设备、固定尺寸。所以Android把各种设备的像素密度划成了好几个范围区间,给不同范围的设备定义了不同的倍率,来保证显示效果相近。像素密度概念虽然重要,但用不着我们自己算,iOS与Android都帮我们算好了。
  如图所示,像素密度在120左右的屏幕归为ldpi,160左右的归为mdpi,以此类推。这样,所有的Android屏幕都找到了自己的位置,并赋予了相应的倍率:
ldpi [0.75倍]
mdpi [1倍]
hdpi [1.5倍]
xhdpi [2倍]
xxhdpi [3倍]
xxxhdpi [4倍]
各型号iPhone的倍率比较简单,我们后面会讲到。那么Android手机那么多,具体怎么分?哪些手机是几倍的倍率呢?我们先看一张表,这是友盟2014年10月到2015年03月的数据:
  就目前市场状况而言,各种手机的分辨率可以这样粗略判断。虽然不全面,但至少在1年内都还有一定的参考意义:
ldpi 如今已绝迹,不用考虑
mdpi [320×480](市场份额不足5%,新手机不会有这种倍率,屏幕通常都特别小)
hdpi [480×800、480×854、540×960](早年的低端机,屏幕在3.5英寸档位;如今的低端机,屏幕在4.7-5.0英寸档位)
xhdpi [720×1280](早年的中端机,屏幕在4.7-5.0英寸档位;如今的中低端机,屏幕在5.0-5.5英寸档位)
xxhdpi [20](早年的高端机,如今的中高端机,屏幕通常都在5.0英寸以上)
xxxhdpi [60](极少数2K屏手机,比如Google Nexus 6)
自然地,以1倍的mdpi作为基准。像素密度更高或者更低的设备,只需乘以相应的倍率,就能得到与基准倍率近似的显示效果。
不过需要注意的是,Android设备的逻辑像素尺寸并不统一。比如两种常见的屏幕480×800和20,它们分别属于hdpi和xxhdpi。除以各自倍率1.5倍和3倍,得到逻辑像素为320×533和360×640。很显然,后者更宽更高,能显示更多内容。所以,即使有倍率的存在,各种Android设备的显示效果仍然无法做到完全一致。
不难发现,真正决定显示效果的,是逻辑像素尺寸。为此,iOS和Android平台都定义了各自的逻辑像素单位。iOS的尺寸单位为pt,Android的尺寸单位为dp。说实话,两者其实是一回事。
单位之间的换算关系随倍率变化:
1倍:1pt=1dp=1px(mdpi、iPhone 3gs)
1.5倍:1pt=1dp=1.5px(hdpi)
2倍:1pt=1dp=2px(xhdpi、iPhone 4s/5/6)
3倍:1pt=1dp=3px(xxhdpi、iPhone 6)
4倍:1pt=1dp=4px(xxxhdpi)
单位决定了我们的思考方式。在设计和开发过程中,应该尽量使用逻辑像素尺寸来思考界面。设计Android应用时,有的设计师喜欢把画布设为20,有的喜欢设成720×1280。给出的界面元素尺寸就不统一了。Android的最小点击区域尺寸是48x48dp,这就意味着在xhdpi的设备上,按钮尺寸至少是96x96px。而在xxhdpi设备上,则是144x144px。
无论画布设成多大,我们设计的是基准倍率的界面样式,而且开发人员需要的单位都是逻辑像素。所以为了保证准确高效的沟通,双方都需要以逻辑像素尺寸来描述和理解界面,无论是在标注图还是在日常沟通中。不要再说“底部标签栏的高度是96像素,我是按照xhdpi做的”这样的话了。
移动端页面的绝对单位仍然是px,至少代码里这么写,但它的道理也和app一样。由于像素密度是设备本身的固有属性,它会影响到设备中的所有应用,包括浏览器。前端技术可以善加利用设备的像素密度,只需一行代码,浏览器便会使用app的显示方式来渲染页面。根据像素密度,按相应倍率缩放。
可以通过这个测试页面http://greenzorro.github.io/demo/basic/响应式断点.html来看看你的移动设备屏幕宽度,这是逻辑像素宽度。
以iPhone 5s为例,屏幕的分辨率是640×1136,倍率是2。浏览器会认为屏幕的分辨率是320×568,仍然是基准倍率的尺寸。所以在制作页面时,只需要按照基准倍率来就行了。无论什么样的屏幕,倍率是多少,都按逻辑像素尺寸来设计和开发页面。只不过在准备资源图的时候,需要准备2倍大小的图,通过代码把它缩成1倍大小显示,才能保证清晰。
大家最关心的还是实际运用,画布该怎么设置。我们就iOS、Android、Web三个平台来分别梳理一下。不过在这之前,我要为使用PS进行设计的朋友介绍一个小技巧。
  之前我说过,我们要以逻辑像素尺寸来思考界面。体现到设计过程中,就是要把单位设置成逻辑像素。打开PS的首选项——单位与标尺界面,把尺寸和文字单位都改成点(Point)。这里的点也就是pt,无论设计iOS、Android还是Web应用,单位都用它。当然,各平台单位名称还是要记住的。这里我们用的只是它的原理,不用在意名称。
要调节倍率,则通过图像大小里的DPI来控制。这个DPI,其实就是PPI,像素密度。有个常识大家都知道,屏幕上的设计DPI设成72,印刷品设计DPI设成300。为什么是这两个数字?
首先说300,这和人眼的分辨能力有关。由于1英寸是固定长度,每1英寸有多少个像素点决定了画质清晰程度。之前说过,这就是像素密度,也就是DPI。DPI达到300以上,其细腻程度就会给人真实感,像真实世界中的物件。相反,DPI只有10的话,在你一个食指指节大小的长度内只有10个像素,这明显就是马赛克了。所以印刷品要设成300,才能保证清晰。
再说72,这有一定的历史原因。最早的图形设计是在mac电脑上进行的,mac本身的显示器分辨率就是72。PS中把图像DPI也设成72,就能保证屏幕上显示的尺寸和打印尺寸相同,便于设计。72的PC显示器分辨率逐渐成为一种默认的行业标准,这套规则就这么沿用下来。
  现在回到正题,我们怎么通过DPI来调节倍率?既然屏幕本身的分辨率是72,DPI设成72刚好是1倍尺寸,那设成72的两倍就是倍率为2的屏幕了,就这么简单。
下面来看看3个平台各自的画布设置:
iPhone的屏幕尺寸各不相同,我说的是逻辑像素尺寸,这确实是让人很头疼的事情。如果想用一套设计涵盖所有iPhone,就要选择逻辑像素折中的机型。
从市场占有率数据来看,目前最多的是iPhone5/5s的屏幕。倍率为2,逻辑像素320×568。上升势头最猛,未来有望登上第一的是iPhone 6的屏幕。倍率为2,逻辑像素375×667。
按照这两种尺寸来设计,都是比较主流的做法。可以兼顾短一些的iPhone 4s,大一点的6 plus也不会过于空旷。
不过在切图的时候要注意,由于iPhone 6 plus的3倍图是由2倍图放大而来,所以位图要注意保证清晰。
都说Android碎片化严重,但它现在反而比iOS好处理。因为如今的Android屏幕逻辑像素已经趋于统一了:360×640,就看你设成几倍了。想以xhdpi为准,就把DPI设成72×2=144。想以xxhdpi为准,就把DPI设成72×3=216。
对于那些比较老的低端机,宽度是480px的那批,画面确实会小一些,显示内容会更少。稍微留意一下,重要内容尽量保持在界面中上部分。
当然,这些机型不出一年就会被边缘化,基本淘汰。现在能运转的也是当作功能机在用,软件多了必卡无疑,用户体验无从谈起。不作考虑也是OK的。
手机端网页就没有统一标准了,比较流行的做法是按照iPhone 5的尺寸来设计。倍率2,逻辑像素320×568。
这样的做法比较实在,倍率2的屏幕无论在iOS还是Android方面都是主流,而且又是2倍屏幕中逻辑像素最小的。所以图片的尺寸可以保持在较小的水平,页面加载速度快。当然,缺点就是在倍率3的设备上看,图片不是特别清晰。
如果追求图片质量,愿意牺牲加载速度,那么可以按照最大的屏幕来设计。也就是iPhone 6 plus的尺寸,倍率3,逻辑像素414×736。
移动端的尺寸比PC端复杂,关键就在倍率。但也正因为倍率的存在,把大大小小的屏幕拉回到同一水平线,得以保证一套设计适应各种屏幕。站在这条水平线的角度看,会发现它很好理解。
作者:老夫的天
来源:简书
原文地址:http://www.jianshu.com/p/d1c6b78fe9e3
赞赏是对原创者的最大认可
收藏已收藏 | 107赞已赞 | 82
愿意作一名产品扫地僧。
产品经理群运营交流群AI产品经理群
文案交流群
Axure交流群
区块链学习群
关注微信公众号
大家都在问
10个回答17人关注
17个回答51人关注
18个回答54人关注
23个回答24人关注
42个回答144人关注
59个回答74人关注\ 经验分享
【转载】使用React重构百度新闻webapp前端
本文仅仅是对前几个月使用React重构百度新闻webapp项目的一个总结和思考,不会泄露任何项目代码(文章中的代码都是或其他开源产品的配置代码,fis3是百度开源产品),因此“伸手党”可绕行。
现在2016年8月,web前端技术这几年变化太快,因此一些信息的时效性非常重要,还是把时间写上比较好。
百度新闻的 webapp 有两个途径可以访问。第一个是用手机浏览器访问 m.baidu.com 点击搜索框下面的“新闻”链接,第二个是下载手机百度app,搜索框下面有个“新闻”链接。每天平均的PV,大概接近1亿。
也可以手机浏览器直接输入m.news.baidu.com/news或者扫描下面的二维码。本次重构代码于日上线,数字还挺吉利!
为何要重构?
重构一个项目需要很多条件的支持,但是最终的目的,是为了:第一减少维护和二次开发的成本、第二提高产品的用户体验或完善功能,两者至少要符合一个,否则没必要重构。不是为了重构而重构,为了技术而重构。
要重构一个项目,特别是一个比较复杂的项目,是需要一些条件的,否则一般都会维护现有版本的产品。比如好多公司的app、网站做的很炫很漂亮,而公司内部的erp、oa、cms等系统都用着10多年前的代码。新闻webapp虽然看似就是一个很简单的新闻列表、新闻分类、新闻内容页,但是详细分析起来还是蛮复杂的。总结起来,重构新闻webapp的条件有这么几个:
目前代码比较混乱、代码之间耦合太多,从2011年做完这一版开始,经历了好几个人维护;
框架比较老(backbone + zepto),已经落伍,使得维护人员很没有认同感;
那段时间产品经理的需求不是很多,开发人员正好有大量的时间;
以上原因中,第三个是最重要的,否则大家都每天加班很晚,谁会再去考虑重构这事儿?既然有时间,那就做吧!我就主动跟我们组长提出了这个事儿,得到他的赞同之后,我们就就开始了下面的内容。
选择靠谱的技术框架
重构的第一步就是选择一个比较靠谱的前端框架。现阶段你如果要做一个webapp,再说什么框架都不用,就用zepto.js,那就out了。这并不是为了炫耀技术或者为了用而用,选用一个靠谱的框架,真的会从设计、开发、维护这几个方面都会增加效率降低成本。
现阶段前端框架可选的有以下几个:
angular我们一开始就直接放弃了。第一,因为它自己太过于强大,什么事儿都自个干了,不利于配置和扩展;第二,它的学习成本相对于其他两个算最高的了,代码毕竟不是自己一个人写,而且写完了也不一定后期谁维护呢,学习成本尽量越低越好;第三,它都快升级2.0版本了,当时2.0没有正式发布,不是已经有beta版本,而且使用了typescript,学习成本就更高了。
下面,就到了vue和react的选择了。这两者我当时都是了解各大概,做过一些demo,但是都没有在项目中实际用过。于是我花了大概一周多的时间做了一个调研,即分别用vue和React做了一个很粗糙的、简化版的新闻webapp的demo,然后两者做了一下对比。后来没有发现两者有太多的悬殊,可能有些细节的习惯上仁者见仁,无论是使用React还是Vue都能很高效、清晰的完成既定功能,学习成本也都不高。
但是,最后还是选择了React,理由就是React生态更大。确切的说,应该是选择了React + React-router + Redux的技术框架,与之对应的是Vue + Vue-router + Vuex
做技术,框架的生态很重要。选择对了,以后的升级就顺风顺水,选择错了,就会很纠结很难受。果不其然,没过多久,手机百度的app团队就成了研究React Native的技术小组,由于我当时早早的熟悉了React,还给他们当了几次老师[偷笑]。
验证技术框架的性能问题
选择完技术框架之后,还有两个重要的问题有待于验证。
低版本android是否流畅
拿我们之前用React做的那个demo,在未经过优化的情况下,使用一些低版本的手机进行验证,结果发现浏览器运行的效果还算是流畅,最后优化之后的流畅度会好一些。但是中途遇到两个其他问题,就此记录一下。
flex兼容性问题:本来利用flex布局,结果如果要使用flex-wrap做换行的话,有些浏览器就不支持了,最典型的就是android的UC浏览器;
的兼容性问题:高级浏览器默认支持fetch了,但是低版本(如 ios6)还不支持,需要借助npm install es6-promise这个库来做兼容。
React比Vue重,如何让首屏更“轻”
用React开发webapp肯定是SPA应用,网页一加载肯定会把系统中用到的所有的js、css都加载下来,但是这样会不会导致首屏时间会很慢?带着这个疑问,我们做了一个使用fis3做异步加载的demo。demo很简单,就一个home页(列表页)、detail页、about也,很简单的一个demo,最关键的是下面的fis-conf.js的配置。
下面这个配置的意思是:根据不同的页面,打包成不同的文件。例如,针对 home页打包成一个home-third.js和home-app.js,针对about页打包成about-third.js和about-app.js……这样,访问哪个页面就动态加载相应的js,暂时访问的不到的页面,其js就先不加载。这样来提高性能。
(以下代码如果看不懂,可以先看下一节介绍fis3配置的内容,那里会有这块的解释)
fis.match('::packager', {
packager: fis.plugin('deps-pack', {
// Home router
'pkg/home-third.js': [
'/app/index.jsx:deps',
'/app/router-index/Home.jsx:deps',
'!/app/**'
'pkg/home-app.js': [
'/app/index.jsx',
'/app/router-index/Home.jsx',
'/app/router-index/Home.jsx:deps'
// Detail router
'pkg/detail-third.js': [
'/app/index.jsx:deps',
'/app/router-index/Detail.jsx:deps',
'!/app/**'
'pkg/detail-app.js': [
'/app/index.jsx',
'/app/router-index/Detail.jsx',
'/app/router-index/Detail.jsx:deps'
// About router
'pkg/about-third.js': [
'/app/index.jsx:deps',
'/app/router-index/About.jsx:deps',
'!/app/**'
'pkg/about-app.js': [
'/app/index.jsx',
'/app/router-index/About.jsx',
'/app/router-index/About.jsx:deps'
后来直到上线,这个分页面加载资源也没用上。原因如下:
配置有点复杂,针对不同router都得配置
经过压缩之后,third.js才80kb,app.js不到50kb,而且third.js一般是强缓存的,文件已经很小了,没必要做分屏加载
选择靠谱的构建工具
在公司内部做项目,当然尽量选用公司自己的框架,而百度的
那会儿已经基本成熟了,有了400+的插件,支持我们当时的React重构是问题不大了。而且,当时已经有人拿fis3做过构建React的重构,还分享了经验——
fis3 是一个很不错的构建工具,至少我们在使用过程中还比较满意。除了基本功能,它的动态假数据模拟、发布到测试机这些功能非常实用,详情请看官网文档。但是它最大的问题是生态、圈子上还没有webpack、gulp大,因此用的人少,用的人越少了生态就越小。
为项目选择打包工具,除了基本功能(打包、压缩、合并、编译less等语法糖、生成md5后缀等等),以下几点是最必须考虑的内容。
编译 React 的 .jsx格式和 ES6 语法
支持 npm 生态,支持js的模块管理
动态引用css和图片(因为要用组件化开发,组件需要的css要在组件中引用)
按需打包js
模拟假数据,运行代码
支持多种编译模式,例如dev模式下不压缩代码、方便调试,而publish模式下压缩代码、压缩资源
下面挨着说明一下,以上几点使用fis3时如何配置的,也权当帮助公司宣传一下国产前端编译神器——fis3
注意:以下所提到的fis3的配置,都要写在./fis-conf.js代码中,这是fis3的规则,可以去查阅官网的文档。另外,以下代码注释中提示要npm install ... --save-dev安装的插件,你都可以在 github.com 上找到。
编译 React 的 .jsx格式和 ES6 语法
一般情况下,编译ES6都用babel,编译jsx也有相应的工具,但是没成想这两个只需要用typescript这一插件就搞定了。速度还要快,不过编译打包,速度慢一点也没关系,不考虑这个因素。但是使用typescript确实很方便。
// 项目中所有的业务代码都放在 ./app 文件夹下面
fis.match('{/app/**.js,*.jsx}', {
// 要支持 es6 和 jsx, typescript 也能胜任,最主要是编译速度要快很多。
// 需要 npm install fis3-parser-typescript --save-dev
parser: fis.plugin('typescript'),
rExt: '.js'
支持 npm 生态,支持js的模块管理
以下配置即可是的fis3支持npm生态,并且选择使用commonjs的模块化方案。这样我们使用 npm install react --save 之后,在js代码中,就直接可以使用import * as React from 'react'了,符合目前js的主流写法。
// 采用 commonjs 模块化方案。需要 npm install fis3-hook-commonjs --save-dev
fis.hook('commonjs', {
baseUrl: './app',
extList: ['.js', '.jsx']
// fis3 中预设的是 fis-components,这里不需要,所以先关了。
fis.unhook('components');
// 使用 fis3-hook-node_modules 插件。
// 需要 npm install fis3-hook-node_modules --save-dev , 之后需要安装 npm install process --save-dev
fis.hook('node_modules');
// 设置成是模块化 js
fis.match('/{node_modules,app}/**.{js,jsx}', {
isMod: true
// 定义modile的id,即打包之后的代码中的 `defind('node_module/react/lib/index.js')`这种相对路径改为 `define('xxxxxx')` 这种ID的形式
// 这个配置是上线之后又作为优化配置上去的,会是打包的代码更小一些
fis.media('publish').match('/{node_modules,app}/**.{js,jsx}', {
moduleId: function (m, path) {
return fis.util.md5(path);
动态引用css和图片
前端现在都是组件化开发的思路,一个项目中可能需要很多css代码,但是一个组件中,就只引用它自己需要的代码,然后构建工具再将所有组件引用的css文件合并起来,一起给最终的页面——这是组件化中使用css的思路。
使用以下配置,我们可以在js文件中直接引用css和图片文件,跟webpack中使用相似。如果使用ES6语法,引用css时写import './style.css',引用图片时写 import * as url from '../img/abc.png'
fis.match('*.{js,es,es6,jsx,ts,tsx}', {
// 直接 require 'xxx.css',npm i fis3-preprocessor-js-require-css --save-dev
// 直接 require 'xxx.png'等文件,npm i fis3-preprocessor-js-require-file --save-dev
preprocessor: [
fis.plugin('js-require-file'),
fis.plugin('js-require-css')
按需打包js
因为是组件化开发,因此项目中所有的图片都是零散的放在各个组件里面的,因此最终打包之后,要将所有的图片都打包到一个统一的目录下,方便管理
fis.match('**/(*.{png,jpg,jpeg,gif})', {
release: '/static/news/webappreact/imgs/$1'
最终打包完成的时候,我们要将项目中用到的所有代码都打包成以下几个文件:
app.js 程序员手写出来的业务代码,后期的二次开发或者维护调整比较频繁,单独打包成一个文件;
third.js 第三方插件的代码,例如 React Redux 等,后期几乎不调整,单独打包成一个文件,可直接使用http强缓存,提高性能;
aio.css 所有的css文件
lib.js 直接以&script&方式写在html页面上的几个js文件,都打包成 lib.js ,减少http请求
具体配置查看如下代码,注释中写的也非常清楚了
fis.match('::packager', {
// 需要 npm install fis3-packager-deps-pack --save-dev
packager: fis.plugin('deps-pack', {
// 第一步,将 /node_module 中的依赖项,打包成 static/news/webappreact/third.js
'static/news/webappreact/third.js': [
// 将 /app/index.js 的依赖项加入队列,包含了 /app 中的依赖项 和 /node_modules 中的依赖项
'/app/index.jsx:deps',
// 移除 /app/** 只保留 /node_module 中的依赖项
'!/app/**'
// 第二步,将 /app 中的依赖项,打包成 static/news/webappreact/app.js
'static/news/webappreact/app.js': [
// 将 /app/index.jsx 加入队列
'/app/index.jsx',
// 将 /app/index/jsx 的所有依赖项加入队列,因为第一步中已经命中了 /node_module 中的所有依赖项,因此这里只打包 /app 中的依赖项
'/app/index.jsx:deps'
// ---------上面是按需打包js文件---------
// 将几个直接以&script&方式引用到 html 中的 js 文件(例如 fastclick.js、mod.js、百度统计的js等)打包成一个 lib.js ,减少http请求
// js工具包,一般单独放在 resource 文件夹下面
'static/news/webappreact/lib.js': '/resource/**.js',
// 将所有的less、css,都打包成一个css文件
// 在此打包 css,因为 fis.match('::packager' 配置的打包优先级更高
'static/news/webappreact/aio.css': '*.{less,css}'
模拟假数据,运行代码
大部分情况下,开发的代码要查看效果都是启用 fis3 server start 然后在本地浏览器打开 127.0.0.1:8080 来自测的,而此时本地是没有服务器端的接口的,例如本地页面中有一个/news?tn=gethotnews这个ajax请求(举例用,实际上根本没有 gethotnews 这个接口名称),默认会请求127.0.0.1/news?tn=gethotnews,是会返回404的。那这时候怎么办呢?
提前你要查阅fis3关于假数据模拟的
选择一,你可以为/news?tn=gethotnews这个接口准备一个静态的json文件,文档中说过了。但是新闻webapp的接口实在是太多了,为每个接口都准备一下,耗费很多工作量,而且万一接下来接口返回的数据结构有变化,还得跟着改,麻烦。因此我们选择第二种。
选择二,如果在本地访问有/news?tn=gethotnews,通过借助fis3的一些功能,能直接返回线上m.news.baidu.com/news?tn=gethotnews的数据,这样是不是就一步搞定了!下面说说该如何操作。
首先,新建一个./config/server.conf的文件,内容如下。意思是,只要发出去的网络请求的url符合^\/news.*$这个正则规则,就交给/test/data.js来处理,具体如何处理,往下看。
rewrite ^\/news.*$ /test/data.js
其次,新建一个./test/data.js的文件,内容我就不能直接粘贴了,意思就是通过nodejs来抓取线上的结果。这样就完成了动态获取线上数据的功能。
// 注意,本文件必须放在 /test 文件夹下面
module.exports = function(request, response, next) {
// 使用nodejs发起一个http请求,抓取线上地址,例如 `m.news.baidu.com/news?tn=gethotnews` 的结果
// 将结果 response.write() 返回
此外,fis-conf.js中还需如下配置,意思是./test和./config两个文件夹下的内容,打包时候要按照既定的路径打包。即 ./test/data.js这个路径,打包之后还是./test/data.js这个路径。
fis.match('/test/**', {
release: '$0'
fis.match('/config/**', {
release: '$0'
支持多种编译模式
这个需求也是我们开发中必须的。例如,我们要为上线打包文件时,需要让js有md5后缀(为了方便缓存),文件要压缩到最小;而我们要自测打包的时候,就无需md5后缀(否则一天下来产生很多冗余文件),文件不要压缩(否则无法在浏览器调试)。
fis3的文档中有介绍,我们可以使用fis.media来满足我们的需求。如下配置,使用fis.media('publish').match配置了js和css的压缩功能,而解析less的时候没有用fis.media
fis.match('*.less', {
// npm i fis-parser-less --save-dev 插件进行解析
parser: fis.plugin('less'),
rExt: '.css'
fis.media('publish').match('*.{js,jsx}', {
// fis-optimizer-uglify-js 插件进行压缩,已内置
optimizer: fis.plugin('uglify-js')
fis.media('publish').match('*.{css,less}', {
// fis-optimizer-clean-css 插件进行压缩,已内置
optimizer: fis.plugin('clean-css')
当运行fis3 release的时候,fis3只会匹配没有配置fis.media的配置项,例如解析less功能。当运行fis3 release publish的时候,fis3既会匹配fis.media('publish').match又会匹配fis.match,即less也解析了、js和css也都压缩了。
当然,你还可以自己定义很多media,例如fis.media('test')。但是不要用fis.media('dev'),因为fis3默认的media就是dev,算是个保留字。
是否使用 npm 生态
其实这里不应该是一个问题,不过当时有一个小小的纠结,就顺便在这里记录一下吧。
解决的问题
我们现在主流的开发方式,引用 React 一般都是 npm install react --save,然后在代码中直接 import * as React from 'react'来引用。这就是所谓的“npm 生态”,即使用 npm 来管理依赖。
但是当时就这个用法,出现过一个纠结,即这样依赖,我们打包的third.js文件中,会有很多define语句,都是和React相关的。因为用 npm 安装的 React 也是有好多零散的文件组成的,并不是就一个 React.js。然后,就开始担心这么多“冗余代码”会不会导致代码文件大很多,就开始想其他解决方法(其实最后根本不是问题)
最后想出来的解决方法很有意思,就是要下载一个react.min.js然后放在如./lib的一个文件夹中,然后在代码中使用import * as React from '../../lib/react.min.js'这样用。
这样是能解决很多个define的问题了,因为没必要define了,只有一个react.min.js文件,还define个什么劲?
后来,这个解决方案还是被我否决了,当时也没想出什么压倒式的理由,但是有一个原因——没人这么用!大家都在基于npm生态,社区中的写法基本已经固定了,现在却不这么写,自己独创一个写法,那样会越走越窄。哪怕会有那么一点的不完善,我也要按照大家通用的格式来,不要独创。
其实后来想了一下,按照解决方案那种使用react.min.js的方式,也是有很多问题的。例如,开发模式下也用.min.js那样就没有React自带的提示、警告功能了,万一忽略了什么性能问题,没有提示和警告,可就麻烦打了。再例如,这样一来就没有版本管理了,前端框架更新很快,版本管理很重要。
最后,我们发下经过各种压缩,最后的third.js都不到100kb,完全满足我们的要求————这个年代,真的用不着自己去创新。
系统设计(逻辑)
要降低系统设计的复杂度,前端目前最好的方式就是组件化。将系统划分成若干个页面,然后将每个页面都划分成若干个组件,还要抽象出多个页面中都会用到的通用组件,这是第一步。接下来要看组件和组件之间如何传递数据,即数据管理和状态管理该如何做。下面我们就从这两个方面来分先一下新闻webapp该如何设计。
从 router 到 page 再到 component
下图是一个最基本的设计理念,实际项目中也是按照这个来细化、扩展最后落地执行的。即,先给页面划分组件,然后组件构成页面,最后页面匹配路由。如下图:
将这个落实到页面上,就是这个效果
但是最后在开发过程中忽略了一个问题,就是一些复杂页面(例如,用浏览器模拟手机查看效果),光这种“页面 - 组件”的形式是不够的,应该在加一个subpage层,这样就扩展性更好一些了。如下图:
总结:一个项目总会遇到个别的比较复杂的页面,因此这种page - subpage - component会更加合理一些,其中的subpage在不需要的时候省略掉就是了。
智能组件 VS 木偶组件
在 React + Redux 结合作为前端框架的时候,提出了一个将组件分为“智能”和“木偶”两种
智能组件:它是数据的所有者,它拥有数据、且拥有操作数据的action,但是它不实现任何具体功能。它会将数据和操作action传递给子组件,让子组件来完成UI或者功能。这就是智能组件,也就是项目中的各个页面。
木偶组件:它就是一个工具,不拥有任何数据、及操作数据的action,给它什么数据它就显示什么数据,给它什么方法,它就调用什么方法,比较傻。这就是木偶组件,即项目中的各个组件。
因此,数据在page层获取、数据的操作和处理在page层定义,组件就是傻傻的知道执行和显示就行了,各操各的心。这种设计也整好符合目前无论是Vue、augular还是React提倡的基于数据驱动的设计理念——程序定义好Model和View的关系,剩下的业余处理只需要关心数据变化,View的变化由框架自动执行,无需像jquery时代再去手动操作DOM。
下面看一下数据在系统中是如何传递的。这里的数据分为两种:
第一种可以称之为“系统数据”,和业务无关的,一般任何系统中都会有。例如用户id、用户头像、配置信息等,这个的特点就是符合单例模式,全局共用一套
第二种可以称之为“业务数据”,每个页面都可能不一样。如在娱乐频道需要的是娱乐新闻列表,而到了军事频道就需要军事新闻的列表了,再到新闻详情页就需要新闻的内容了
针对这两种不同的数据,当然要分开处理。针对第一种“系统数据”,系统一初始化就立即获取,然后交给Redux做管理,这也符合Redux的特点。而针对第二种“业务数据”,那就什么时候用,就什么时候获取。
代码架构(物理)
使用React + Redux设计代码结构,目前方式都比较统一,基本都是按照以下方式来设计,这些在github等社区都能找到相似的结构。
// 业务代码目录,或者叫 src
// 定义 Redux 的各个 action
--components
// 定义项目中的各个组件,里面可能有很多个子文件夹
// 项目配置,无具体规定,自由发挥
--constants
// 定义 Redux 中用到的各个常量
--container
// 定义项目中的所有的页面
// 定义项目中所有数据获取、提交的方法
--reducers
// 定义 Redux 的 reducer 规则
// 定义项目中的 router 规则
// 定义 Redux 的全局 store 对象
// 工具函数,例如时间格式的处理等
`--index.jsx
// 入口,被 ../index.html 引用
// 静态资源目录,或者叫 static
// 测试用例,一般叫 test ,但是使用 fis3 时候 test 文件夹有其他用处,不得不换个名字
.eslintignore
.eslintrc.json
.gitignore
fis-conf.js
index.html
package.json
以上目录中,app/components和app/container是开发中修改最多的目录。app/container里面定义的都是页面,即智能组件,只关心数据,功能比较单一,因此结构也比较简单
app/container
Baijia.jsx
detail.jsx
imgDetail.jsx
但是针对组件app/components来说,要显示样式,当然就需要css和图片,文件类型比较多。因此,要按照如下方式定义组件
app/components
style.less
style.less
即,用一个文件夹来表示单个组件,里面的index.jsx是业务和模板代码,style.less是样式,img/文件夹放图片文件。这样的话,可以把每个组件都作为一个整体来管理,而且引用的时候也比较方便,例如import LoadMore from '../../app/components/LoadMore'就可以了——目录名即组件的名字。
虽然我没法将源码的目录结构截图出来分享给大家,但是我们实际开发中的目录结构基本是按照这个方式来做的,可能就是细节上因此会因为业务的问题做了特殊处理,但是设计理念上是一样的。
开发 - 如何多人协作开发
上文已经描述了一些基本配置和系统设计的解决方案,接下来即可进入开发。由于不是一个人做,因此必须考虑如何高效率的多人协作开发。其实这不是一个技术问题,这里就简单写一下这方面的心得体会吧。
提前定义好代码结构,统一各个文件夹的作用
提前设计Router规则,以及和页面的对应关系
提前抽象出可能在多个页面中通用的组件,创建文件夹(占位置)
讨论确定每个页面都如何拆分组件,统一设计思路
每人开发不同的页面,遇到页面单独用的组件,即自行开发;
遇到多页面公用的组件,先同步组内开发进度,有则直接用,没有则自己开发;
每装配好一个组件,都提交一次代码,随时开发、随时提交、随时合并;
心得:如果你要参与一个重构项目,你只需要按部就班发挥自己的技术能力即可,按照规则编码、测试、提交代码等。但是如果你要自己组织、规划一次系统重构,考虑的事情那就太多了。除了顶住外在的压力之外,还得考虑如何让这件事儿更快、更稳定的运行起来。
开发 - 自测
使用fis3作为构建工具,其实使用fis3 server start即可启动本机的服务,然后进行测试。但是像新闻这种产品,它的任何页面都需要获取数据再展示,因此测试的时候需要一些模拟的或者真实的数据,这个fis3也支持,在上文介绍fis3配置的时候已经说明了。
但是这种本机运行、并用fis3动态假数据模拟的情况有一个问题:它没法模拟登录的情况,http请求中也没有登录状态下的那些cookies信息,这就会影响很多功能的测试。因为新闻的许多功能是需要登录才能运行的,例如个人收藏、订阅频道、评论、点赞等。
最终想到的一个办法是将代码放在公司内部的一台测试机上,然后通过测试机访问,这样就可以获取登录信息。因此这里介绍一下如何使用fis3将代码发布到测试机上。fis-conf.js中做如下配置:
var deployConfig = {
receiver: 'http://22.47.249.11:8888/receiver.php',
// 测试机要配置一个服务,接收文件并覆盖到指定的位置
to: '/home/work/webapp-react'
fis.media('remote').match('/static/news/webappreact/**', {
deploy: fis.plugin('http-push', deployConfig)
}).match('*.{png,jpg,jpeg,gif}', {
deploy: fis.plugin('http-push', deployConfig)
}).match('*.html', {
deploy: fis.plugin('http-push', deployConfig)
配置完了之后,执行fis3 release remote,它就会执行编译,并且将编译后的文件传上去。然后再在测试机上配置一个服务,支持页面的访问即可。
开发 - 代码检查
代码检查是开发环境中非常重要的一步,其实这块的配置很简单,之所以单独列出来,就是为了体现它在开发过程中(特别是多人协作)的重要性。
项目中使用eslint做检查,其主要配置文件有两个。.eslintignore定义了忽略哪些文件的检查,例如我们要忽略一个第三方插件的代码检查
**/bdNativeShare.js
还有一个.eslintrc.json定义了代码的检查规则,本项目的检查规则相对比较宽松,配置如下。其配置项的意义,在网络上可以轻松查询到。
"browser": true,
"commonjs": true,
"es6": true
"extends": "eslint:recommended",
"parserOptions": {
"ecmaFeatures": {
"experimentalObjectRestSpread": true,
"jsx": true
"sourceType": "module"
"plugins": [
"rules": {
"indent": 0,
"linebreak-style": 0,
"quotes": 0,
"no-extra-semi": 0,
"no-unused-expressions": 0,
"no-unused-vars": 0,
"no-console": 0,
"no-mixed-spaces-and-tabs": 0,
"no-cond-assign": 0
最后,我们将检查代码的命令封装进package.json中,如下代码。这样,在检查的时候,只需要运行npm run lint这个简单命令即可
"scripts": {
"lint": "eslint --ext \".js,.jsx\" app"
目前只是软性的规定,在git commit之前必须做检查,如果开发人员忽略了,也能将代码提交上。接下来将考虑将代码检查强制做到git-hook里面,即git commit之前必须要检查通过,否则无法提交。
打包 & 提测
上文说过,自测的时候,发布的代码是未经过压缩、也未加md5后缀的,而且直接将代码发布到服务器的目录即可,无需存到指定目录。但是要打包出一个目录,然后将文件提交给测试人员,就和自测不一样了。
首先,打包的文件要压缩、要加md5后缀(上文讲述fis3的配置的时候已经说过);其次,要讲文件打包到指定目录,这里定义将文件打包到./release目录下;第三,fis3的默认release功能还会将开发环境的源文件一起打包了,这些是不需要的(仅仅需要合并出来的代码即可,合并的代码在./release/static目录下)。将以上这些需求一整合,写一个复杂的命令一起放在package.json中
"scripts": {
"publish": "rm -rf ./release && fis3 release publish -c -d ./release && rm -rf ./release/app ./release/node_modules ./release/resource"
这样,执行npm run publish即可生成一个./release文件夹,里面包含了最终的模板文件、编译之后的js和css、以及处理之后的图片文件。目录结构如下。最终,将这个文件夹提交给测试人员部署即可。每个公司都有自己的提测流程,百度内部流程这里就不说了。
测试过程中,qa可能会有反馈bug,至于如何修复bug,以及如何进行二次开发和维护,我都写了一个(仅供百度内网访问),规定了每个步骤该如何执行。
测试完了之后要上线,每个公司的上线步骤也都不尽相同,有的高级一些,有的low一些,这里就不管了。
上线之后注意如何及时快速的回滚,这一点很重要。
洋洋洒洒写了好多,最后做一个简单的总结。
系统重构的目的永远都是为了后面减少开发成本、提高系统性能和稳定性,这是公司或部门需要的结果。对于实际执行的个人来说,参与或发起重构项目,是对自己如何掌控一个产品前端设计和架构的一次很好的机会,会对自己有很大的能力提升。重构过程中会遇到一些预想不到的问题,思考在过程中解决这些问题,对自己又是另一方面的能力提升。因此,好的东西,都是双赢的。
继续压榨性能:无论是通过资源的懒加载,还是使用Immutable.js做不可变数据,都要让性能达到最优
完善一些设计不足的地方:例如目前的page - components 改为到 page - subpage - components的方式
选择React框架肯定要再试图往两个方向来攻:
服务器端渲染
React Native
原文链接:
若觉得本文不错,就分享一下吧!
作者的热门手记
请登录后,发表评论
评论加载中...
Copyright (C) 2018 imooc.com All Rights Reserved | 京ICP备 号-11}

我要回帖

更多关于 app store下载 的文章

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信