微信小程序之前,是使用weixin-sdk进行开发,调用视频,摄像头等。
微信小程序weixin up端,所以PC端的window这些没有,运行环境是IOS,安卓等,有一些特殊的调用录音功能,摄像头等
申请账号:开发账号+开发工具
小程序根目录下的 app.json 文件用来对微信小程序进行全局配置。
页面配置高于全局配置。页面配置和全局配置相同时,页面配置会覆盖全局配置
分为应用的生命周期、页面的生命周期、组件的生命周期
App({
/**
* 当小程序初始化完成时,会触发 onLaunch(全局只触发一次)
*/
onLaunch: function () {
console.log('onLaunch --- app')
},
/**
* 当小程序启动,或从后台进入前台显示,会触发 onShow
*/
onShow: function (options) {
console.log('onShow --- app')
},
/**
* 当小程序从前台进入后台,会触发 onHide
*/
onHide: function () {
console.log('onHide --- app')
}
})
onLoad()页面首次加载,可接受一个参数
Page({
/**
* 生命周期函数--监听页面加载
*/
onLoad: function (options) {
console.log('onLoad --- page')
},
/**
* 生命周期函数--监听页面初次渲染完成
*/
onReady: function () {
console.log('onReady --- page')
},
/**
* 生命周期函数--监听页面显示
*/
onShow: function () {
console.log('onShow --- page')
},
/**
* 生命周期函数--监听页面隐藏
*/
onHide: function () {
console.log('onHide --- page')
},
/**
* 生命周期函数--监听页面卸载
*/
onUnload: function () {
console.log('onUnload --- page')
}
})
组件移动,拖拽等
组件所在页面的生命周期(当小程序进入后台,后台进入前台进行操作时,调整屏幕尺寸等),如再次进入前台时,列表页数据展示的刷新,就是根据组件内页面的生命周期完成
Component({
// 组件的生命周期
lifetimes: {
// 在组件实例刚刚被创建时执行
created: function () {
console.log('created --- component')
},
// 在组件实例进入页面节点树时执行
attached: function () {
console.log('attached --- component')
},
// 在组件在视图层布局完成后执行
ready: function () {
console.log('ready --- component')
},
// 在组件实例被移动到节点树另一个位置时执行
moved: function () {
console.log('moved --- component')
},
// 在组件实例被从页面节点树移除时执行
detached: function () {
console.log('detached --- component')
}
},
// 组件所在页面的生命周期
pageLifetimes: {
// 组件所在的页面被展示时执行
show: function () {
console.log('show --- component')
},
// 组件所在的页面被隐藏时执行
hide: function () {
console.log('hide --- component')
},
// 组件所在的页面尺寸变化时执行
resize: function () {
console.log('resize --- component')
}
}
})
页面路由:在小程序中所有页面的路由全部由框架进行管理。
框架以栈的形式维护了当前的所有页面。 当发生路由切换的时候,可以使用 getCurrentPages()
函数获取当前页面栈。
重加载:一般不用,小程序打开或者页面刷新时
测试:
使用wx.navigateTo()从index跳转到logs页面:
使用wx.redirectTo()跳转
navigateTo
, redirectTo
只能打开非 tabBar 页面。switchTab
只能打开 tabBar 页面。reLaunch
可以打开任意页面。onLoad
中获取。API接口可以直接使用的方法:App(),Page(),Component()以及组件中的全局接口wx.navigateTo()等方法
数组中第一个元素为首页,最后一个元素为当前页面。
如订单支付后返回上级或者返回多级,即可通过getCurrentPages()获取当前页面栈信息。或替换成另一个页面
可以通过 this.pageRouter
或 this.router
获得当前页面或自定义组件的路由器对象。
页面路由器有 switchTab
reLaunch
redirectTo
navigateTo
navigateBack
五个方法,与 wx 对象向同名的五个方法 switchTab reLaunch redirectTo navigateTo navigateBack 功能相同
this
指代的页面或自定义组件。this.pageRouter
获得的路由器对象具有更好的基路径稳定性。通常情况下,使用 this.pageRouter.navigateTo
代替 wx.navigateTo
是更优的。this.pageRouter.navigateTo
跳转后的新路径是相对路径,相对于当前this页面this.pageRouter
和 this.router
在页面中将获得同样的页面路由器对象。但如果在自定义组件中调用, this.pageRouter
将相对于自定义组件所在的页面来进行路由跳转,而 this.router
相对于自定义组件自身的路径。
相对比较复杂,页面中如果需要使用到监听等特殊用法也需要使用Component()
导出:
module.exports 或者 exports,exports
是 module.exports 的一个引用,随意更改 exports
的指向会造成未知的错误。所以更推荐开发者采用 module.exports
来暴露模块接口
module.exports.sayHello = sayHello
exports.sayGoodbye = sayGoodbye
小程序目前不支持直接引入 node_modules,
使用到 node_modules
时候建议拷贝出相关的代码到小程序的目录中,或者使用小程序支持的 npm 功能。
使用:
使用这些模块的文件中,使用 require
将公共代码引入
var common = require('common.js')
简单绑定: {{ message }}
属性中绑定:
控制属性: wx:if="condition"
关键字:
可以进行表达式计算、算术运算
可以对对象和数组中的变量和数据进行组合
{{item}}
Page({
data: {
zero: 0
}
})
属性后面有空格会解析成空白字符串
{{item}}
等同于
{{item}}
wx:if wx:elif wx:else,一般用在
wx:if
和 hidden区别【-
wx:if
之中的模板也可能包含数据绑定,所以当 wx:if
的条件值切换时,框架有一个局部渲染的过程,因为它会确保条件块在切换时销毁或重新渲染。wx:if
也是惰性的,如果在初始渲染条件为 false
,框架什么也不做,在条件第一次变成真的时候才开始局部渲染。hidden
就简单的多,组件始终会被渲染,只是简单的控制显示与隐藏(display属性none和block)。wx:if
有更高的切换消耗而 hidden
有更高的初始渲染消耗。因此,如果需要频繁切换的情景下,用 hidden
更好,如果在运行时条件不大可能改变则 wx:if
较好。默认数组的当前项的下标变量名默认为 index
,数组当前项的变量名默认为 item(不需要重新声明)
使用 wx:for-item
可以指定数组当前元素的变量名,
使用 wx:for-index
可以指定数组当前下标的变量名:
{{index}}: {{item.message}}
如果是对象遍历的item和index分别是key和value
block wx:for使用block标签包裹
wx:key唯一值指定列表中项目的唯一的标识符。
wx:for
的值为字符串时,会将字符串解析成字符串数组
wx:for="array"
等同于
wx:for="{{['a','r','r','a','y']}}
使用 name 属性,作为模板的名字。然后在内定义代码片段
{{index}}: {{msg}}
Time: {{time}}
当前页面可直接使用,如果跨页面需要进行引用。两种文件引用方式import
和include
使用 is 属性,声明需要的使用的模板,然后将模板所需要的 data 传入,
只会 import 目标文件中定义的 template,而不会 import 目标文件 import 的 template。
如:C import B,B import A,在C中可以使用B定义的template
,在B中可以使用A定义的template
,但是C不能使用A定义的template
。
include
可以将目标文件除了
外的整个代码引入,相当于是拷贝到 include
位置
body
bindtap点击事件;
detail:自定义事件携带数据,点击事件带有的 x, y 同 pageX, pageY 代表距离文档左上角的距离。
currentTarget:如果有事件冒泡,使用currentTarget获取的dataset,表示当前组件上由data-
开头的自定义属性组成的集合数据
阻止事件冒泡:使用catchtap即可阻止事件冒泡
outer view
middle view
inner view
手指触摸事件:小程序中用得不多,内部有封装很多拖拽事件
与 CSS 相比,WXSS 扩展的特性有:
一般设计稿规范:以iPhone6 为基准,屏幕宽度为375px,共有750个物理像素,则750rpx = 375px = 750物理像素,1rpx = 0.5px = 1物理像素
样式导入:@import "common.wxss"
内联样式:如果需要动态渲染可以使用,如果纯静态样式不建议使用内联会影响渲染速度
全局样式app.wxss会作用域全局,但局部样式优先级高于全局
右击创建components创建自定义组件
使用时:页面js文件中usingComponent中引入;wxml页面中引入组件
注意:在组件wxss中不应使用ID选择器、属性选择器和标签名选择器。
注意点:
usingComponents
字段引入;usingComponents
时, setData
内容不会被直接深复,即 this.setData({ field: obj })
后 this.data.field === obj
。(深复制会在这个值被组件间传递时发生。)默认插槽和具名插槽,基本和vue一致
如果要使用多个插槽需要在options中设置multipleSlots: true
options: {
multipleSlots: true // 在组件定义时的选项中启用多slot支持
},
不能使用id,属性,标签 ,子元素选择器(.a > .b)
可以设置默认样式: :host{ color: red; },当前自定义组件下所有默认样式
父子组件都有同一个样式,样式设置在page中,自定义组件中使用。发现自定义组件中样式没有生效。
页面和组件样式都是相互隔离的。
改变:使用options:{ styleIsolation: "isolated" }进行修改
styleIsolation属性值:
isolated
表示启用样式隔离,在自定义组件内外,使用 class 指定的样式将不会相互影响(一般情况下的默认值);apply-shared
表示页面 wxss 样式将影响到自定义组件,但自定义组件 wxss 中指定的样式不会影响页面;shared
表示页面 wxss 样式将影响到自定义组件,自定义组件 wxss 中指定的样式也会影响页面和其他设置了 apply-shared
或 shared
的自定义组件。(这个选项在插件中不可用。)组件希望接受外部传入的样式类。此时可以在 Component
中用 externalClasses
定义段定义若干个外部样式类。
实现类似于 view
组件的 hover-class
属性:页面可以提供一个样式类,赋予 view
的 hover-class
,这个样式类本身写在页面中而非 view
组件的实现中。
注意:在同一个节点上使用普通样式类和外部样式类时,两个类的优先级是未定义的,因此最好避免这种情况。
使启用了样式隔离 isolated
,组件仍然可以在局部引用组件所在页面的样式或父组件的样式。
默认情况下,自定义组件本身的那个节点是一个“普通”的节点,使用时可以在这个节点上设置 class
style
、动画、 flex 布局等,就如同普通的 view 组件节点一样。
自定义组件并不希望这个节点本身可以设置样式、响应 flex 布局等,而是希望自定义组件内部的第一层节点能够响应 flex 布局或者样式由自定义组件本身完全决定。这种情况下,可以将这个自定义组件设置为“虚拟的”:
Component({
options: {
virtualHost: true
},
properties: {
style: { // 定义 style 属性可以拿到 style 属性上设置的值
type: String,
}
},
externalClasses: ['class'], // 可以将 class 设为 externalClasses
})
不是蓝色的
满宽的
需要注意的是,自定义组件节点上的 class
style
和动画将不再生效,但仍可以:
properties
属性来获取 style 上设置的值;externalClasses
外部样式类使得自定义组件 wxml 可以使用 class 值。Component构造器有两种作用: 创建自定义组件;页面中使用 Component 构造器构造页面
Component
构造器可用于定义组件,调用 Component
构造器时可以指定组件的属性、数据、方法等。
监听数据,公共逻辑复用(behaviors)等。
Component 构造器构造页面也可以实现以下功能:
onLoad()中获取页面跳转后的参数;
可以通过properties获取父级页面的数据;(properties定义的数据,可以通过this.data进行获取)
通的属性的绑定是单向的
如果使用 this.setData({ value: 'leaf' })
来更新 value
,this.data.value
和输入框的中显示的值都会被更新为 leaf
;但如果用户修改了输入框里的值,却不会同时改变 this.data.value
。
如果要实现可以使用bindinput然后手动更改this.data.value的值
这是输入框的值: {{inputText}}
Component({
data: {
inputText: ''
},
methods: {
inputChange(e){
console.log(e.detail.value);
this.setData({
inputText: e.detail.value
})
},
}
})
注意是model:value="{{inputText}}"不是model:input-text="{{inputText}}"。model:input-text="{{inputText}}"是自定义组件双绑方法
这是输入框的值: {{inputText}}
用于双向绑定的表达式有如下限制
属性传值必须小写字母+ “-”形式,不能使用大驼峰
父组件: model:input-text="inputText"
子组件:通过properties接收,然后通过update方法直接在子组件中修改(和vue不同,vue必须通知父级修改)
父组件:
data: {
inputText: ''
},
子组件:
子组件:{{inputText}}
properties: {
inputText: String
},
methods: {
updateData: function() {
// 更新 inputText
this.setData({
inputText: '重置数据'
})
}
},
父组件中传入数据和方法:input-text="{{inputText}}" bind:set-input="handleInput"。handleInput方法中监听子组件传递过来数据并更改inputText
子组件中:properties获取数据,然后在button点击时,通过this.triggerEvent("set-input",{inputText:"重置数据"})进行修改
父组件:
handleInput(e){
this.setData({
inputText: e.detail.inputText
})
},
子组件:
子组件:{{inputText}}
updateData: function() {
// 自定义事件实现双绑
this.triggerEvent('set-input', {inputText: "重置数据"})
},
bubbles:事件是否冒泡,默认false
composed:是否可以穿越边界。如下为false时事件只在my-component组件中触发时生效,外层的another-component不会生效
this.selectComponent
在父组件里调用 this.selectComponent
,获取子组件的实例对象。
因为时在父级操作子组件,所以会造成逻辑混乱。所以除特殊需要一般不要使用
const child = this.selectComponent('.my-component');
类似vue的watch,但是比vue的watch更加强大,在watch基础上也实现了computed的功能。
数据监听器可以用于监听和响应任何属性和数据字段的变化。 2.6.1 以上基础库版本
只能定义在Component()下面
numberA和numberB任何一个变量修改都会重新赋值,相当与vue的computed
numberA:
numberB:
sum和为:{{sum}}
Component({
data: {
// inputText: ''
numberA:0,
numberB:0,
sum:0
},
observers:{
'numberA,numberB':function(newA,newB){
this.setData({
sum: parseInt(newA) + parseInt(newB)
});
}
},
})
购物车案例:
{{item.name}}
¥{{item.price}}
+
-
合计:¥{{totalPrice}}
Component({
data: {
item:[
{
id:1,
name: '华为Mate 50E 4G',
price: 3999,
num:0
},
{
id:2,
name: '苹果15',
price: 7400,
num:0
},
],
totalPrice:0
},
observers:{
'item':function(newVal){
let totalPrice = this.data.item.reduce((sum,item)=>{
return sum = sum + item.price * item.num
},0)
this.setData({
totalPrice
});
}
},
methods: {
changeNum(e){
console.log(e);
let { type, index } = e.target.dataset;
let data = JSON.parse(JSON.stringify(this.data.item))
if(type==='add'){
data[index].num +=1;
}else{
data[index].num -=1;
}
this.setData({
item: data
});
},
ready(){
let totalPrice = this.data.item.reduce((sum,item)=>{
return sum = sum + item.price * item.num
},0)
this.setData({
totalPrice
})
}
}
})
定义在data中的字段可以进行组件间传递,但是也同时会影响页面的性能。那么就可以给不需要进行页面渲染只存在逻辑处理的数据声明为纯数据字段
Component({
options: {
pureDataPattern: /^_/ // 指定所有 _ 开头的数据字段为纯数据字段
},
data: {
a: true, // 普通数据字段
_b: true, // 纯数据字段
},
methods: {
myMethod() {
this.data._b // 纯数据字段可以在 this.data 中获取
this.setData({
c: true, // 普通数据字段
_d: true, // 纯数据字段
})
}
}
})
_b: {
type: Boolean,
observer() {
// 不要这样做!这个 observer 永远不会被触发
}
},
observers: {
timestamp: function () {
// timestamp 被设置时,将它展示为可读时间字符串
var timeString = new Date(this.data.timestamp).toLocaleString()
this.setData({
timeString: timeString
})
}
}
注意点:
这是头部区域
{{item.id}}-{{item.name}}
.header{
width: 100%;
height: 200rpx;
background-color: darkgreen;
}
.scroll-view{
height: calc(100% - 100px);
}
Component({
data: {
scrollItem:[],
scrollTo:0
},
methods: {
onLoad(){
const data = Array(100).fill(0).map((_, i) => {
return {
id: 'test'+i,
name: i+'test'
}
});
this.setData({
scrollItem: data
});
},
gotoPos(){
this.setData({
scrollTo: 'test'+50
});
}
}
})