微信小程序
一:项目开始
注册账号
- 申请小程序账号
- AppID:
- 服务器域名:小程序发请求必须先配置请求的服务器域名
- 安装微信开发者工具
- 使用微信开发者工具初始化项目
注意
服务器域名:
- 域名只支持 https (request、uploadFile、downloadFile) 和 wss (connectSocket) 协议;
- 一个月内仅能修改5次
- 小程序必须使用 HTTPS 请求。小程序内会对服务器域名使用的HTTPS证书进行校验,如果校验失败,则请求不能成功发起(跳过域名校验)
二:项目构成
- app.js :
全局逻辑
- app.json:
全局配置
,包括小程序的所有页面路径、界面表现、网络超时时间、底部 tab 等 - app.wxss:
全局css
- project.config.json:
微信开发者工具配置
- page:
页面
- logs
- index
- json 后缀的 JSON 配置文件:
页面的单独配置
- wxml 后缀的 WXML 模板文件:
页面结构
- wxss 后缀的 WXSS 样式文件:
页面样式
(仅对当前页面生效) - js 后缀的 JS 脚本逻辑文件:
页面逻辑
(可通过getApp()获取全局应用实例)
- json 后缀的 JSON 配置文件:
注意:为了方便开发者减少配置项,描述页面的四个文件必须具有相同的路径与文件名
三:生命周期
前台、后台定义: 当用户点击左上角
关闭
,或者按了设备Home 键离开微信
,小程序并没有直接销毁,而是进入了后台;当再次进入微信或再次打开小程序,又会从后台进入前台。
注意:只有当小程序进入后台一定时间,或者系统资源占用过高,才会被真正的销毁
属性 | 描述 |
---|---|
onLoad(option) | 监听页面加载: componentWillMount |
onReady | 监听页面初次渲染完成 -- 结构渲染:相当于componentDidMount |
onShow | 监听页面显示 -- 前后台切换 |
onHide | 监听页面隐藏 -- 前后台切换 |
onUnload | 监听页面卸载 -- 跳转页面 |
- Page.prototype.setData:页面重新渲染
-
Page.prototype.route:页面路由
四:视图层
4.1 wxml
用于描述页面的结构
data: {
str: 'str',
num1: 1,
num2: 2,
length: 5,
arr: [
{name: 'arr1', id: 1},
{name: 'arr2', id: 2},
],
obj: {
a: 'obj1',
b: 'obj2'
}
}
4.1.1 数据绑定
{{str}}
{{obj.a}}
{{num1 + num2}}
属性
三元运算
4.1.2 列表渲染
{{index}}: {{item.name}}
{{idx}}: {{itemName.name}}
{{index}}
{{item}}
{{index}}: {{item.name}}
{{index}}: {{item.name}}
4.1.3 条件渲染
1
2
3
view1
view2
注意:
并不是一个组件,它仅仅是一个包装元素,不会在页面中做任何渲染,只接受控制属性
wx:if
vs hidden
-
hidden
:始终会渲染 -
wx:if
:可能会渲染
如果有频繁的切换,选择hidden
,否则wx:if
4.1.4 模板
{{index}}: {{msg}}
Time: {{time}}
4.1.5 引用
WXML 提供两种文件引用方式import和include
- import:引用部份
- include:引用全部
import
{{text}}
include
body
header
footer
4.2 事件
事件类型
- 冒泡事件:当一个组件上的事件被触发后,该事件会向父节点传递
- 非冒泡事件:当一个组件上的事件被触发后,该事件不会向父节点传递
事件绑定
- bind事件绑定不会阻止冒泡事件向上冒泡
- catch事件绑定可以阻止冒泡事件向上冒泡
- capture-bind事件绑定会触发捕获事件向下捕获
- capture-catch 中断捕获阶段和取消冒泡阶段
outer view
inner view
dataset
事件的参数
click me!
Page({
handleClick: function(e){
console.log(111, e)
}
})
4.3 wxs
WXS(WeiXin Script)是小程序的一套脚本语言,结合 WXML,可以构建出页面的结构
var msg = "hello world";
var fun = function(num1, num2){
var res = num1 + num2
return res.toFixed(2)
}
module.exports.message = msg;
module.exports.fun = fun;
{{m1.message}}
{{m1.fun(num1, num2)}}
4.4 wxss
WXSS 具有 CSS 大部分特性
全局wxss和page的wxss会自动引用,不需要手动导入
4.4.1 尺寸单位
- rpx(responsive pixel): 可以根据屏幕宽度进行自适应
4.4.2 样式导入
/** common.wxss **/
.small-p {
padding:5px;
}
/** app.wxss **/
import "common.wxss";
.middle-p {
padding:15px;
}
4.4.3 内联样式
五:组件
降低耦合,利于维护代码
5.1 创建组件
page
// page json
{
"component": true,
"usingComponents": {
"comtext": "path/to/the/custom/component"
}
}
引用组件的路径写 相对路径
引用组件的属性名采用连写
component
{{innerText}}
标签用于显示子节点
/* component wxss */
.inner {
color: red;
}
注意:在组件wxss中不应使用ID选择器、属性选择器和标签名选择器(尝试后可以用标签名选择器,但建议用class选择器)
// component js
Component({
properties: {
// 这里定义了innerText属性,属性值可以在组件使用时指定
innerText: {
type: String,
value: 'default value',
}
},
data: {
// 这里是一些组件内部数据
someData: {}
},
ready: function(){
console.log(this, 'this')
},
methods: {
// 这里是一个自定义方法
customMethod: function(){}
}
})
properties
的属性名采用驼峰
5.2 事件
page与component之间的事件
page
我是component的子节点
Page({
parentEvent: function(e){
console.log('parentEvent', e.detail)
}
})
component
{{innerText}}
Component({
properties: {
// 这里定义了innerText属性,属性值可以在组件使用时指定
innerText: {
type: String,
value: 'default value',
}
},
data: {
// 这里是一些组件内部数据
someData: {}
},
methods: {
// 这里是一个自定义方法
childEvent: function (e) {
console.log('childEvent')
var myEventDetail = {
data: 1
} // detail对象,提供给事件监听函数
var myEventOption = {} // 触发事件的选项
this.triggerEvent('parentEvent', myEventDetail, myEventOption)
}
}
})
5.3 behaviors
抽离共用的组件js代码
behaviors 是用于 组件间 代码 共享 的特性,类似于一些编程语言中的
mixins
或traits
behavior
// my-behavior.js
module.exports = Behavior({
behaviors: [],
properties: {
myBehaviorProperty: {
type: String
}
},
data: {
myBehaviorData: {}
},
attached: function(){},
methods: {
myBehaviorMethod: function(){}
}
})
component
// my-component.js
var myBehavior = require('my-behavior')
Component({
behaviors: [myBehavior],
properties: {
myProperty: {
type: String
}
},
data: {
myData: {}
},
attached: function(){},
methods: {
myMethod: function(){}
}
})
5.4 组件间关系
注意:必须在 两个组件 定义中都加入relations定义,否则不会生效
page
item 1
item 2
custom-ul
// custom-ul js
Component({
relations: {
'../custom-li/custom-li': {
type: 'child', // 关联的目标节点应为子节点
linked: function (target) {
console.log(target, 'ul-linked')
},
linkChanged: function (target) {
console.log(target, 'ul-linkChanged')
},
unlinked: function (target) {
console.log(target, 'ul-unlinked')
}
}
},
methods: {
_getAllLi: function () {
// 使用getRelationNodes可以获得nodes数组,包含所有已关联的custom-li,且是有序的
var nodes = this.getRelationNodes('../custom-li/custom-li')
console.log(nodes, 'nodes-before')
nodes[0].setData({
name: 2
}, () => {
console.log(nodes, 'nodes-after')
})
}
},
ready: function () {
this._getAllLi()
}
})
custom-li
{{name}}
// custom-li js
Component({
data: {
name: 1
},
relations: {
'../custom-ul/custom-ul': {
type: 'parent', // 关联的目标节点应为父节点
linked: function (target) {
console.log(target, 'li-linked')
},
linkChanged: function (target) {
console.log(target, 'li-linked')
},
unlinked: function (target) {
console.log(target, 'li-linked')
}
}
}
})
六:请求
这是一个demo
const url = "https://cnodejs.org/api/v1"
const fetch = function (method = 'get', uri, data = {}, success = () => {}){
wx.request({
method,
url: `${url}/${uri}`,
data,
header: {
'content-type': 'application/json'
},
success
})
}
module.exports = {
url,
fetch
}
{{index}} - {{item.title}}
.del{
text-decoration: line-through;
}
const { fetch } = require('../../config/api.js')
Page({
data: {
category: []
},
onLoad: function (options) {
this.getList()
},
getList: function(){
fetch('get', '/topics', {}, res => {
const val = res.data.map(v => {
let obj = v
obj.del = false
return obj
})
this.setData({
category: val
})
})
},
handleTap: function(e){
const id = e.currentTarget.id
const index = this.data.category.findIndex(v => v.id == id)
let category = this.data.category
category[index].del = !category[index].del
this.setData({
category
})
}
})