当前位置: 首页 > Web前端 > HTML5

移动H5多页面开发敲门砖经验

时间:2023-04-05 19:41:58 HTML5

两年前才接触移动开发,一开始也是一头雾水。每次遇到问题,我都会去社区提问或者借鉴前人的经验。感谢分享开发者为前端社区带来欣欣向荣的活力。本文结合之前写的文章和开发经验分享给大家,希望对刚踏入移动开发的新人有所帮助。下面将以其中一个公积金页面开发项目为例,介绍移动端的一些常见问题以及使用Vuejs做lib进行多页面开发的经验。移动端自适应布局项目中最常用的移动端自适应布局方案是flexbox结合rem。标准的列样式使用flexbox,其他大部分不规则视图使用rem。rem最常用的方案是淘宝开源的可扩展布局方案。根据设备像素比设置scale的值(scale=1/deviceRatio),让viewportdevice-width始终等于设备的物理像素,然后根据屏幕动态计算根字体大小size,具体把屏幕分成100等份,每份为a,1rem等于10a。Annotation通常我们会得到一个750宽的设计稿,它是基于iPhone6的物理分辨率。有的设计师可能比较懒,设计图上没有标注。如果边开发边测尺寸,效率无疑是比较低的。要么让设计师标注,要么自己做。如果设计师实在没时间,建议使用markman进行标注。免费版阉割了部分功能(比如不能保存到本地),但基本能满足我们的需求。后来发现PxCook,比markman更好用的标注工具,可以在PSD设计图中显示图层的样式代码,对于前端来说极其方便。注解完成后,我们开始写我们的样式。使用淘宝的lib-flexible库后,我们的根字体基准值为750/100*10=75px。这时候如果一个标签距离图中100px,那么在css中应该设置为100/75=1.333333rem。所以为了提高开发效率,可以使用px转rem插件。下面是sublimeText和Vscode的转换插件:px转rem插件SublimeText插件:rem-unitVScode插件:cssrem使用rem的一些要点在所有的单位中,推荐使用px转font-size,然后结合mediaquery来控制重要节点,可以满足高亮或弱化某些字体的需要,而不是整体调整。公共方向的所有单位可以使用px,水平单位可以使用rem,因为移动设备的宽度是有限的,高度可以无限向下滑动。但也有特殊情况。比如一些活动报名页面,需要一屏完整展示,没有下拉。此时,rem应该作为所有公共或水平方向的单位。如图:左侧窗体的高度单位底部间距更大,使用px在不同屏幕上显示更方便;而右边的活动报名页面不能有滚动条,所有的公共高度、外边距、内边距都应该使用rem。border、box-shadow、border-radius等一些效果要以px为单位。手机状态栏和浏览器导航栏的影响在之前发表的文章中,有个顺丰前端小伙伴提出的问题:作者强调布局完全覆盖,解决方法到底部和许多缝隙是不同的。我在工作中遇到过这种情况。设计师设计稿的宽度是750×1334,但是实际显示高度没有那么多,因为顶部有导航栏和手机自带状态栏的显示,所以整体高度达不到750,但是设计师的设计稿是严格按照750设计的。这种情况下,如果使用rem,严格按照设计师的尺寸还原,屏幕会出现滚动条。你如何处理这种情况?是根据设计稿的规范,还是从开发上有相应的措施?还是以我的分享界面为例:显示高度的差异通常出现在微信和浏览器之间,因为前者没有地址栏和工具栏,所以显示高度通常会低一些。它符合设计师设计的视图。那么如果使用纯padding的话,即使margin都是rem,在浏览器端还是会超过一屏的高度,这对于分享页面来说并不是我们希望看到的。这个时候,我们就得做一个取舍。主要区域我使用绝对定位,这样虽然上层空隙很小,但仍然可以显示在一个屏幕高度。如果设置中使用了边距填充,则必须出现滚动条。当然,这样的前提还要看设计图。通常,设计师为了空间感会留有一定的空隙,不会将主要物件的高度设置的过高,否则会显得过于饱满,不好看。如果设计图的宽高不在一定范围之内,超出是在所难免的。但是我们的分享界面一般都是通过微信分享给好友的。通过浏览器打开的视图中的滚动条其实影响不大,不是吗?下面附上微信和浏览器的效果图:微信:浏览器:使用Vuejs作为lib开发手机页面。为什么不使用SPA模式?一般移动端数据交互频繁,开发速度快的页面使用vue。为什么不使用它?单页SPA开发模型有几个原因。项目其他成员为了快速开发上线,对SPA和webpack并不熟悉。参与项目时,项目使用了多页面开发,短时间内无法重构。除了使用单页面架构,在开发多页面应用时,一个页面交互逻辑和一个Vue实例是对应的。基于接口返回数据的属性注入“基于接口返回数据的属性注入”是个人创造的一个词组。抛开这个概念,我们先来说说表单数据的绑定方法。表单数据绑定的一个重点是,如果有多个表单,则分离出几个表单对象进行数据绑定。上图中的公积金查询就是一个例子。由于不同城市查询要素不同,登录方式可能只有一种,也可能有多种。比如上图中有三种登录方式,使用vue布局时有两种选择。1.只创建一个表单进行数据绑定,点击按钮触发判断2.有几种登录方式,创建多个表单,用一个字段标识当前显示的表单。由于使用了第三方接口,所以首先没有接口。回到数据结构来看,采用的是第一种错误的方式。第一个错误是每个登录方式下的登录元素个数也不一样。第二个错误是数据绑定在同一个表单数据下。当用户使用用户名登录,输入用户名和密码后,切换到客户账户登录方式,会出现数据混乱。解决布局问题后,我们需要根据设计图定义一些状态,比如当前登录方式的切换,授权状态的切换,按钮是否可以点击,是否处于请求状态.当然还有一些通过app传递的数据,这里先忽略。data:{tags:{arr:[''],activeIndex:0},isAgreeProxy:true,isLoading:false}然后查看接口返回的数据。推荐使用chrome插件postman。例如呼和浩特的登录元素如下:{"code":2005,"data":[{"name":"login_type","label":"身份证号","fields":[{"name":"user_name","label":"身份证号码","type":"text"},{"name":"user_pass","label":"password","type":"password"}],"value":"1"},{"name":"login_type","label":"公积金账户","fields":[{"name":"user_name","label":"公积金账户","type":"text"},{"name":"user_pass","label":"密码","type":"password"}],"value":"0"}],"message":"请求登录元素成功"}可以看到呼和浩特有两种授权登录方式,我们定义一个data中的loginWays,一开始是一个空数组,然后在methods中定义了一个请求接口的函数,根据返回的数据向上面的fields对象中注入一个input字段进行绑定。这就是所谓的基于接口返回数据的属性注入方法:{queryloginWays:function(channel_type,channel_code){varparams=newURLSearchParams();params.append('channel_type',channel_type);params.append('channel_code',channel_code);axios.post(this.loginParamsProxy,params).then(function(res){console.log(res);varcode=res.code||res.data.code;varmsg=res.message||res.data.message;varloginWays=res.data.data?res.data.data:res.data;//查询失败if(code!=2005){alert(msg);return;}//添加输入字符段使用于v-模型绑定loginWays.forEach(function(loginWay){loginWay.fields.forEach(function(field){field.input='';})})this.loginWays=loginWays;this.tags.arr=loginWays.map(function(loginWay){returnloginWay.label;})}.bind(this))}}即使返回的数据中包含我们不需要的数据也没关系,这样我们就不会losealltheinformationfornextlogin需要的数据多表单绑定数据的问题解决了,那么如何在页面之间传递数据呢?如果是从app传来的,一般是使用url拼接,使用window.location.search获取queryString然后拦截;如果通过页面插入到javaWeb中,可以直接使用"${fieldname}"获取,注意js中获取java字段需要加双引号。computed:{//真实姓名realName:function(){returnthis.getQueryVariable('name')||''},//身份证明identity:function(){returnparseInt(this.getQueryVariable('identity'))||''},/*IfjavaWebrealName:function(){returnthis.getQueryVariable('name')||''},identity:function(){returnparseInt(this.getQueryVariable('identity'))||''}*/},方法:{getQueryVariable:function(variable){varquery=window.location.search.substring(1);varvars=query.split('&');for(vari=0;i