如果一个元素的宽和高分别设置成340rpx和100%(在iphone6下就是750rpx),而雪糕图片的素材原始高度分别为600px和750px。
在现实的项目中,我们经常需要面对原始图片的尺寸和设计图里的尺寸不一样的情况(尤其是原始图片高度是未知和不固定的情况,比如动态从网络获取图片)。在这种情况下,我们必须要有所舍弃,或放弃等比例,或者裁剪掉图片的一部分。接受不完美,这也是编程中很重要的心态,如和选择,需要看业务上的需求。
小程序的image组件提供了4种缩放模式和9种裁剪模式,来支持我们的选择。
小程序页面设计的框架结构MINA(MVVM)
整个系统分为两块:视图层(View)和逻辑层(AppService)。MINA可以让数据与视图保持同步非常简单。当做数据修改的时候,只需要在逻辑层修改数据,视图层就会做相应的更新。(通过this.setData进行同步数据)
什么是页面的生命周期?如同人的成长需要分为出生、童年、青年、中年、老年一样,一个页面从创建到卸载,同样会经历以下5个周期:
MINA框架分别提供了5个生命周期函数来监听这个5个特定的生命周期,以方便开发人员可以在这些特定的时刻执行一些自己的代码逻辑,它们分别是:
可以在Page()方法中去演示这些页面的生命周期
Page({data:{},onLoad:function(options){console.log('onLoad:页面被加载')},onShow:function(){console.log('onShow函数被加载')},onReady:function(){console.log('onReady函数被加载')},onHide:function(){console.log('onHide函数被加载')},onUnload:function(){console.log('onUnload函数被加载')}})onHide和onUnload这两个函数需要执行一些API操作,比如页面执行tab栏切换页面、navigateTo方法、或者使用小程序切换后台的按钮时会执行onHide函数;当页面执行redirectTo或navigateBack的时候会执行onUnload函数。
当然我们还可以添加任意的数据和函数到这个Page方法的Object参数中,在页面的函数中用this就可以访问这些自定义的数据或者函数
以下内容你不需要立马完全弄明白,不过以后它会有帮助。
生命周期
通过以上图解可知
小程序借鉴了比如像Angular、vue这些流行框架的思想,采用数据绑定的机制来做数据的初始化和更新,不同于像Angular和Vue的双向数据绑定,小程序仅实现了单向数据绑定,即支持从逻辑层传递到视图层的数据绑定,反之则不行。
小程序使用Page方法参数里的data变量作为数据绑定的桥梁,写在data里的数据,被称为数据绑定的初始化数据。
数据的绑定有以下两种:
当页面执行了onShow函数后,逻辑层会收到一个通知(Notify),随后逻辑层会将data对象以json的形式发动到view视图层(SendInitialData),视图层接收到初始化数据后,开始第一次渲染,显示初始化数据(FirstRender),最终将数据呈现在开发者的眼前。
说明:如果数据绑定是作用在组件的属性中,比如
通过AppData面板来查看和调试数据绑定变量,AppData下的数据以页面为组织单位,更改这里的某一项数据的值,都是实时进行更新的。
可以通过setData函数来做数据绑定,这种方法可以理解为“数据更新”。setData方法位于Page对象的原型链上:Page.prototype.setData。大多数情况下,我们使用this.setData的方式来调用这个方法。
setData的参数接受一个对象,以key和value的形式将this.data中的key对应的值设置成value。
上面的话要注意两点:
this.setData所绑定或者更新的数据,并不要求在this.data中已预先定义。
Page({data:{},onLoad:function(){varobjData={obj:{text:"hello"},name:"小明"}this.setData({pageData:objData})}})
wx:for-item="item"指定数组当前子元素的变量名,我们将元素的变量名指定为item,当然这个变量名可以更改。
如果不定义item数组子元素的变量名,依然是可以正常显示的,原因是小程序默认子元素的变量名就是item。
wx:for-index="idx"指定当前元素在数组中索引号的变量名,我们命名为idx。
wx:for并不是一定要作用在block标签上的,也可以作用在view组件上,一样可以照常运行,但是并不推荐使用view等组件来做列表渲染,因为我们希望标签或者组件元素是语义明确的,view组件通常被用来当做视图容器或者是区域的分隔,它有它的使命,不应该滥用。
要从一个页面跳转到另外一个页面,需要使用事件来响应点击某个动作。
什么是事件?
事件定义:事件是视图层(wxml)到逻辑层的通讯方式。简单理解:事件可以让我们在js里处理一些用户在界面上的一些操作,并对这些操作做出反馈。比如:点击一个按钮,从一个页面跳转到另外一个页面,在这个过程中,需要在js里调用MINA框架的API,使从一个页面跳转到另外一个页面。
想要实现页面跳转的这个机制,需要做两件事情
冒泡事件是指某个组件上的事件被触发后,事件还会向父级元素传递,一直到页面的顶级元素。
非冒泡事件则不会向父级元素传递事件。
bind和catch的区别
bind不会阻止事件的传播,而catch会阻止事件继续向父节点传播。
小程序提供了5个导航API,从而帮助开发者实现页面的跳转
wx.navigateTo和wx.redirectTo的区别
tapHandle:function(){wx.navigateTo({url:'../main/mainname=小明',})//wx.redirectTo({//url:'../footer/footer',//})},onUnload:function(){console.log("pageisunload")},onHide:function(event){console.log("pageishide")}使用wx.redirectTo实现跳转,将打印输出pageisunload,但是不会输出pageishide,跳转到的页面没有返回按钮,无法返回到之前的页面了。
使用wx.navigateTo实现跳转,将打印输出pageishide,但是不输出pageisunload,页面左上角出现一个可以返回到之前页面的按钮。
所以总结出wx.redirectTo是将关闭当前页面并将页面卸载,无法返回到之前的页面,而wx.navigateTo仅仅是隐藏当前页面,还可以再次返回到之前的被隐藏的页面。
再来考虑一个问题,当wx.navigateTo从一个页面跳转到另外一个页面后(从A页面跳转到B页面),再从B页面返回到A页面时,B页面会执行onHide还是onUnload呢?答案是执行B页面的onUnload函数,也就是说当从子页面返回到父页面时,子页面会被卸载。因为这样设计就不会造成大量的子页面残留在小程序中了。(早期的小程序是不会卸载的,后来在版本更新的时候更改的。)
当我们使用wx.navigateTo从父页面跳转到子页面后,就形成了2个页面层级,可以继续在子页面里使用wx.navigateTo跳转到子页面。
但是小程序强制规定,只允许有最多5层父子页面,事实上,太多的页面将严重影响用户的产品体验,建议页面最多不要超过3层。
wx.redirectTo不存在这个问题,因为当跳转到另外一个页面上后,上一个页面被强制卸载掉了。
如果所有的数据都写在js文件中,这样会污染了我们的业务层,我们应该把这些数据分离到一个单独的js文件中,
在项目的根目录下新建一个文件夹,命名为data,然后再data目录下新建一个js文件,命名为data.js。
//data.jsvarpostList=[{date:'1111',title:'hahha'}]然后将之前js文件中data里面的数据剪切到data.js中。所以我们提取出来的数据文件data.js可以看做是小程序的一个模块。同时我们需要在data.js中使用module.exports向外部暴露一个接口
//data.jsvarpostList=[{data:'1111',title:'hahha'}]module.exports={postList:postList}然后在其他js文件中引用这个data.js模块,
//其它js文件vardataObj=require('../data/data.js')Page({data:{},onLoad:funciton(){this.setData({postList:dataObj.postList})}})使用require引用js模块时,要注意以下几点:
我们通常可以将一些公共的、经常使用的业务逻辑提取成一个公共的函数,当在多个地方需要使用函数时,只需要要调用这个函数即可。
事实上,有一句话是这么描述软件开发的:编程世界里遇到的绝大多数问题都可以用封装的思想来解决。
//post.wxml//使用import来引用模板
模板的好处是它可以让多个调用方来调用,不可能要求每个调用方都使用同样的变量名来调用模板,这种由定义方要求调用方遵守变量名命名的做法是不合理的。
要解决这个问题,就必须消除template对于外部变量名的依赖,可以使用拓展运算符"…"展开传入对象变量来消除这个问题。
//post-item-tpl.wxml
template标签仅仅只是一个占位符,在编译后,会被template的模板内容替换,所以在template标签上注册事件是无效的。同理,也不能在block上注册事件,因为block也会在编译后消失。
解决的办法就是在template标签的外部增加一个view组件,将template包裹起来,并将事件注册在view组件上。
所以在这里就涉及到页面之前的参数传递与通信了,通过使用页面导航url的query参数传递,就能够实现页面之间的参数传递。
小程序提供了wx.setNvigationBarTitle()来动态设置导航栏标题,这个方法无论是在onLoad或者onShow函数中调用,都可以成功的设置导航栏标题,但是建议在onReady函数中设置此方法,因为onReady在onShow发生之后才触发,onShow将标题设置完毕后,onReady会重新渲染页面,并覆盖导航栏的标题。
wx.previewImage只能预览位于网络中的图片,无法预览本地的图片。
以上事件都属于非冒泡事件
input输入值都是在事件对应的响应函数中使用event.detail.value
给页面的容器加上-webkit-overflow-scrolling:touch;css属性
animation.scale(2,2).rotate(45).step().translate.step()以上是两个动画组,它们之间使用step()作为分隔,每个动画组中的动画方法执行顺序是:同一组中的动画方法会同时执行,但动画组必须是先后执行。也就是说一组动画先执行完成后,后面的动画组中的动画才能执行。
可不可以在不同的动画组中设置不同的动画效果参数答案是可以的。每个step方法都可以接受一个obiect对象:可以传入一个跟wx.createAnimation()一样的配管.参数,用于指定当前组动画的配置。
step接受动画配置
//创建一个动画实例,
varanimation=wx.createAnimation(!timingFunction:'ease-in-out
//设置动画组(以step()分隔),每个队列,
animation.scale(2,2).rotate(45).step().translate(30).step((duration:1000)
小程序提供了6类动画方法:
实现一个页面的刷新需要三步
小程序提供一个wx.getUserInfo()方法来获取用户信息,用户信息分为用户基本信息和用户openIdUnionId。基本信息是明文的,而openId和unionid是加密数据。这两种类型的数据都由wx.getUserInfo()方法返回。
如果要开发真实的项目,一定要考虑各种调用失败的情况,并加强安全性。
openid是用户对于当前小程序的身份标识。
code是一把钥匙,是得到openid和session_key的关键。code的有效期只有5分钟,如果在5分钟之内还没有用code换取openid和session_key,那么就不能在使用了。
code是一把钥匙,是得到openid和session_key的关键,code有效期只有5分钟,如果在5分钟之内还没有用code换取openid和session_key,那么就不能再使用了。
session_key肯定是有失效期的,在session_key有效期内,开发者最好不要重复调用wx.login接口,不断用code换取session_key,而应该将session_key保存在服务器中,等到session_key失效后,再重新获取新的session_key。
怎么检查session_key是否失效了呢?小程序提供了wx.checkSession();来校验session_key是否失效,只有在session_key确认失效后,才能再次调用wx.login。
wx.login得到的code只能使用一次,一旦你使用code换取了openid和session_key,这个code就马上失效,不能再次使用。当然如果5分钟内这个code还没有使用,那么也会失效。
在实际的项目中,将openid和session_key返回到客户端是非常危险的,也完全没有必要。因为需要使用openid和session_key的场景都会被放到服务器进行的,所以返回到小程序中没有任何意义,反而会增加数据的泄露风险。
调用wx.getUserInfo接口拿到了用户的明文基本信息数据和用户加条新据,并使用了明文数据。下面回顾一下wx.getUserInfo返回的数据:
,我们使用了userlnfo对象,包括userInfo和rawData在内的明文数据。都可能存在被篡改的风险。如何知道明文数据是否被篡改了呢
这个时候rawData和singature就可以发挥作用了.rawData和signature用于校验用户数据到底有被篡改过(没有绝对安全的网络,据极有可能被抓包或者通过其他万式.通常来说,想要实现这个校验必在服务器编码才能进行。这需要小程序将获取的rawData和signature一并提交到服务器,由服务器完成校验工作。
校验的基本原理是:rawData是用户原始明文数据,signature是使用shal(rawData+sessionkey)得到的字符串。理论上讲,如果数据没有被篡改,那么signature等于shal(rawData+sessionkey);如果rawData或者signature被修改了,那么signature必然不再等于shal(rawData.+sessionkey).
是否存在signature和rawData同时被修改的情况呢理论上是不可能的,因为sessionkey并不在网络上传输,篡改者不知道这个变量,被篡改且校验通过的概率很小。
有可能从signature中sessionkey论E,这是不可能的。因为shal算法是不可逆的,无法在已知rawDatasignature的情况下推算出sessionkev,不知道sessionkey就无法通过同时修改rawData和signature达到“欺骗校验的目的”。如果知道了sessionkey,只需要修改rawData并重新用sessionkey计算一下新的shal(rawData+sessionkev)就又可以让新的rawData等于新的shal(rawData+sessionkey)了。这样,开发者就无法知道rawData是被修改过的。
这也是为什么官方文档一再强调,不要在网络上传输sessionkev,而应该将其保存在服务器上使用,以降低sessionkey被泄露的风险。