跳至主要內容

微信小程序

程序员李某某大约 20 分钟

微信小程序

前置知识

移动端适配

  • 物理像素:屏幕的分辨率,设备能控制显示的最小单元,可以把物理像素看成对应的像素点
  • 设备独立像素:也叫密度无关像素,可以认为是计算机坐标系统中的一个点,这个点代表一个可以由程序使用并控制的虚拟像素,比我css像素,只是在安卓机中的css像素就不叫css像素了,而是叫设备独立像素,然后由关系系统转为物理像素
  • dpr:设备像素比,物理像素/设备独立像素,一般以iPhone6的dpr为准(dpr=2)
  • ppi:一英尺显示屏上的像素点的个数
  • dpi:最早指的是打印机在单位面积上打印的墨点数,墨点数越多越清晰

小程序适配

iPhone6:1rpx = 1物理像素 = 0.5px

微信官方提供的换算方式:

  • 以iPhone6的物理像素个数为标准:750
  • 1rpx = 目标设备宽度 / 750px
  • 此时底层已经做了viewport适配处理,即实现了理想视口

视网膜屏幕:是分辨率超过人眼识别极限的高分辨率屏幕,由苹果公司在2010年发布iPhone4的发布会上首次推出的术语,dpr=2是人类肉眼分辨的极限

Hello 小程序

项目结构

- page							存放页面
	- index						每个页面的名称,目录下包含该页面的配置
		- index.js
		- index.json
		- index.wxml
		- index.wxss
	- ortherPage
		...
- utils							存放工具代码
	- util.js
	...
app.js							小程序项目的入口文件
app.json						小程序项目的全局配置文件
app.wxss						小程序项目的全局样式文件
project.config.json				项目的配置文件
project.private.config.json
sitemap.json					用于配置小程序及其页面是否允许被微信索引,如果没有,默认为所有页面允许被索引
.eslintrc.js					代码检查工具

app.json

{
  "pages":[					// 所有页面路径
    "pages/index/index",	// 第一个作为首页加载,tabBar必须在非tabBar前
    "pages/logs/logs",
    "pages/test/test"
  ],
  "window":{				// 全局定义小程序所有页面的背景色、文字颜色等
    "backgroundTextStyle":"light",				// 下拉窗口loading样式,二选一:dark、light
    "backgroundColor":"#fff",					// 下拉窗口颜色
    "navigationBarBackgroundColor": "#fff",		// 导航栏背景颜色
    "navigationBarTitleText": "Weixin",			// 导航栏标题
    "navigationBarTextStyle":"black",			// 导航栏标题颜色,二选一:black、white
    "enablePullDownRefresh":false,				// 是否开启全局下拉刷新,一般在页面中单独开启
    "onReachBottomDistance":50					// 上拉触底事件触发时距离页面底部的距离,一般用默认值
  },
  "tabBar":{				// 配置导航栏
      "list":[{									// 2-5个导航栏
          "pagePath":"pages/index/index",			// 页面路径,必填
          "text":"日志",							   // 导航标签名称,必填
          "iconPath":"/images/tabs/index.png",		// 导航标签图标
          "selectedIconPath":"/images/tabs/index-active.png"	// 选中的导航标签图标
      },{
 		  "pagePath":"pages/logs/logs",
          "text":"首页",
          "iconPath":"/images/tabs/logs.png",
          "selectedIconPath":"/images/tabs/logs-active.png"
      },{
          "pagePath":"pages/test/test",
          "text":"首页",
          "iconPath":"/images/tabs/test.png",
          "selectedIconPath":"/images/tabs/test-active.png"
      }]
  }
  "style": "v2",			// 全局定义小程序组件所使用的样式版本
  "sitemapLocation": "sitemap.json"		// 用来指明 sitemap.json 的位置
}

页面.json

{
    "backgroundTextStyle":"light",				// 下拉窗口loading样式,二选一:dark、light
    "backgroundColor":"#fff",					// 下拉窗口颜色
    "navigationBarBackgroundColor": "#fff",		// 导航栏背景颜色
    "navigationBarTitleText": "Weixin",			// 导航栏标题
    "navigationBarTextStyle":"black",			// 导航栏标题颜色,二选一:black、white
    "enablePullDownRefresh":false,				// 是否开启全局下拉刷新,一般在页面中单独开启
    "onReachBottomDistance":50					// 上拉触底事件触发时距离页面底部的距离,一般用默认值
}

project.config.json

{
  "description": "项目配置文件",
  "packOptions": {
    "ignore": [],
    "include": []
  },
  "setting": {								// 编译相关配置
    "bundle": false,
    "userConfirmedBundleSwitch": false,
    "urlCheck": true,
    "scopeDataCheck": false,
    "coverView": true,
    "es6": true,
    "postcss": true,
    "compileHotReLoad": false,
    "lazyloadPlaceholderEnable": false,
    "preloadBackgroundData": false,
    "minified": true,
    "autoAudits": false,
    "newFeature": false,
    "uglifyFileName": false,
    "uploadWithSourceMap": true,
    "useIsolateContext": true,
    "nodeModules": false,
    "enhance": true,
    "useMultiFrameRuntime": true,
    "useApiHook": true,
    "useApiHostProcess": true,
    "showShadowRootInWxmlPanel": true,
    "packNpmManually": false,
    "enableEngineNative": false,
    "packNpmRelationList": [],
    "minifyWXSS": true,
    "showES6CompileOption": false,
    "minifyWXML": true,
    "babelSetting": {
      "ignore": [],
      "disablePlugins": [],
      "outputPath": ""
    },
    "condition": false
  },
  "compileType": "miniprogram",
  "libVersion": "2.19.4",
  "appid": "wx8c8bf9a0912c75e9",			// 自己的AppId
  "projectname": "miniprogram-92",			// 项目名称
  "condition": {},
  "editorSetting": {
    "tabIndent": "insertSpaces",
    "tabSize": 2
  },
   "checkSiteMap": false					// sitemap 的索引提示是默认开启的,配置后关闭
}

修改首页

小程序app.json中pages配置项中,排在第一个的当做首页

只要在pages中配置的页面,会自动生成页面的骨架

WXML

和html相比

  • 标签名不同
    • html(div、span、img、a)
    • wxml(view、text、image、navigator)
  • 属性节点不同
    • <a href="#">超链接</a>
    • <navigator url="/pages/index/index"></navigator>

WXSS

和css相比

  • 尺寸单位
    • css需要手动进行像素换算,如rem
    • wxss支持的新单位rpx可自适应屏幕大小,自动换算,通常以iPhone6为基准1 rpx = 0.5 px
  • wxss有全局样式和局部样式
  • wxss仅支持部分css选择器 --- 类选择器、id选择器、element、并集选择器、后代选择器、伪类选择器
  • wxss支持样式导入@import,后跟外联样式表的相对路径

运行机制

小程序启动过程

  • 把小程序包下载到本地
  • 解析app.json全局配置文件
  • 执行app.js小程序入口文件,调用App()创建的小程序实例
  • 渲染小程序首页
  • 启动完成

页面渲染过程

  • 加载解析页面的json文件
  • 加载页面的wxml模板和wxss样式
  • 执行页面js文件,调用Page()场景·创建页面实例
  • 渲染完成

组件、API

九大组件

  • 视图容器
  • 基础内容
  • 表单组件
  • 导航组件
  • 媒体组件
  • map地图组件
  • canvas画布组件
  • 开发能力
  • 无障碍访问

三大API

  • 事件监听,以on开头,如wx.onWindowResize(function callback) 监听窗口尺寸变化的事件
  • 同步API,以Sync结尾的,如wx.setStorageSync('key', 'value') 向本地存储中写入内容
  • 异步API,如wx.request() 发起网络数据请求,通过 success 回调函数接收数据

视图容器

  • view:普通的视图区域,类似div,是一个块级元素,用来页面布局

  • scroll-view:可滚动的视图区域,常用来实现滚动列表

  • swiper 和 swiper-item:轮播图组件

    <swiper class="s" indicator-dots indicator-color="#fff">
      <swiper-item>
        <view>A</view>
      </swiper-item>
      <swiper-item>
        <view>B</view>
      </swiper-item>
      <swiper-item>
        <view>C</view>
      </swiper-item>
    </swiper>
    

    属性

    • indicator-dots,是否显示指示点,默认false
    • indicator-color,指示点颜色,默认rgba(0,0,0,.3)
    • indicator-active-color,选中的指示点颜色,默认#000
    • autoplay,自动切换,默认false
    • interval,自动切换时间间隔,默认5000
    • circular,是否采用衔接滑到,默认false

基础内容组件

  • text:文本组件,类似span,行内元素
    • selectable属性,支持长按选中<text selectable>12345</text>
  • rich-text:富文本组件,支持将html字符串渲染为wxml
    • nodes属性,放html<rich-text nodes="<h1> 标题1 </h1>"></rich-text>

其他常用组件

  • button:按钮组件
    • type:三选一,default默认灰底绿字,primary主色调按钮绿底白字,warn警告按钮灰底红字
    • size:二选一,default,mini
    • plain:镂空
  • image:图片组件,默认宽度300px,高度240px
    • mode:
      • scaleToFill,默认值,变形填满,
      • aspectFit,不变形,长边全显,
      • aspectFill,不变形,短边全显
      • widthFix,不变形,宽度不变
      • heightFix,不变形,高度不变
  • navigator:导航组件

数据绑定

和vue一样,数据可以在初始化时存放在当前页面内存的data中

定义:在当前页面的js文件中进行配置

Page({
    data: {
        username:'lala',
        password:'xxxxx',
        imgUrl:'https://xxxxxxxxxxxxxx'
    },
    ...
})

使用:在wxml中使用

<view>{{username}}</view>

和vue不同的是,差值语法不仅可以绑定文本,进行运算(算数运算、三元运算),还可以绑定属性

<image src="imgUrl"></image>

事件绑定

事件类型绑定方式说明
tapbindtap 或 bind:tap手指触摸后马上离开,类似于 HTML 中的 click 事件
inputbindinput 或 bind:input文本框的输入事件
changebindchange 或 bind:change状态改变时触发

事件对象的属性:当事件回调触发的时候,会收到一个事件对象 event,它的详细属性如下表所示

属性类型说明
typeString事件类型
timeStampInteger页面打开到触发的时间
targetObject触发事件的组件(冒泡的源头)的属性值集合
currentTargetObject当前组件(绑定事件的组件)的属性值的集合
detailObject额外的信息
touchesArray触摸事件,当前停留在屏幕的触摸点信息的数组
changedTouchesArray触摸事件,当前变化的触摸点信息的数组

事件传参 --- 通过data-kkk=“vvv”传参,通过e.target.dataset.xxx获取

  • bindtap
<button type="primary" bindtap="test" data-info="{{2}}">按钮</button>
Page({
    data:{
        count:0
    },
 	test(e){
 		console.log(e)
        console.log(e.target.dataset.info)
        this.setData({
            count: ++this.data.count
        })
 	}
})
  • bindinput
<input bindinput='inputTest'></input>
Page({
    inputTest(e){
        console.log(e.detail.value)		// 变化后最新的值
    }
})

文本框的数据绑定

<input value="{{msg}}" bindinput='inputTest'></input>
Page({
    data:{
        msg:'你好呀'
    },
    inputTest(e){
        this.setData({
            msg:e.detail.value
        })
    }
})

条件渲染

<input value="{{sex}}" bindinput='inputTest'></input>

<view wx:if="{{sex == 1}}">男的</view>
<view wx:elif="{{sex == 2}}">女的</view>
<view wx:else>不知道</view>
Page({
    data:{
        sex:1
    },
    inputTest(e){
        console.log(1111111111)
        this.setData({
            sex:e.detail.value
        })
    }
})

一次性控制多组件的显示隐藏,需要加<block>包裹,<block> 并不是一个组件,它只是一个包裹性质的容器,不会在页面中做任何渲染

<block wx:if="{{true}}">
	<view> A </view>
    <view> B </view>
    <view> C </view>
</block>

hidden 相当于vue中的v-show,控制样式来实现的隐藏

<view hidden="{{true}}">展示</view>

频繁切换时用hidden,控制条件复杂时用wx:if

列表渲染

<view wx:for="{{array}}">
	索引是:{{index}},值为:{{item}}
</view>

默认索引为index,变量名为item,可以手动指定

<view wx:for="{{array}}" wx:for-index="idx" wx-for-item="good">
	索引是:{{idx}},值为:{{good}}
</view>

wx:key类似vue中的:key,指定唯一键

<view wx:for="{{userList}}" wx:key="id">
	{{item.name}}
</view>
Page({
    data:{
        userList:[
            {id:111,name:'小红'},
            {id:222,name:'小黄'},
            {id:333,name:'小白'}
        ]
    }
})

网络请求

  • 配置request合法域名(小程序只能发https请求),将接口的域名添加到信任列表
    • 登录微信小程序管理后台 -> 开发 -> 开发设置 -> 服务器域名 -> 修改 request 合法域名
    • 只能是备案的域名,不能使用ip和localhost
  • 本地测试跳过合法域名校验:详情 -> 本地设置 -> 不校验....
  • 微信小程序没有跨域,也没有ajax

get请求

wx.request({
	url:'https://xxxxxxxxxxx',
    method:'GET',
    data:{
        name:'xx',
        age:11
    },
    success:(resp)=>{
        console.log(resp)
    }
})

post请求

wx.request({
    url:'https://xxxxxxxxx',
    method:'POST',
    data:{
        name:'vv',
        age:22
    },
    success:(resp)=>{
        console.log(resp)
    }
})

生命周期

应用的生命周期

  • onLaunch(options){}:小程序初始化完成,全局只触发一次
  • onShow(options){}:小程序启动时,或从后天进入前提时触发
  • onHide(){}:小程序从前台进入后台时触发

页面的生命周期

  • onLoad(options){}:监听页面的加载,一个页面仅调用一次
  • onShow(){}:监听页面显示
  • onReady(){}:监听页面初次渲染完成,一个页面仅调用一次
  • onHide(){}:监听页面隐藏
  • onUnload(){}:监听页面卸载,一个页面仅调用一次

组件的生命周期

生命周期函数参数描述说明
created在组件实例刚刚被创建时执行
attached在组件实例进入页面节点树时执行
ready在组件在视图层布局完成后执行
moved在组件实例被移动到节点树另一个位置时执行
detached在组件实例被从页面节点树移除时执行
errorObject Error每当组件方法抛出错误时执行
// 生命周期函数--监听页面加载
onLoad(options){
    this.getGoodList()
},
getGoodList(){}

页面导航

html中使用<a>location.href,类似的,小程序也是有两种方式

声明式导航

  • 导航到tabBar页面
    • url:页面地址,必须以/开头
    • open-type:六选一,
      • switchTab:导航到tabBar页面
      • navigate:导航到普通页面,可省略
      • navigateBack:后退 和 delta 属性搭配使用,值为1时可省略
      • exit:
      • redirect:重定向
      • reLaunch:
<navigator url="/pages/logs/logs" open-type="switchTab">导航到日志tabBar</navigator>
<navigator url="/pages/info/info" open-type="navigate">导航到信息</navigator>
<navigator url="/pages/info/info" open-type="navigateBack" delta="1">导航到信息</navigator>

编程式导航

<button bindtap="gotoXxx">跳转tabBar</button>
<button bindtap="gotoInfo">跳转非tabBar</button>
<button bindtap="gotoBack">回退</button>
Page({
    gotoXxx(){
        wx.switchTab({
            url:"xxxxxxxx",		// tabBar路径
            successs:()=>{},	// 成功的回调
            fail:()=>{},		// 失败的回调
            complete:()=>{}		// 必定执行的回调
        })
    },
    gotoInfo(){
        wx.navigateTo({
            url:"xxxxxxxx",		// 非tabBar路径
            successs:()=>{},	// 成功的回调
            fail:()=>{},		// 失败的回调
            complete:()=>{}		// 必定执行的回调
        })
    },
    gotoBack(){
        wx.navigateBack({		// 没有对象。默认回退一步
            delta:1,			// 回退步数
            successs:()=>{},	// 成功的回调
            fail:()=>{},		// 失败的回调
            complete:()=>{}		// 必定执行的回调
        })
    }
})

导航传参

传参:url拼接参数

<navigator url="/pages/logs/logs?user=aaa&age=20" open-type="switchTab">导航到日志tabBar</navigator>
gotoXxx(){
    wx.switchTab({
        url:"/pages/logs/logs?user=aaa&age=20",		// tabBar路径
        successs:()=>{},	// 成功的回调
        fail:()=>{},		// 失败的回调
        complete:()=>{}		// 必定执行的回调
    })
}

接收:在onLoad中接收

onLoad(options){
	console.log(options)
}

页面事件

下拉刷新

通过onPullDownRefresh监听

<view> count = {{count}}</view>
<button bind:tap="addCount">
    count+1
</button>
Page({
    data:{
        count:0
    },
    andCount(){
        this.setData({
            count:++this.data.count
        })
    },
    onPullDownRefresh(){
        this.setData({
            count:0
        })
        wx.stopPullDownRefresh()
    }
})

停止下拉刷新

当处理完下拉刷新后,下拉刷新的 loading 效果会一直显示,不会主动消失,所以需要手动隐藏下拉刷新的 loading 效果。此时,调用 wx.stopPullDownRefresh() 可以停止当前页面的下拉刷新

上拉触底

通过onReachBottom监听

无尽的颜色小案例

Page({
    data:{
        colorList:[],
        isloading:false // 节流阀
    },
    getColor(){
        this.setData({
            isloading:true
        })
        // 开启loading
        wx.showLoading({
          title: '数据加载中'
        })
        setTimeout(()=>{
          const arr = [1,2,3,4,5,6,7,8,9,0,'a','b','c','d','e','f']
          const colorList = this.data.colorList
          // const i = Math.random()*16
          for(let j = 0 ; j < 30 ;j++){
            let color = "#"
            for(let i = 0 ; i < 6 ; i++){
              const n = Math.floor(Math.random() * 16)
              color = color + arr[n]
              console.log(color)
            }
            colorList.push(color)
          }
          this.setData({
            colorList
          })
          console.log(this.data.colorList)
          wx.hideLoading()		// 关闭loading
        },3000)
		this.setData({
            isloading:false
        })
      },
      // 页面加载
      onLoad(options) {
        this.getColor()
      },
      // 下拉刷新
      onPullDownRefresh() {
        if(isloading) return
        this.setData({
          colorList:[]
        })
        this.getColor()
        wx.stopPullDownRefresh()
      },
      // 上拉触底
      onReachBottom() {
        if(isloading) return
        this.getColor()
      } 
})

wxs脚本

虽然 wxs 的语法类似于 JavaScript,但是 wxs 和 JavaScript 是完全不同的两种语言:

①wxs 有自己的数据类型

  • number 数值类型、string 字符串类型、boolean 布尔类型、object 对象类型、

  • function 函数类型、array 数组类型、 date 日期类型、 regexp 正则

②wxs 不支持类似于 ES6 及以上的语法形式

  • 不支持:let、const、解构赋值、展开运算符、箭头函数、对象属性简写、etc...

  • 支持:var 定义变量、普通 function 函数等类似于 ES5 的语法

③wxs 遵循 CommonJS 规范

  • module 对象

  • require() 函数

  • module.exports 对象

内嵌

wxml 文件中的每个 <wxs></wxs> 标签,必须提供 module 属性,用来指定当前 wxs 的模块名称,方便在 wxml 中访问模块中的成员:

<view>{{m1.toUpper(name)}}</view>
<wxs module='m1'>
	module.exports.toUpper = function(str){
    	return str.toUpperCase()
    }
</wxs>

外联

编写在以 .wxs 为后缀名的文件内

  • module 用来指定模块的名称

  • src 用来指定要引入的脚本的路径,且必须是相对路径

  • 在 wxs 中定义的函数不能作为组件的事件回调函数

  • wxs 不能调用 js 中定义的函数

  • wxs 不能调用小程序提供的 API

<view>{{m2.toLower(country)}}</view>
<wxs src="../xxxxxxx" module="m2"></wxs>
function toLower(str){
    return str.toLowerCase()
}

module.exports = {
    toLower:toLower
}

自定义组件

组件与页面的区别

  • 组件的 .json 文件中需要声明 "component": true 属性
  • 组件的 .js 文件中调用的是 Component() 函数
  • 组件的事件处理函数需要定义到 methods 节点中

创建

①在项目的根目录中,鼠标右键,创建 components -> test 文件夹

②在新建的 components -> test 文件夹上,鼠标右键,点击“新建 Component”

③键入组件的名称之后回车,会自动生成组件对应的 4 个文件,后缀名分别为 .js,.json, .wxml 和 .wxss

注意:为了保证目录结构的清晰,建议把不同的组件,存放到单独目录中

引用

局部引用

在页面的json文件中,引入组件

{
    "usingComponents":{
        "my-test":"/components/test/test"
    }
}

页面的wxml中使用

<my-test></my-test>

全局引用

{
    "page":[],
    "window":{},
    "usingComponents":{
        "my-test":"/components/test/test"
    }
}

样式隔离

  • 默认情况下,组件样式与页面样式互不影响

  • 默认情况下的隔离性只对类选择器有效,id选择器,属性选择器,标签选择器依然会影响

  • 修改隔离:在组件的js文件中添加如下配置 或 在json文件中添加配置

    • isolated:启用样式隔离
    • apply-shared:页面影响组件,组件不影响页面
    • shared:相互影响
    Component({
        options:{
            styleIsolation:'isolated'
        }
    })
    
    {
        "styleIsolation":"isolated"
    }
    

js文件

Component({
    data:{
        good:{
            name:'',
            picUrl:''
        }
    },
    properties:{		// 对外属性,用来接收外界传递到组件中的数据,相当于vue中的props
        max:{				// 完整定义,定义类型和默认值
            type:Number,
            value:10
        },
        min:Number			// 简单定义,只定义类型
        
    },
    methods:{},
    observers:{			// 数据监听,类型vue中的watch
        'max,min':function(maxNew,minNew){},
        'good.name,good.picUrl':function(a,b){}	// 监听属性或整个对象,当对象变化或指定属性变化时就会触发
        'good.**':function(obj){}	// 通配符监听对象及所有属性变化
    }
})
<my-test max="10"></my-test>
  • data用于存储组件的私有数据
  • properties用于对外访问的数据
  • 修改时也是使用this.setData

纯数据字段

不用于页面渲染的字段,提升渲染速度,可配置,如下

Component({
    options:{
        pureDataPattern:/^_/			// 配置_开头的字段为纯数据字段
    },
    data:{
        a:'sss',		// 普通字段
        _b:true			// 纯数据字段
    }
})

组件的生命周期

常用的

  • created:组件实例刚被创建好的时候,created 生命周期函数会被触发

    • 此时还不能调用 setData

    • 通常在这个生命周期函数中,只应该用于给组件的 this 添加一些自定义的属性字段

  • attached:在组件完全初始化完毕、进入页面节点树后, attached 生命周期函数会被触发

    • 此时, this.data 已被初始化完毕

    • 这个生命周期很有用,绝大多数初始化的工作可以在这个时机进行(例如发请求获取初始数据)

  • detached:在组件离开页面节点树后, detached 生命周期函数会被触发

    • 退出一个页面时,会触发页面内每个自定义组件的 detached 生命周期函数

    • 此时适合做一些清理性质的工作

使用

  • 可以直接在Component构造器中使用

  • 推荐在Component构造器的lifetimes属性中使用

    Component({
        lifetimes:{
            attached(){},
            detached(){}
        }
    })
    

组件所在页面的生命周期

生命周期函数参数描述
show组件所在的页面被展示时执行
hide组件所在的页面被隐藏时执行
resizeObject Size组件所在的页面尺寸变化时执行

使用

Component({
    pageLifetimes:{
        show(){},
        hide(){},
        resize(size){}
    }
})

插槽

组件

<view>
	<view>已知的组件的内部节点</view>
    <!-- 不确定的内容,放一个插槽,使用时填充上 -->
    <slot></slot>
</view>

使用

<my-test>
	<view>插槽的内容</view>
</my-test>

启用多个插槽

Component({
    options:{
        multipleSlots:true
    }
})
<view>
	<view>已知的组件的内部节点</view>
    <slot name="slot1"></slot>
    <view>一些固定的内容</view>
    <slot name="slot2"></slot>
</view>
<my-test>
	<view slot="slot1">插槽内容</view>
    <view slot="slot2">插槽内容</view>
</my-test>

组件通信

方式一:属性绑定:用于实现父向子传值,而且只能传递普通类型的数据,无法将方法传递给子组件

Component({
    data:{
        count:0
    }
})
<my-test count="{{count}}"></my-test>
<view>------------------</view>
<view>父组件中,count={{count}}</view>

Component({
    properties:{
        count:Number
    }
})
<text> 子组件中,count={{count}}</text>

方式二:自定义事件绑定:用于实现子向父传值,可以传递任何类型的数据

syncCount(e){
    this.setData({
        count:e.detail.value
    })
}
<my-test count="{{count}}" bind:sysc="syscCount"></my-test>

Component({
    properties:{
        count:Number
    }
    methods:{
        addCount(){
            this.setData({
                count:++this.properties.count
            })
    		this.triggerEvent('sync',{value:this.properties.count})	// 事件名称,参数对象
        }
    }
})
<text>子组件中的count = {{count}}</text>
<button type="primary" bind:tap="addCount"> count + 1 </button>

方式三:获取组件实例

在父组件中调用this.selectComponent(“id或类选择器”)

<my-test count="{{count}}" bind:sysc="syscCount" class="customA"></my-test>
<button bind:tap="getChild">获取子组件实例对象</button>
getChild(){
	const child = this.selectComponent('.costomA')
    child.setData({
        count:child.properties.count+1
    })
    child.addCount()
}

组件共享

behaviors类似vue中的mixins

创建

module.exports = Behaviors({
    properties:{},
    data:{},
    methods:{},
    behaviors:[],
    created:function(){},
    attached:function(){},
    ready:function(){},
    moved:function(){},
    detached:function(){}
    ...
})

导入

const myBehavior = require("../../behaviors/my-behavior")

Component({
    behaviors:[myBehavior]
})

第三方库

API Promise化

在小程序中,实现 API Promise 化主要依赖于 miniprogram-api-promise 这个第三方的 npm 包

npm i --save miniprogram-api-promise

app.js只需调用一次promisifyAll()即可实现异步api的Promise化

import {promisifyAll} from 'miniprogram-api-promise'

const wxp = wx.p = {}
promisifyAll(wx,wxp)

调用

<van-button type="danger" bindtap="getInfo">vant按钮</van-button>
async getInfo(){
  const {data:res} = await wx.p.request({
    method:'get',
    url:'https://jpt-yf.jd.com/api/v1/adPerformance/list',
    header:{

    },
    data:{
      name:'zs',
      age:20
    }
  })
  console.log(res)
}

全局数据共享

Mobx类似vuex

引入两个包

  • mobx-miniprogram:用于创建Store对象

  • mobx-miniprogram-bindings:用来把 Store 中的共享数据或方法,绑定到组件或页面中使用

npm i --save mobx-miniprogram mobx-miniprogram-bindings

在store文件夹下新建一个js文件,创建Store实例

import {observable,action} from 'mobx-miniprogram'
export const store=observable({
  numA:1,
  numB:2,
  get sum(){
    return this.numA + this.numB
  },
  updateNumA:action(function(step){
    this.numA += step
  }),
  updateNumB:action(function(step){
    this.numB += step
  })
})

使用:绑定到页面

import {createStoreBindings} from 'mobx-miniprogram-bindings'
import {store} from '../../store/store'
Page({
  onLoad(options) {
    this.storeBindings = createStoreBindings(this,{
      store,
      fields:['numA','numB','sum'],
      actions:['updateNumA','updateNumB']
    })
  },
  onUnload() {
    this.storeBindings.destroyStoreBindings()
  },
  andNumA(e){
    console.log(e.target.dataset.step)
    this.updateNumA(e.target.dataset.step)
  },
  andNumB(e){
    console.log(e.target.dataset.step)
    this.updateNumB(e.target.dataset.step)
  },
})
<view>{{numA}} + {{numB}} = {{sum}}</view>
<van-button type="primary" bindtap="andNumA" data-step="{{1}}">按钮</van-button>
<van-button type="default" bindtap="andNumB" data-step="{{-1}}">默认按钮</van-button>

绑定到成员

import {createStoreBindings} from 'mobx-miniprogram-bindings'
import {store} from '../../store/store'
Component({
    behaviors:[storeBindingBehavior],
    storeBindings:{
        store,
        fields:{
            numA:()=>store.numA, 			// 绑定字段方式一
            numB:(store)=>store.numB,		// 绑定字段方式二
            sum:'sum'						// 绑定字段方式三
        },
        actions:{
            updateNumA:'updateNumA',
            updateNumB:'updateNumB'
        }
    },
    methods:{
         andNumA(e){
            console.log(e.target.dataset.step)
            this.updateNumA(e.target.dataset.step)
          },
          andNumB(e){
            console.log(e.target.dataset.step)
            this.updateNumB(e.target.dataset.step)
          },
    }
})

分包

对小程序进行分包的好处主要有以下两点:

  • 可以优化小程序首次启动的下载时间

  • 在多团队共同开发时可以更好的解耦协作

主包:一般只包含项目的启动页面或 TabBar 页面、以及所有分包都需要用到的一些公共资源

分包:只包含和当前分包有关的页面和私有资源

加载规则

  • 在小程序启动时,默认会下载主包并启动主包内页面,tabBar 页面需要放到主包中

  • 当用户进入分包内某个页面时,客户端会把对应分包下载下来,下载完成后再进行展示,非 tabBar 页面可以按照功能的不同,划分为不同的分包之后,进行按需下载

项目结构

- page							存放页面
- utils							存放工具代码
- packageA						分包A
	- pages							分包下的页面
		- page1
		- page2
- packageB						分包B
	- pages							分包下的页面
		- page3
		- page4
app.js							小程序项目的入口文件
app.json						小程序项目的全局配置文件
app.wxss						小程序项目的全局样式文件
project.config.json				项目的配置文件
project.private.config.json
sitemap.json					用于配置小程序及其页面是否允许被微信索引,如果没有,默认为所有页面允许被索引
.eslintrc.js					代码检查工具

配置

{
    "page":[],
    'subpackages':[{
        "root":"packageA",
        "pages":[{
            "pages/page1",
            "pages/page2"
        }]
    },{
        "root":"packageB",
        "name":"pack2",
        "pages":[{
            "pages/page3",
            "pages/page4"
        }]
    }]
}

打包原则

  • 小程序会按 subpackages 的配置进行分包,subpackages 之外的目录将被打包到主包中
  • 主包也可以有自己的 pages(即最外层的 pages 字段)
  • tabBar 页面必须在主包内
  • 分包之间不能互相嵌套

独立分包

可以独立于主包和其他分包而单独运行,只需在普通的分包配置中,给独立分包加independent为true的字段

独立分包中不能引用主包内的公共资源

配置

{
    "page":[],
    'subpackages':[{
        "root":"packageA",
        "pages":[{
            "pages/page1",
            "pages/page2"
        }]
    },{
        "root":"packageB",
        "name":"pack2",
        "pages":[{
            "pages/page3",
            "pages/page4"
        }],
        "independent":true			// 独立分包
    }]
}

分包预下载

{
    "preloadRule":{
        "page/test/test":{			// 进入页面后预下载
            "network":"all",		// 默认为wifi
			"packages":["pack2"]   	// 预下载的分包,文件名root和别名name都可         
        }
    }
}

uni-app

vue create -p dcloudio/uni-preset-vue my-project
上次编辑于:
贡献者: ext.liyuanhao3