小程序注册流程
1、注册方法
在微信公众平台官网首页(mp.weixin.qq.com)点击右上角的“立即注册”按钮。
2、选择注册的帐号类型
选择“小程序”,点击“查看类型区别”可查看不同类型帐号的区别和优势。
3、填写邮箱和密码
请填写未注册过公众平台、开放平台、企业号、未绑定个人号的邮箱。
4、激活邮箱
登录邮箱,查收激活邮件,点击激活链接。
5、填写主体信息
点击激活链接后,继续下一步的注册流程。请选择主体类型选择,完善主体信息和管理员信息。
选择主体类型:
填写主体信息并选择验证方式
企业类型帐号可选择两种主体验证方式。
- 方式一:支付验证
需要用公司的对公账户向腾讯公司打款来验证主体身份,打款信息在提交主体信息后可以查看到。
请根据页面提示,向指定的收款帐号汇入指定金额。
温馨提示:请在10天内完成汇款,否则将注册失败。
- 方式二:微信认证
通过微信认证验证主体身份,需支付300元认证费。认证通过前,小程序部分功能暂无法使用。
填写管理员信息
微信小程序开发基础
小程序目录结构
根目录下有两个文件夹,分别命名为pages和utis
根目录下还有4个全局文件,其中,,3个是应用程序的配置文件, 1个是工程配置文件。
在开发小程序时会遇到4种类型的文件:
以js为后缀的文件是核心的逻辑代码文件;
以.json为后缀的文件通常用来存储配置信息;
以.wxml为后缀的文件用来编写页面结构;
以.wxss为后缀的文件是样式表文件,用来进行页面渲染样式的设置。
project.config.json配置文件用来对工程进行全局配置,如工程名称、目录路径、AppID等。
project.config.json配置文件可进行配置的常用字段下图所示。
.setting选项可以配置的字段如下图所示。
compileType字段可选的字符串值如下图所示。
app.js文件是当前应用程序的入口文件,阅读此文件的代码可以发现,其中只调用了一个App ()函数。
App ()函数的作用是注册小程序,并且会接收一个Object作为参数,其中会定义小程序的生命周期回调。
需要注意的是,App ()函数必须在app.js文件中进行调用,并且只能调用一次。
App ()函数中传入的Object参数可以指定的回调函数如下图所示。
app.json文件用来对小程序进行全局配置,其决定页面文件的路径、窗口表现等,可配置项如下图所示。
窗口配置字段window对象的可配置属性如下图所示。
tabBar字段的可配置属性
关于标签栏的list属性,其中可以定义一组标签,标签数量需要大于1个且小于6个。每个标签可配置的属性如下图所示。
networkTimeout字段配置网络超时时间可以配置的属性。
注意:所有超时时间的配置单位都为ms。app.wxss用来定义一些全局的样式表,样式表的定义与Css语法基本一致,后面会详细介绍。
除上面比较重要的几个文件外,模板工程中还生成了一个命名为pages的文件夹,该文件夹中又包含index和logs两个文件夹。
pages文件夹用来存放页面文件,其中每个文件夹都是一个页面,如index文件夹存放的是示例程序的主页面相关代码。
在微信小程序中,每个页面都由JS,JSON,WXML和WXSS这4种类型的文件共同定义。
箭头函数
箭头函数 是在es6 中添加的一种规范
x => x * x 相当于 function(x){return x*x}
箭头函数相当于 匿名函数, 简化了函数的定义。 语言的发展都是倾向于简洁 对人类友好的, 减轻工作量的。
x => {
if (x>0){
return x*x
}else{
return x
}
}
如果有多个参数就要用():
// 两个参数返回后面的值
(x, y) =>x*y + y*y
//没有参数
() => 999
// 可变参数
(x, y, ...rest) =>{
var i,sum = x+y;
for (i=0;i<rest.length;i++){
sum += rest[i];
}
return sum;
}
如果要返回一个单对象, 就要注意, 如果是单表达式, 上面一种会报错, 要下面这种:
// 这样写会出错
x => {foo:x} // 这和函数体{}有冲突
// 写成这种
x => {{foo:x}}
箭头函数中this 指向
箭头函数 看起来是匿名函数的简写。但是还是有不一样的地方。 箭头函数中的this是词法作用域, 由上写文确定。
var obj = {
birth: 1990,
getAge: function () {
var b = this.birth; // 1990
var fn = function () {
return new Date().getFullYear() - this.birth; // this指向window或undefined
};
return fn();
}
};
箭头函数修复了this的指向, this 总是指向词法作用域, 也就是外层调用者obj;
var obj = {
birth: 1990,
getAge: function () {
var b = this.birth; // 1990
var fn = () => new Date().getFullYear() - this.birth; // this指向obj对象
return fn();
}
};
obj.getAge(); // 25
如果使用箭头函数,以前的那种hack写法 就不需要了:
var that = this;
由于this 在箭头函数中已经按照词法作用域绑定了, 所以施一公call 或者apply() 调用函数的时候, 无法对this 进行绑定, 即 传入的第一个参数被忽略:
var obj={
birth:2018,
getAge:function(year){
var b =this.birth;//2018
var fn = (y)=>y-this.birth //this.birth 仍然是2018
return fn.call({birth:200},year)
}
}
obj.getAge(2020)
下面对比写es5 es6 直接关于箭头函数的对比使用
//es5
var fn = function(a, b){return a+b}
//es6 直接被return时候可以省略函数体的括号
const fn=(a,b) => a+b;
//es5
var foo = function(){
var a=20;
var b= 30;
return a+b;
}
//es6
const foo=()=>{
const a= 20;
const b=30;
return a+b
}
// 注意这里 箭头函数可以替代函数表达式但是不能替代函数声明
再回到this 上面来,箭头函数样意义上面来说没有this. 如果使用了this 那么就一定是外层this .不会自动指向window对象。所以也就不能使用call/apply/bind来改变this指向
var person = {
name: 'tom',
getName: function() {
return this.name;
}
}
使用es6 来重构上面的对象
const person = {
name:'tom',
getName:()=>this.name
}
这样编译的结果就是
var person ={
name:'tom',
getName:function getName(){return undefined.name}
}
在ES6中,会默认采用严格模式,因此this也不会自动指向window对象了,而箭头函数本身并没有this,因此this就只能是undefined,这一点,在使用的时候,一定要慎重慎重再慎重,不然踩了坑你都不知道自己错在哪!这种情况,如果你还想用this,就不要用使用箭头函数的写法。
// 可以稍做改动
const person = {
name: 'tom',
getName: function() {
return setTimeout(() => this.name, 1000);
}
}
// 编译之后变成
var person = {
name: 'tom',
getName: function getName() {
var _this = this; // 使用了我们在es5时常用的方式保存this引用
return setTimeout(function () {
return _this.name;
}, 1000);
}
};
为了更好的理解exports和module.exports 的关系,我们先来补点 js 基础。代码如下:
// index.js
Page({
onLoad: function(){
var a = {name: '张三'};
var b = a;
console.log(a);
console.log(b);
b.name = '李四';
console.log(a);
console.log(b);
var b = {name: '王五'};
console.log(a);
console.log(b);
}
})
运行结果:
{ name: '张三' }
{ name: '张三' }
{ name: '李四' }
{ name: '李四' }
{ name: '李四' }
{ name: '王五' }
解释一下:
a 是一个对象,b 是对 a 的引用,即 a 和 b 指向同一个对象,即 a 和 b 指向同一块内存地址,所以前两个输出一样。
当对 b 作修改时,即 a 和 b 指向同一块内存地址的内容发生了改变,所以 a 也会体现出来,所以第三四个输出一样。
当对 b 完全覆盖时,b 就指向了一块新的内存地址(并没有对原先的内存块作修改),a 还是指向原来的内存块,即 a 和 b 不再指向同一块内存,也就是说此时 a 和 b 已毫无关系,所以最后两个输出不一样。
明白了上述例子后,我们进入正题。我们只需知道三点即可知道exports和module.exports的区别了:
- exports是指向的module.exports 的引用;
- module.exports初始值为一个空对象{},所以exports初始值也是{};
- require() 返回的是module.exports 而不是exports。
所以我们通过:
var name = '张三';
exports.name = name;
exports.sayName = function() {
console.log(name);
}
给exports赋值其实是给module.exports这个空对象添加了两个属性而已,上面的代码相当于:
var name = '张三';
module.exports.name = name;
module.exports.sayName = function() {
console.log(name);
}
下面就在微信小程序中module.exports和exports的区别做出示例
// common.js
function sayHello(name) {
console.log(`Hello ${name} !`);
}
function sayGoodbye(name) {
console.log(`Goodbye ${name} !`);
}
// 第一种情况,module.exports初始值为空对象,两个函数使用module.exports或exports都一样效果
module.exports.sayHello = sayHello;
module.exports.sayGoodbye = sayGoodbye;
exports.sayHello = sayHello;
exports.sayGoodbye = sayGoodbye;
// 第二种情况,module.exports初始值不为空对象,只能使用module.exports暴露接口,而不能使用exports暴露,会出现is not a function错误。
module.exports = {name:1};//module.exports给一个初始值
//以下两个正常使用
module.exports.sayHello = sayHello;
module.exports.sayGoodbye = sayGoodbye;
//使用以下两个会报错误sayHello is not a function
exports.sayHello = sayHello;
exports.sayGoodbye = sayGoodbye;
综上所述,当module.exports 指向新的对象时,exports断开了与 module.exports 的引用,module.exports 指向了新的内存块,而exports还是指向原来的内存块。
因此,在不是很清楚两者关系的时候,请采用module.exports来暴露接口,而尽量不采用exports暴露接口。
模块化
可以将一些公共的代码抽离成为一个单独的 js 文件,作为一个模块。
模块只有通过 module.exports 或者 exports 才能对外暴露接口。
注意:
exports 是 module.exports 的一个引用,因此在模块里边随意更改 exports 的指向会造成未知的错误。所以更推荐开发者采用 module.exports 来暴露模块接口,除非你已经清晰知道这两者的关系。
小程序目前不支持直接引入 node_modules , 开发者需要使用到 node_modules 时候建议拷贝出相关的代码到小程序的目录中,或者使用小程序支持的 npm 功能。
例:
在通用类common.js中写两个公用方法
// common.js
function sayHello(name) {
console.log(`Hello ${name} !`)
}
function sayGoodbye(name) {
console.log(`Goodbye ${name} !`)
}
module.exports.sayHello = sayHello
exports.sayGoodbye = sayGoodbye
在需要使用这些模块的文件中,使用 require 将公共代码引入
var common = require('common.js')
Page({
helloMINA: function() {
common.sayHello('MINA')
},
goodbyeMINA: function() {
common.sayGoodbye('MINA')
}
})
JS的作用域
作用域其实就是作用范围。JS的作用域主要是说变量的作用范围。
JS的作用域从大类分的话是两种:
-
局部作用域:在局部作用域声明的变量叫局部变量。它的作用是局部的,在函数里声明的变量,只能函数内部可以访问,在块作用域声明的变量,只能在块里访问。局部变量是私有的,外部是访问不了的。局部作用域又可以分为函数作用域和块作用域。
-
全局作用域: 在全局作用域声明的变量叫全局变量。它的作用是全局的,网页里所有的脚本和函数都能访问它。
不同函数中可以使用相同的变量名。
注意:函数的参数也属于局部变量。
文件作用域
在 JavaScript 文件中声明的变量和函数只在该文件中有效;不同的文件中可以声明相同名字的变量和函数,不会互相影响。
通过全局函数 getApp 可以获取全局的应用实例,如果需要全局的数据可以在 App() 中设置。
如:在全局类app.js中定义一个参数
// app.js
App({
globalData: 1
})
a.js
// a.js
//localValue只能在a.js文件中使用
var localValue = 'a'
// 获取app的实例
var app = getApp()
// 获取全局数据并更改它
app.globalData++
b.js
// b.js
// 你可以在文件b.js中重新定义localValue,而不会干扰a.js中的localValue
var localValue = 'b'
// 如果a.js在b.js之前运行,现在globalData应该是2
console.log(getApp().globalData)
块作用域
在JS中,代码可以放到{}里,我们称为代码块。一个{}就是一个块。
我们声明变量,之前一直用关键词var。用var声明的变量是没有块作用域的。即使在块里声明了变量,外部也是可以访问到的。比如:
{
var a = 10;
}
alert(a);//输出10
声明变量
声明变量的关键词有三个:var、let、const。
它们三个有什么区别呢?后面细讲它们三个的区别。
- const 定义常量的
- let: 作用和var类似, 有作用域的概念
- var 特点:没有作用域
我们可以通过 let、const 关键词声明拥有块作用域的变量。这样,我们在块里声明的变量,外部是访问不到的。比如:
{
let a = 10;
const b = 20;
}
alert(a);//此处会报错 a is not defined
alert(b);//此处会报错 b is not defined
变量的生命周期
全局变量在声明时被创建,在关闭页面时被删除。
局部变量在函数调用时创建,在函数完成后被删除。
自动全局
如果给一个没有声明的变量赋值,这个变量会成为全局变量,即使变量是在函数里赋值的。比如:4
<p id="demo"></p>
<script>
function test() {
a = "hello";
}
test();
document.getElementById("demo").innerHTML = a; //输出hello
</script>
网页中,全局作用域是window,所有的全局变量都属于window对象。比如:
<p id="demo"></p>
<script>
var a = "hello";
document.getElementById("demo").innerHTML = window.a; //输出hello
</script>
注意:我们应该尽量避免使用全局变量。
因为window对象有一套自己的属性和方法。你的全局变量或函数能够覆盖 window 自带的变量或函数。window 自带的变量或函数也会覆盖你的全局变量和函数。这样,就容易引起冲突。比如:
var name = 10;
console.log(typeof name);//输出string
我们声明的全局变量name赋值一个数值10,它的数据类型应该是number才对,为什么会是string呢?
这是因为window对象有一个自带的name属性,它的类型是字符串。你声明的全部变量名和window自带的属性名冲突了。
要想知道window自带的属性和方法有哪些,我们可以在浏览器的开发者模式里的Console标签里输入window按回车,就会输出window所有的属性和方法。如下图:
window.onload必须等到页面内包括图片的所有元素加载完毕后才能执行。
在Jquery中$ (function(){ })和 $ (document).ready(function(){ })的效果是一样,是在DOM树加载完成之后(DOM树加载完不代表全部资源加载完,例如图片,音频和视频等还没加载)就会执行。所以$ (document).ready(function(){ })是比window.onload要先执行的。
微信小程序 生命周期详解
通俗的讲,生命周期就是指一个对象的生老病死。 从软件的角度来看,生命周期指程序从创建、到开始、暂停、唤起、停止、卸载的过程。
下面从一下三个方面介绍微信小程序的生命周期:
- 应用生命周期
- 页面生命周期
- 应用生命周期影响页面生命周期
应用生命周期
- 用户首次打开小程序,触发 onLaunch(全局只触发一次)。
- 小程序初始化完成后,触发onShow方法,监听小程序显示。
- 小程序从前台进入后台,触发 onHide方法。
- 小程序从后台进入前台显示,触发 onShow方法。
- 小程序后台运行一定时间,或系统资源占用过高,会被销毁。
前台、后台定义: 当用户点击左上角关闭,或者按了设备 Home 键离开微信,小程序并没有直接销毁,而是进入了后台;当再次进入微信或再次打开小程序,又会从后台进入前台。
在整理本文资料的时候,有点不解,为什么不把小程序监听『销毁』方法开放给开发者,我猜测是因为IOS系统限制『按下Home键时,app从活动状态转入后台,会被挂起』;微信也不例外,只要运行一段时间或把微信客户端进程杀掉,就无法通知小程序应用被销毁。
页面生命周期
- 小程序注册完成后,加载页面,触发onLoad方法。
- 页面载入后触发onShow方法,显示页面。
- 首次显示页面,会触发onReady方法,渲染页面元素和样式,一个页面只会调用一次。
- 当小程序后台运行或跳转到其他页面时,触发onHide方法。
- 当小程序有后台进入到前台运行或重新进入页面时,触发onShow方法。
- 当使用重定向方法wx.redirectTo(OBJECT)或关闭当前页返回上一页wx.navigateBack(),触发onUnload
应用生命周期影响页面生命周期
- 小程序初始化完成后,页面首次加载触发onLoad,只会触发一次。
- 当小程序进入到后台,先执行页面onHide方法再执行应用onHide方法。
- 当小程序从后台进入到前台,先执行应用onShow方法再执行页面onShow方法。