微信小程序
- 三级目录
- 介绍
- 所需技术
- 特点
- JSON配置
- WXML模板
- WXSS样式
- rpx
- JS文件
- 小程序宿主环境
- app.json全局配置
- 页面配置
- sitemap配置
- 微信小程序组件
- 微信小程序API
- 协同开发流程
- 应用生命周期函数
- 页面生命周期函数
- 页面事件函数
- WXS脚本
- 定义外联的WXS脚本
- &&使用
- 数据绑定
- Block标签
- 事件绑定
- 列表渲染
- 条件判断
- 定义使用模板
- 引用外部模板
- 发起网络请求
- 事件冒泡和不冒泡
- 组件
- 组件样式影响
- 组件js介绍
- properties
- properties和data的区别
- observers数据监听
- 纯数据字段
- 组件的生命周期函数
- 组件所在页面的生命周期函数
- 组件插槽
- 父子组件通信
- behaviors共享
- 使用npm包
- CSS引用变量
- 微信API进行Promise化
- 全局数据共享mobx
- 创建mobx对应的store
- 在页面中使用mobx
- 在组件中使用mobx
- 分包
- 普通分包
- 独立分包
- 分包预下载
- 自定义tabBar
- 关于微信登录凭证
- 发布小程序
三级目录
介绍
-
微信小程序是一款不需要下载安装就可以使用的应用,实则是需要安装的,只不过体积较小,下载速度很快,用户基本感受不到
-
小程序的大小为2M,不可以大于2M,否则申请不通过
-
在开发项目的时候,难免项目开发完成之后大小超过2MB,这个时候发布不上去就可以通过分包的方式进行拆分包然后再进行发布
-
同APP进行互补,有APP有的功能,通过扫一扫或者微信搜索就可以下载,使用频率不高,但是又不得不用的一款软件,连接线上线下,开发门槛低,成本低。
所需技术
- flex布局。移动端的相关知识点和rem
特点
-
没有DOM和BOM
-
组件化开发
JSON配置
- json是一种数据格式,并不是编程语言,在小程序中,扮演的是静态配置角色
WXML模板
- 和传统的web界面一样,是定义结构的文件,但是与之不同的时候标签名称不一致,例如原本的div,span,img,a标签变成了view,text,image,navigator等等
WXSS样式
-
@import "/common/common.wxss" 导入另外一个wxss样式
-
和传统的web界面的css一样,定义结构的样式,新增一个单位rpx,微信会自动进行算法然后根据屏幕计算大小,不需要人为进行计算了
-
定义在app.wxss中的样式为全局样式,当前界面的wxss为局部样式,会根据就近原则局部样式替换掉全局样式,或者权重一致的时候,会替换掉全局样式
rpx
- 小程序的适配单位,小程序的默认宽度为750px,即1rpx=屏幕宽度/750px,响应式像素单位
JS文件
- js文件就是写交互的地方,数据存放等等
小程序宿主环境
-
小程序的宿主环境不是安卓和iOS,而是微信环境
-
小程序分为渲染层和逻辑层,渲染层就是wxml文件和wxss文件,这俩文件工作在渲染层,js文件工作在逻辑层
app.json全局配置
-
在根目录下面的app.json中进行配置,后续每个界面也可以有单独的json配置文件来替换掉全局配置
-
这里列举了一些常用的,具体可以参考官方文档中框架/全局配置
-
window为全局窗口样式配置
-
pages为界面
-
tabBar为tabBar栏配置,最少配置两个,最多配置五个
-
{ "pages": [ //配置界面,这里对应三个界面 "pages/index1/index1", "pages/index2/index2" ], "entryPagePath": "pages/index2/index2", //默认启动界面 "request": 60000, //请求超时时间 "window": { //样式配置 "navigationBarBackgroundColor": "#FF00FF", //顶部背景颜色 "navigationBarTextStyle": "white/black", //顶部字体颜色 "navigationBarTitleText": "三七", //顶部字体 "navigationStyle": "default/custom", //顶部样式 "backgroundColor": "#B0E2FF", //下拉背景颜色 "backgroundTextStyle": "dark/light", //下拉样式 "onReachBottomDistance": 50, //触底事件触发距离距离 "enablePullDownRefresh": true/false //是否开启刷新 }, "tabBar": { //tab栏定义 "color": "#000000", //字体颜色 "selectedColor": "#EE0000", //选中字体颜色 "backgroundColor": "#F0FFFF", //背景颜色 "borderStyle": "black/white", //顶部边框线样式 "position": "bottom/top", //tab栏位置,顶部显示的时候不显示icon "list": [ //定义有几个tab栏 { "text": "index1", //tab栏的文本 "pagePath": "pages/index1/index1", //tab栏对应的界面路径 "iconPath": "tabBarIcon/_home.png", //tab栏的图标 "selectedIconPath": "tabBarIcon/home.png" //tab栏选中时候的图标 }, { "text": "index2", "pagePath": "pages/index2/index2", "iconPath": "tabBarIcon/_cart.png", "selectedIconPath": "tabBarIcon/cart.png" } ] }, "permission": { "scope.userLocation": { "desc": "你的位置信息将用于小程序位置接口的效果展示" } }, "style":"v2", //使用最新的样式 "sitemapLocation": "sitemap.json" //允许被检索,提高曝光率 }
页面配置
-
每个界面单独的配置,配置和全局配置window一致,全局配置有的它也都有,但是与之不同的就是有多了两个
-
{ "disableScroll":false/true, //界面是否跨域上下滑动 "usingComponents": { //引入组件 "Header":"../../components/Header/Header" //引入组件,后续使用的时候组件名称就是Header }, "navigationBarBackgroundColor": "#FF00FF", //顶部背景颜色 "navigationBarTextStyle": "white/black", //顶部字体颜色 "navigationBarTitleText": "三七", //顶部字体 "backgroundColor": "#B0E2FF", //下拉背景颜色 "backgroundTextStyle": "dark/light", //下拉样式 "onReachBottomDistance": 50, //触底事件触发距离距离 "enablePullDownRefresh": true/false //是否开启刷新 }
sitemap配置
-
用于设置开发的应用界面是否被微信检索
-
{ "rules": [{ //被检索的规则 "action": "allow/disallow", //是否检索 检索/不检索 "page": "*" //检索界面,这里为所有界面 }] }
微信小程序组件
-
文档链接:https://developers.weixin.qq.com/miniprogram/dev/component
-
常用的组件分为:视图组件,基础内容,表单组件,导航,媒体组件
微信小程序API
-
分为三大类:事件监听API,同步API,异步API
-
事件监听都是以on开头的,用于监听某些事件的触发
-
同步API都是以sync结尾的
-
异步API都是以success,fail,complete调用结果的
协同开发流程
-
首先是总管理者负责项目的把控和风险
-
产品组提出需求
-
设计组根据需求进行设计
-
开发组根据设计图形进行开发
-
产品组和设计组进行体验
-
测试组进行测试项目
-
管理者发布
应用生命周期函数
-
每个项目根目录下面必须有一个app.js文件
-
前台指的就是当前小程序切回的时候,指的就是你手机上目前显示的界面是当前小程序的界面
-
后台指的就是在后台运行,当前手机上面显示的不是当前小程序,但是并没有进行关闭当前小程序
-
// 注册App App({ onLaunch(){ //初始化的时候触发,全局只会触发一次 }, onShow(){ //小程序切回前台的时候触发 }, onHide(){ //小程序切回后台的时候触发 }, onError(){ //发生错误的时候触发 } })
页面生命周期函数
-
// 创建界面实例 Page({ onLoad(query){ //页面加载的时候触发,每个界面只会触发一次,除非卸载当前界面 query为传递过来的参数 }, onShow(){ //页面显示时触发,可以触发多次 }, onReady(){ //页面初次渲染时候触发,一个界面只会触发一次,除非卸载当前界面 }, onHide(){ //页面隐藏时触发 }, onUnload(){ //界面卸载时触发 } })
页面事件函数
-
Page({ onPullDownRefresh(){ //下拉刷新的时候触发 }, onReachBottom(){ //滚动到底部的时候触发 }, onShareAppMessage(){ //点击右上角转发给朋友的时候触发 }, onShareTimeline(){ //点击右上角转发到朋友圈的时候触发 }, onAddToFavorites(){ //点击右上角收藏的时候触发 }, onPageScroll(){ //页面滚动的时候触发 }, onResize(){ //屏幕发生变化旋转的时候触发 }, onTabItemTap(){ //点击tab界面的时候触发 }, onSaveExitState(){ //当前界面销毁前的回调 } })
WXS脚本
-
充当过滤器的角色
-
wxs中不能调用js的方法,也能调用微信的api
-
和javascript不一样,不支持高级的es6语法
-
//定义 <wxs module="名称"> module.exports.方法名 = function{ return 处理的结果 } </wxs> //使用 <view>{{名称.方法名(msg)}}</view>
定义外联的WXS脚本
-
需要是wxs结尾的后缀名
-
function 方法名(){ return 返回结果 } module.exports = { 返回出去的名称: 返回出去的方法 }
-
进行引入使用
-
<wxs src="/wxs/wxs.wxs" module = 'm1'></wxs>
&&使用
-
判断这个isStatus为true的时候让a+1
-
isStatus && a+1
数据绑定
-
用于绑定内容,绑定属性,三元运算,算数运算
-
小程序中数据的绑定也是单向的,model—view
-
在data中定义数据,在界面和vue用法一致,双大括号即可
-
修改数据的时候使用this.getData({})来进行修改
-
//定义数据 data: { msg: "hello world" } //使用数据,里面可以写js表达式 <text>{{msg == "你好,世界。" ? "你好世界" : msg}}</text> //修改数据 this.setData({ msg: "你好,世界。" })
Block标签
-
在实际渲染的时候并不会渲染到界面上
-
<block></block>
事件绑定
-
渲染层触发逻辑层
-
常用事件为bindtap(点击事件),bindinput(input框输入事件),bindchange(状态改变事件)
-
target和currentTarget区别就在于事件冒泡
-
target指的就是触发这个事件的元素
-
currentTarget指的就是绑定这个事件的元素
-
事件绑定元素传递参数的时候需要使用data-参数名的方式来进行传递参数
-
bindtap拿传递过来的参数方法为e.target.dataset.参数名
-
bindinput拿的参数方法为e.detail.value
列表渲染
-
规定要渲染的数组,可以设置变量和当前项名称,默认为item和index
-
需要绑定key值,否则会警告,在这里key不需要带{{}},也不需要通过item.去取到哪一个对象里面的哪一个属性名,直接写属性名即可
-
通过wx:for-item可以设置循环项的名称
-
通过wx:for-index可以设置循环项的索引
-
<view wx:for="{{arrList}}" wx:for-item="j" wx:for-index="id" wx:key="id"> {{j.name}} </view>
条件判断
-
wx:if是插入和不插入,hidden是隐藏和不隐藏,在频繁切换的时候建议使用hidden
-
<block wx:if="{{ifState}}"> <view>年后</view> <view>再见</view> </block> <view wx:elif="{{isState == 1}}">内容1</view> <view wx:else>内容</view> //适用于频繁切换 <block hidden="{{ifState}}"> <view>年后</view> <view>再见</view> </block>
定义使用模板
-
模板中所用到的数据需要使用模板的时候传递过去
-
//使用模板,data为传递参数 <template is="userInfo" data="{{name:'张三',age:10}}"></template> //定义模板,name为使用时候的名称 <template name="userInfo"> <view>{{name}}</view> <view>{{age}}</view> </template>
引用外部模板
-
引用的时候都是在wxml文件引入
-
import引用相当于就是在其他地方定义模板然后引入使用
-
include是将另外一个界面的东西复制到这个界面
-
//相当于就是赋值粘贴另外一个界面的内容 <include src="../../Template/02"/> //模板在外部定义直接使用 <import src="../../Template/01"/> <template is="pl" data="{{...chuandishuju}}"></template>
发起网络请求
-
只能发送https请求
-
需要添加到信任列表之中
-
必须是ICP备案且域名的接口,localhost和ip地址不可以
-
小程序中不存在跨域的问题,跨域的问题只存在于网页之中
-
在小程序之中发送的请求叫做发送网路请求,不叫作发送ajax请求
-
配置域名的时候多个域名使用;来进行分隔,不得超过20个
-
一次发送的请求不得超过10个
-
wx.request({ url:'', method:'', timeout:'50000', success: (data) => {}, fail: (err) => {}, complete: () => {} })
事件冒泡和不冒泡
-
点击事件有两种,冒泡和不冒泡
-
//冒泡 <view bindtap="clickHander">冒泡点击</view> //不冒泡 <view catchtap="clickHander">不冒泡点击</view>
组件
-
在微信小程序中创建component即可创建组件
-
组件里面的样式不会影响到其他组件的样式,也不会影响到界面的样式,同时界面也影响不到组件的样式,全局app.wxss的样式也影响不到组件的样式,在组件里面建议使用class定义类名
-
组件的json文件中component必须为true
-
使用组件分为局部使用和全局使用
-
//引入,在全局和局部都是这样进行引入,my-test1为组件名称,/components/test1/test1为当前组件的路径 { "usingComponents": { "my-test1": "/components/test1/test1" } } //使用 <my-test1></my-test1>
组件样式影响
-
第一种方法定义在组件的js文件之中
-
isolated是默认值,互不影响
-
apply-shared是界面影响组件,但是组件影响不了界面
-
shared界面影响组件,组件也影响界面
-
options: { styleIsolation: 'isolated/apply-shared/shared' },
组件js介绍
-
//创建组件实例 Component({ //behaviors behaviors: [ ], //组件配置 options: { }, //外部传递过来的数据 properties: { }, //组件数据存放 data: { }, //组件方法存放 methods: { }, //数据监听 observers: { } })
properties
-
接受外部传递过来的数据,跟vue中的props差不多
-
max为基础写法
-
min为详细写法,会有默认值
-
properties: { max:Number, min: { type: Number, value: 10 } }
properties和data的区别
-
两者毫无区别,都是可读可写
-
修改的方法都是一致的,使用this.setdata({})进行修改
-
properties取值为this.properties.属性名
-
data取值为this.data.属性名
observers数据监听
-
要监听的属性为n1和n2,new1和new2为新值
-
监听对象的时候是使用" 对象名.属性名 "
-
如果要监听的属性太多可以使用通配符," 对象名.** "
-
observers: { "n1, n2": function(new1,new2){ console.log(new1,new2) } }
纯数据字段
-
用于只在业务逻辑里面使用,不会在界面和传递到其他组件使用的数据
-
可以提升页面更新的性能
-
匹配data中以_开头的属性变成纯数据字段
-
options: { pureDataPattern: /^_/ }
组件的生命周期函数
-
created(){} 刚被创建好的时候,此时里面不可以使用this.setdata({})来修改数据 attached(){} 初始化完毕,可以进行修改数据,发送网络请求 ready(){} 组件布局完成后执行 moved(){} 组件实例被移动到节点树另一个位置时执行 detached(){} 销毁的时候,用于做一些清理工作 error(){} 组件方法发生错误时候执行
-
声明周期函数定义,所有的生命周期函数都是写在这个里面,也可以写在与data平级,但是不建议
-
lifetimes: { }
组件所在页面的生命周期函数
-
有时候组件需要根据页面来进行处理,此时就需要用到组件所在页面的生命周期函数
-
pageLifetimes: { show(){}, //当前所在页面显示的时候 hide(){}, //当前所在页面隐藏的时候 resize(){} //当前所在页面尺寸发生变化的时候 }
组件插槽
-
指的就是组件有一部分内容不知道要渲染什么,此时就需要使用者来进行填充渲染,可以使用插槽进行占位
-
//定义插槽 <view> <slot></slot> </view> //使用插槽 <view> <my-test1> <view>插槽内容</view> </my-test1> </view>
-
多个插槽,需要先配置进行启用
-
options: { multipleSlots: true }
-
//定义插槽 <view> <slot name="slot01"></slot> <slot name="slot02"></slot> </view> //使用插槽 <view> <my-test1> <view slot="slot01">插槽内容1</view> <view slot="slot02">插槽内容2</view> </my-test1> </view>
父子组件通信
属性绑定
-
用于父组件向子组件传递数据,只能传递普通类型的数据,不可以传递方法
-
//父组件进行传递 <my-test2 count="{{count}}"></my-test2> //子组件进行接受,然后进行使用 properties: { count:Number, } <view>{{count}}</view>
事件绑定
-
用于子组件向父组件进行传递值,可以传递如何类型的数据
-
父组件定义一个方法并且传递给子组件,注意子组件触发方法的时候不需要带上bind,并且可以传递对应的参数,以键值对的方式进行传递,父组件使用e.detail.键名来进行接受数据
-
//父组件 methods: { countMethod(e){ console.log(e.detail) } } <my-test2 bind:Count="countMethod"></my-test2> //子组件 this.triggerEvent("Count",{value: 1})
获取组件实例
-
用于获取子组件实例,然后通过实例可以访问到子组件的数据和方法
-
通过class或者id来进行获取子组件实例
-
//父组件 <my-test2 bind:Count="countMethod" class="myTest2"></my-test2> const myTest2 = this.selectComponent(".myTest2") myTest2.setdata({ msg: "我是父组件获取实例修改子组件的内容" })
behaviors共享
-
类似于vue中的mixins,实现代码共享
-
可以共享数据,方法,生命周期函数,属性等等
-
先创建一个behaviors文件目录,里面创建一个behaviors.js文件
-
module.exports = behaviors({ properties: { }, //数据存放 data: { }, //方法存放 methods: { }, })
使用
-
const myBehaviors = require("/behaviors/behaviors") behaviors: [ myBehaviors ]
-
同名方法和数据处理
-
数据是对象的时候会进行合并,其他情况覆盖,就近原则 方法是覆盖,就近原则 生命周期函数是依次触发,优先触发behaviors中的生命周期函数
使用npm包
-
小程序目前已经支持使用第三方的npm包来进行开发项目
-
可使用的npm包不支依赖于node.js内置库的包,不支持依赖浏览器内置对象的包,不支持依赖于C++的包
-
在下载npm包之前需要有一个package.json文件,如果没有的话需要初始化
-
初始化npm所需文件
-
npm init -y
-
然后下载对应的包,下载完成的包不可以直接使用,需要在小程序开发者工具,点击工具—构建npm
-
构建完成之后就可以进行使用了,微信小程序只能识别miniprogram_npm目录下面的包,因此需要npm构建出来这个包
CSS引用变量
-
定义引用变量
-
--situaColor: #ffffff;
-
使用
-
background: var(--situaColor)
微信API进行Promise化
-
下载对应的包
-
npm install --save miniprogram-api-promise@1.0.4
然后在app.js文件里面将所有的微信API进行promise化
-
import { promisifyAll } from "miniprogram-api-promise" const wxp = wx.p = {} promisifyAll(wx,wxp)
-
使用的时候只需要wx.p.API即可
-
const {data:res} = await wx.p.request({ })
全局数据共享mobx
-
解决组件之间的数据问题
-
需要用到的是mobx-miniprogram和mobx-miniprogram-bindings
-
mobx-miniprogram创建Store实例对象
-
mobx-miniprogram-bindings用来把Store中的的共享数据或者方法绑定到组件或页面进行使用
-
安装对应的包
-
npm i --save mobx-miniprogram@4.13.2 mobx-miniprogram-bindings@1.2.1
创建mobx对应的store
-
在根目录文件夹下面创建一个store文件夹,然后里面创建一个store.js文件
-
//进行导入创建store的包 import { observable, action } from "mobx-miniprogram" //创建并且进行导出 export const store = observable({ //数据字段 numA: 1, numB: 2, get sum(){ return this.numA + this.numB }, undataNumA: action(function(value){ this.numA = value }) })
在页面中使用mobx
-
//导入对应的包 import { createStoreBindings } from "mobx-miniprogram-bindings" //导入所需要的Store import { store } from "/store/store" Page({ //在页面加载的时候进行绑定 onLoad: function(){ //往当前实例身上追加一个新的属性叫做storeBindings this.storeBindings = createStoreBindings(this, { store, //需要用到的数据,计算属性 fields:["numA","numB","sum"], //需要用到的方法 actions:["undataNumA"] }) } //在页面卸载的时候需要进行解绑 onUnload: function() { this.storeBindings.destroyStoreBindings() } }) //使用 <view>{{numA}} + {{numB}} = {{sum}}</view> <button bindtap="editNumA">修改numA</button> //在界面的Page里面进行定义 editNumA(){ this.undataNumA(10) }
在组件中使用mobx
-
//导入对应的包 import { storeBindingsBehavior } from "mobx-miniprogram-bindings" //导入所需要的Store import { store } from "/store/store" Component({ //进行绑定 behaviors: [storeBindingsBehavior], storeBindings: { store, //需要用到的数据,计算属性 fields:{ numA: () => store.numA, //第一种方法 numB: (store) => store.numB, //第二种方法 sum,"sum" //第三种方法 }, //需要用到的方法 actions:{ undataNumA: "undataNumA" } } }) //使用 <view>{{numA}} + {{numB}} = {{sum}}</view> <button bindtap="editNumA">修改numA</button> //在组件的methods里面进行定义 editNumA(){ this.undataNumA(10) }
分包
-
把一个完整的项目进行拆分,按照需求划分成不同的的子包,在构建的时候打包成不同的包,用户在使用的时候进行按需加载
-
可以优化小程序首次启动的下载时间
-
在多人开发的时候可以更好的解耦协作
-
分包之前的项目会全部打包到一个文件
-
分包之后的项目会有一个主包和多个子包构成
-
主包里面都是tabbar页面和主页还有一些公共的资源等等
-
子包里面都是当前界面所需要的资源
-
所有的分包大小不得超过20MB,单个分包,包括主包不得超过2MB
-
普通分包中,分包可以使用主包的资源,各自子包之间不可以引用其他子包资源
普通分包
-
subpackages下面有几个对象就是分成了几个包,当前是分成了两个包,root是包的根路径,name是为当前分包起的名称,pages是当前分包下面的界面
-
{ "pages":[ "pages/index", "pages/logs" ], "subpackages": [ { "root": "packageA", "pages": [ "pages/cat", "pages/dog" ] }, { "root": "packageB", "name": "pack2", "pages": [ "pages/apple", "pages/banana" ] } ] }
独立分包
-
独立分包只需要在当前对象上面加上一个属性"independent": true即可
-
独立分包不可以引用主包的资源,同时其他子包也不可以使用独立分包的资源
-
{ "pages": [ "pages/index", "pages/logs" ], "subpackages": [ { "root": "moduleA", "pages": [ "pages/rabbit", "pages/squirrel" ] }, { "root": "moduleB", "pages": [ "pages/pear", "pages/pineapple" ], "independent": true } ] }
分包预下载
-
指的就是当用户进入一个界面的时候就提前将后续可能需要用到的包进行下载下来,提升打开效率
-
"pages/index"为访问界面的路径,指的就是在那个界面的时候准备预下载
-
“network”: "all/wifi/"指的就是在什么情况下会进行预下载,all是所有时候,wifi是无线网络
-
“packages”: [“important”]为要预下载的界面,root或者name
-
{ "preloadRule": { "pages/index": { "network": "all/wifi/", "packages": ["important"] }, "sub1/index": { "packages": ["hello", "sub3"] } } }
自定义tabBar
-
先进行在tabbar中配置
-
注意:list数组不可以删除,因为要兼容低版本,其次就是为了区分那个是tabBar界面
-
{ "tabBar":{ "custom": true //启用自定义tabBar } }
-
先在根目录文件下面创建一个文件夹custom-tab-bar,必须是这个名字,不可以进行修改,然后右键新建component,名称为index
关于微信登录凭证
-
先调用wx.login获取到唯一凭证code
-
然后拿到自己的AppId
-
然后生成拿到自己的AppSecret密钥(06ec10f79f3d38e0b972d5b0c3b04bf2)
-
前端进行请求后端接口,所传递的参数为获取的凭证code,自己的AppId,生成的AppSecret密钥
-
后端请求接口地址:https://api.weixin.qq.com/sns/jscode2session?appid=APPID&secret=SECRET&js_code=JSCODE&grant_type=authorization_code
-
请求方式为Get,将前端所传递过来的参数进行发送,分别对应的是appid,secret,code
-
请求返回的结果拿到对应的openid,就是用户的唯一标识,然后进行加密存储,将加密之后的结果返回给前端,前端在发送请求的时候进行携带后端返回的token,token因此生成,然后进行判断token来确定身份
发布小程序
- 上传—小程序后台管理进行审核—审核通过发布成线上版本