微信小程序是一种全新的连接用户与服务的方式,它可以在微信内被便捷地获取和传播,同时具有出色的使用体验。提倡把渲染和逻辑分离。简单来说就是不要再让 JS 直接操控 DOM,JS 只需要管理状态即可,然后再通过一种模板语法来描述状态和界面结构的关系即可。
微信小程序的相关文件类型:
一、.wxml 后缀的 WXML 模板文件,是框架设计的一套标签语言,结合基础组件、事件系统,可以构建出页面的结构。内部主要是微信自己定义的一套组件。
二、.wxss 后缀的 WXSS 样式文件。
三、.js 后缀的 JS 脚本逻辑文件
四、.json 后缀的 JSON 配置文件,小程序设置,如页面注册,页面标题及tabBar。
JSON 配置
我们可以看到在项目的根目录有一个 app.json 和 project.config.json,此外在 pages/logs 目录下还有一个 logs.json,我们依次来说明一下它们的用途。
小程序配置 app.json
app.json 是当前小程序的全局配置,包括了小程序的所有页面路径、界面表现、网络超时时间、底部 tab 等。QuickStart 项目里边的 app.json 配置内容如下:
{ "pages": ["pages/index/index", "pages/logs/logs"], "window": { "backgroundTextStyle": "light", "navigationBarBackgroundColor": "#fff", "navigationBarTitleText": "WeChat", "navigationBarTextStyle": "black" }}pages字段 —— 用于描述当前小程序所有页面路径,这是为了让微信客户端知道当前你的小程序页面定义在哪个目录。
window字段 —— 定义小程序所有页面的顶部背景颜色,文字颜色定义等。
工具配置 project.config.json
大家在使用一个工具的时候,都会针对各自喜好做一些个性化配置,例如界面颜色、编译配置等等,当你换了另外一台电脑重新安装工具的时候,就不需要重新配置
页面配置 page.json
可能你小程序里边的每个页面都有不一样的色调来区分不同功能模块,因此我们提供了 page.json
小程序的启动
小程序启动之后,在 app.js 定义的 App 实例的 onLaunch 回调会被执行: 只执行一次
App({ onLaunch() { // 小程序启动之后 触发 }})整个小程序只有一个 App 实例,是全部页面共享的。
Page({ data: { // 参与页面渲染的数据 logs: [] }, onLoad() { // 页面渲染后 执行 }})Page 是一个页面构造器,这个构造器就生成了一个页面。在生成页面的时候,小程序框架会把 data 数据和 index.wxml 一起渲染出最终的结构,于是就得到了你看到的小程序的样子。
在渲染完界面之后,页面实例就会收到一个 onLoad 的回调,你可以在这个回调处理你的逻辑。
mvvm模式,提倡渲染和逻辑分离,js只需管理状态
封装微信小程序的数据请求:
一、将所有的接口放在统一的js文件中并导出
二、在app.js中创建封装请求数据的方法
三、在子页面中调用封装的方法请求数据
参数传值的方法:
一、给HTML元素添加data-*属性来传递我们需要的值,然后通过e.currentTarget.dataset或onload的param参数获取。但data-名称不能有大写字母和不可以存放对象
二、设置id 的方法标识来传值通过e.currentTarget.id获取设置的id的值,然后通过设置全局对象的方式来传递数值
三、在navigator中添加参数传值
wx.navigateTo({ url: '../play/index?id='+ dataset.id }) console.log(dataset.id); }onLoad:function (param) { //页面初始化 this.setData({ currentId:param.id })}提高微信小程序的应用速度:
一、不要频繁使用setdata,传递大量新数据,后台态页面进行 setData
二、优化图片资源,减少使用大图片资源
三、代码包大小的优化
劣势:
代码包限制,不能打开超过5个层级的页面、托于微信,无法开发后台管理功能
微信小程序与H5的区别:
运行环境的不同,传统的HTML5的运行环境是浏览器,包括webview,而微信小程序的运行环境并非完整的浏览器,是微信开发团队基于浏览器内核完全重构的一个内置解析器,针对小程序专门做了优化
获取系统级权限的不同,系统级权限都可以和微信小程序无缝衔接
小程序关联微信公众号如何确定用户的唯一性:
使用wx.getUserInfo方法withCredentials为 true 时 可获取encryptedData,里面有 union_id。后端需要进行对称解密
框架
逻辑层
小程序开发框架的逻辑层由 JavaScript 编写,增加 App 和 Page 方法,进行程序和页面的注册。
增加 getApp 和 getCurrentPages 方法,分别用来获取 App 实例和当前页面栈。
提供丰富的 API,如微信用户数据,扫一扫,支付等微信特有能力。
每个页面有独立的作用域,并提供模块化能力。
由于框架并非运行在浏览器中,所以 JavaScript 在 web 中一些能力都无法使用,如 document,window 等。
开发者写的所有代码最终将会打包成一份 JavaScript,并在小程序启动的时候运行,直到小程序销毁。类似 ServiceWorker,所以逻辑层也称之为 App Service。
核心===响应数据绑定系统
为了减少配置项,四个文件必须具有相同的文件名
生命周期:
onLaunchFunction生命周期函数–监听小程序初始化当小程序初始化完成时,会触发 onLaunch(全局只触发一次)
onLoad: 页面加载
一个页面只会调用一次,可以在 onLoad 中获取打开当前页面所调用的 query 参数。
onShow: 页面显示
每次打开页面都会调用一次。
onReady: 页面初次渲染完成
一个页面只会调用一次,代表页面已经准备妥当,可以和视图层进行交互。
对界面的设置如wx.setNavigationBarTitle请在onReady之后设置。详见生命周期
onHide: 页面隐藏
当navigateTo或底部tab切换时调用。
onUnload: 页面卸载
当redirectTo或navigateBack的时候调用。
onload 页面加载完成, onreay监听页面初次渲染完成
小程序与vuejs区别:
直接修改 this.data 而不调用 this.setData 是无法改变页面的状态的,还会造成数据不一致。
单次设置的数据不能超过1024kB,请尽量避免一次设置过多的数据
重点内容
1. wx.navigateTo(OBJECT)保留当前页面,跳转到应用内的某个页面,使用wx.navigateBack可以返回到原页面。
2. wx.redirectTo(OBJECT)关闭当前页面,跳转到应用内的某个页面。
3. wx.reLaunch(OBJECT)关闭所有页面,打开到应用内的某个页面。
4. wx.switchTab(OBJECT)跳转到 tabBar 页面,并关闭其他所有非 tabBar 页面
5. wx.navigateBack(OBJECT)关闭当前页面,返回上一页面或多级页面。可通过 getCurrentPages()) 获取当前的页面栈,决定需要返回几层。
模块化
exports 是 module.exports 的一个引用,因此在模块里边随意更改 exports 的指向会造成未知的错误。所以更推荐开发者采用 module.exports 来暴露模块接口,除非你已经清晰知道这两者的关系。
小程序目前不支持直接引入 node_modules , 开发者需要使用到 node_modules 时候建议拷贝出相关的代码到小程序的目录中。
require 暂时不支持绝对路径
使用 wx:for-item 可以指定数组当前元素的变量名,
使用 wx:for-index 可以指定数组当前下标的变量名
block wx:for
类似 block wx:if,也可以将 wx:for 用在标签上,以渲染一个包含多节点的结构块。例如:
block wx:for="{{[1, 2, 3]}}" view {{index}}: /view view {{item}} /view/blockwx:key
如果列表中项目的位置会动态改变或者有新的项目添加到列表中,并且希望列表中的项目保持自己的特征和状态(如 中的输入内容,
wx:key 的值以两种形式提供
字符串,代表在 for 循环的 array 中 item 的某个 property,该 property 的值需要是列表中唯一的字符串或数字,且不能动态改变。
保留关键字 *this 代表在 for 循环中的 item 本身,这种表示需要 item 本身是一个唯一的字符串或者数字,如:
当数据改变触发渲染层重新渲染的时候,会校正带有 key 的组件,框架会确保他们被重新排序,而不是重新创建,以确保使组件保持自身的状态,并且提高列表渲染时的效率。
如不提供 wx:key,会报一个 warning, 如果明确知道该列表是静态,或者不必关注其顺序,可以选择忽略。
wx:if vs hidden
因为 wx:if 之中的模板也可能包含数据绑定,所有当 wx:if 的条件值切换时,框架有一个局部渲染的过程,因为它会确保条件块在切换时销毁或重新渲染。
同时 wx:if 也是惰性的,如果在初始渲染条件为 false,框架什么也不做,在条件第一次变成真的时候才开始局部渲染。
相比之下,hidden 就简单的多,组件始终会被渲染,只是简单的控制显示与隐藏。
一般来说,wx:if 有更高的切换消耗而 hidden 有更高的初始渲染消耗。因此,如果需要频繁切换的情景下,用 hidden 更好,如果在运行时条件不大可能改变则 wx:if 较好。
定义模板
使用 name 属性,作为模板的名字。然后在内定义代码片段,如:
template name="msgItem" view text {{index}}: {{msg}} /text text Time: {{time}} /text /view/template使用模板
使用 is 属性,声明需要的使用的模板,然后将模板所需要的 data 传入,如:
template is="msgItem" data="{{...item}}"/Page({ data: { item: { index: 0, msg: 'this is a template', time: '2016-09-15' } }})事件分为冒泡事件和非冒泡事件:
冒泡事件:当一个组件上的事件被触发后,该事件会向父节点传递。
非冒泡事件:当一个组件上的事件被触发后,该事件不会向父节点传递。
非冒泡事件,如的submit事件,的input事件,的scroll事件
事件绑定与冒泡:
bind事件绑定不会阻止冒泡事件向上冒泡,catch事件绑定可以阻止冒泡事件向上冒泡。
WXS了解
WXS(WeiXin Script)是小程序的一套脚本语言,结合 WXML,可以构建出页面的结构。
注意
wxs 不依赖于运行时的基础库版本,可以在所有版本的小程序中运行。
wxs 与 javascript 是不同的语言,有自己的语法,并不和 javascript 一致。
wxs 的运行环境和其他 javascript 代码是隔离的,wxs 中不能调用其他 javascript 文件中定义的函数,也不能调用小程序提供的API。
wxs 函数不能作为组件的事件回调。
由于运行环境的差异,在 iOS 设备上小程序内的 wxs 会比 javascript 代码快 2 ~ 20 倍。在 android 设备上二者运行效率无差异。
WXSS
全局样式与局部样式
定义在 app.wxss 中的样式为全局样式,作用于每一个页面。在 page 的 wxss 文件中定义的样式为局部样式,只作用在对应的页面,并会覆盖 app.wxss 中相同的选择器。
##API##
框架提供丰富的微信原生API,可以方便的调起微信提供的能力,如获取用户信息,本地存储,支付功能等
小程序开发常见问题整理如下
如何获取扫码进来的参数
可以在app.js的生命周期参数如onLaunch(option)的option.query来获取
如参数为myscene,则通过option.query.myscene获取。
微信小程序textarea的内容随着屏幕上下移动的问题
当我们对textarea所在区域设置position为fixed的时候,我们在textarea中输入文字后滚动页面,会发现textarea位置不变,但是textarea中的内容却随着滚动而移动。
解决方法:设置textarea fixed="true"即可
数据双向绑定运用到class中的小细节
怎么获取用户输入
var inputContent = {}Page({
data: {
inputContent: {}
},
bindBlur: function(e) {
inputContent[e.currentTarget.id] = e.detail.value
}
})
为什么脚本内不能使用window等对象
页面的脚本逻辑是在JsCore中运行,JsCore是一个没有窗口对象的环境,所以不能在脚本中使用window,也无法在脚本中操作组件
为什么 zepto/jquery 无法使用
zepto/jquery 会使用到window对象和document对象,所以无法使用。
一个应用同时只能打开5个页面,当已经打开了5个页面之后,wx.navigateTo不能正常打开新页面。请避免多层级的交互方式,或者使用wx.redirectTo
样式表不支持级联选择器
background-image:可以使用网络图片,或者 base64,或者使用标签
不同页面传值方式
通过URL进行传值,在另一个页面可通过options拿到
通过app.js传值,可通过app.函数名.方法名获取
把一个页面的值写在缓存里面,在另外一个页面调取,官方提供10M的本地缓存
后面加Sync的为同步缓存,不加的为异步缓存。
如果对同一个控件同时添加wx:if和wx:for,是不能正常起作用的。修改代码,在图片列表控件外添加一个view布局,来单独控制其显示隐藏。修改后代码如下:
view wx:if="{{item.isShow}}" block class="imglist" wx:for="{{item.piclists}}" image class='image-view' src="{{item.pic}}"/image /block/view微信实现不同分享按钮分享不同内容
onshareAppMessage
其中options参数中有两个参数from和target,from用来区分分享的来源,确定是按钮分享还是右上角分享,target参数则是按钮分享的触发控件。
如何去掉自定义button灰色的圆角边框
解决方式:通过设置button的伪元素样式进行去除: button::after{ display: none;}
如何获取自定义属性
view bindtap="bintap" data-id="1"/viewbintap:function(e){ var id = e.currentTarget.dataset.id;}快速创建页面的方式
在app.json文件下pages数组里,添加一个页面的路径,如果这个路径指向的是一个不存在的文件,那么MINA框架会自动创建这个页面的四个文件。我们可以试一下,在app.json文件的pages数组里添加一项 “pages/demo/demo”,然后保存项目。
EventEmitter检测内存泄漏问题。
全局变量:全局变量直接挂在 root 对象上,不会被清除掉
闭包:闭包会引用到父级函数中的变量,如果闭包未释放,就会导致内存泄漏。上面例子是 inner 直接挂在了 root 上,那么每次执行 out 函数所产生的 bigData 都不会释放,从而导致内存泄漏。
表单元素都是原生组件,微信小程序中原生组件层级最高,所以在用input,canvas,map这些组件就要注意了,就比如说,下面填写备注是一个input标签,然后点击优惠券弹出一个选择使用优惠券的浮层就会出现下面这种情况,input里的value会在浮层上面的,要解决这一问题还是很简单的,在小程序中input有个placeholder-class属性,我们只要写一个类,规定它的z-index:1只要比浮层权重低就行了,然后使用placeholder-class属性绑定这个类就行了,
还有input标签无法设置 font-family;这些大家都要主意,对input直接float:left也是不行的,要在input外面套view,然后对其进行浮动。
开发过程中背景图片如果是在本地,真机调制预览是不显示的,display:flex,在ios会中存在一些问题。
A B2个页面a跳转到B 。然后b选择后关闭 如何给A里面的变量赋值
在B的js文件里面做处理:
在B的js文件里面做处理给A里面的变量赋值
var pages = getCurrentPages(); //得到所有的页面
var prevPage = pages[pages.length - 2];//上一个页面。
//给上一个页面的变量赋值
prevPage.setData({
account: card_number
})
可自动刷新页面状态 + 关闭页面再次进入 是采用onshow的方式;为了监控关闭采用onhide
轮播图最后一张如何与第一张衔接
swiper indicator-dots="true" indicator-color="指示点颜色" indicator-active-color="当前选中指示点颜色" interval="自动切换时间间隔" duration="滑动动画时长" autoplay="true" vertical="false(是否改为纵向)" block wx:for="{{imgUrls}}" image src="{{item}}" class="slide-image" width="355" height="150"/ /swiper-item /block/swiper在swiper标签中加上一句 circular=“true” 就神奇般的好了
微信小程序自定义弹框滚动与页面滚动冲突问题
scroll-view class="scanInvoice_content" height="100%" scroll-y="{{isScroll}}" //设置Page的overflow-y属性值为hidden/scroll-view如果自定义弹框不涉及滚动,则直接在自定义弹框最外层盒子加上 catchtouchmove=‘true’ 即可。
input标签既有bindblur/bindinput事件,input使用bindinput存储输入的值时,手指将光标前移再删除,光标自动跑到最后 ——输入和获取焦点只处理了后边的X号显示隐藏, 而失去焦点去存储值
提交表单时如果后端需要formId,则前端需要使用form
获取用户token,并对外暴露,每次使用直接调用即可
var config = require("../config")function getAuthKey() { var that = this; return new Promise(function (resolve, reject) { // 调用登录接口 // TODO if if (wx.getStorageSync("token") != '') { var token = wx.getStorageSync("token"); var uid = wx.getStorageSync("uid"); //token失效,更新token wx.request({ url: config.accountUrl + "/account/wx/getToken?uid=" + uid + "&token=" + token + "&type=" +10, data: {}, header: { 'content-type': 'application/x-www-form-urlencoded' }, method: 'post', success: function (res) { if (res.data.code == '0000') { resolve(wx.getStorageSync("token")); //只要是0000就无需更新token,否则重新获取 } else { resolve(getToken()) } }, fail: function(res) { resolve(getToken()) } }) } else { resolve(getToken()) } })} /*获取token*/function getToken() { var that = this; return new Promise(function (resolve, reject) { wx.login({ success: function (res) { wx.request({ url: config.wxserviceUrl + '/api/jscode2session', data: { code: res.code, appid: "wx9630dd9447e885d2", }, method: 'post', success: function (res) { var openid = res.data.openid var session_3rd = res.data.session_3rd; var unionid = res.data.unionid; //获取用户信息 if (res.data.openid) { wx.request({ url: config.accountUrl + '/account/littleApp/weChatLogin', data: { openid: openid, unionid: unionid, session_3rd: session_3rd, appid: "wx9630dd9447e885d2" //此处需根据后端需要的值传递 }, method: 'post', header: { 'content-type': 'application/x-www-form-urlencoded' // 默认值 }, success: function (res) { if (res.data.code == "0000") { var token = res.data.data.token; wx.setStorageSync("token", token); wx.setStorageSync("uid", res.data.data.uid); resolve(token); } } }) } else { reject('error'); } } }) } }) })}













