这里我开源了一个微信小程序的案例:https://gitee.com/xiaoshixiaoran/wechat-applet
相关后台接口我会有空用SSM重写一遍再挂上去
微信小程序官网 https://mp.weixin.qq.com/
注册微信小程序开发:
打开微信开发工具后左上角有个项目点击 新建项目 选择小程序,项目名称自己命名 ,目录 新建个文件夹存放 App ID就是官网中开发管理里面的开发设置给定开发者ID直接复制过来,开发模式选择小程序,后端服务选择 不使用云服务,语言选择JavaScript
默认配置
小程序根目录下的 app.json
文件用来对微信小程序进行全局配置。
sitemap 配置小程序根目录下的 sitemap.json
文件用于配置小程序及其页面是否允许被微信索引,文件内容为一个 JSON 对象,如果没有 sitemap.json
,则默认为所有页面都允许被索引
详情见小程序开发目录结构:https://developers.weixin.qq.com/miniprogram/dev/framework/structure.html
app.json中必要参数配置pages,为小程页面路径列表,每新建一个页面这里会自动将路径填入
window属性配置全局的默认窗口表现:
black
/ white
更多参数见配置项window:https://developers.weixin.qq.com/miniprogram/dev/reference/configuration/app.html#window
详情见小程序全局配置https://developers.weixin.qq.com/miniprogram/dev/reference/configuration/app.html
单页面配置大于全局属性配置如
直接新建文件夹然后鼠标移动至文件夹上右击page,会自动生成四个文件,命名.js 命名.json 命名.wxml 命名.wxss
# 2.小程序的基础知识储备
Flex基本概念
- Flex 是 Flexible Box 的缩写,意为”弹性布局”,用来为盒状模型提供最大的灵活性。
- 任何一个容器都可以指定为 Flex 布局。
- display: ‘flex’
4. 这部分是一阶段基础知识,可看[文档](http://www.runoob.com/w3cnote/flex-grammar.html
)
屏幕的分辨率
设备能控制显示的最小单元,可以把物理像素看成是对应的像素点
设备独立像素(也叫密度无关像素),可以认为是计算机坐标系统中的一个点,这个点代表一个可以由程序使用并控制的
虚拟像素
(比如:CSS 像素,只是在 android 机中 CSS 像素就不叫”CSS 像素”了而是叫”设备独立像素”),然后由相关系统转换为物理像素。
概念
dpr: 设备像素比,物理像素/设备独立像素 = dpr, 一般以 Iphon6 的 dpr 为准 dpr = 2
PPI: 一英寸显示屏上的像素点个数
DPI:最早指的是打印机在单位面积上打印的墨点数,墨点越多越清晰
不同机型对比表
- 为什么做
viewport
适配 ?a) 手机厂商在生产手机的时候大部分手机默认页面宽度为 980px
b) 手机实际视口宽度都要小于 980px,如: iphone6 为 750px
c) 开发需求需要将 980 的页面完全显示在手机屏幕上且没有滚动条
- 代码实现
<meta name="viewport" content="width=device-width,initial-scale=1.0">
- 为什么做
rem
适配?
a) 机型太多,不同的机型屏幕大小不一样
b) 需求:一套设计稿的内容在不同的机型上呈现的效果一致,根据屏幕大小不同的变化,页面中的内容也相应变化- 原生代码实现:
function remRefresh() { let clientWidth = document.documentElement.clientWidth; // 将屏幕等分 10 份 let rem = clientWidth / 10; document.documentElement.style.fontSize = rem + 'px'; document.body.style.fontSize = '12px'; } window.addEventListener('pageshow', () => { remRefresh() }) // 函数防抖 let timeoutId; window.addEventListener('resize', () => { timeoutId && clearTimeout(timeoutId); timeoutId = setTimeout(() =>{ remRefresh() }, 300) })
框架的视图层由 WXML 与 WXSS 编写,由组件来进行展示。
将逻辑层的数据反映成视图,同时将视图层的事件发送给逻辑层。
WXML(WeiXin Markup Language)是框架设计的一套标签语言,结合基础组件、事件系统,可以构建出页面的结构。
WXSS (WeiXin Style Sheets)是一套样式语言,用于描述 WXML 的组件样式。
WXS(WeiXin Script)是小程序的一套脚本语言,结合
WXML
,可以构建出页面的结构。组件(Component)是视图的基本组成单元。
该部分将
截取官方文档
并加以注解
WXSS (WeiXin Style Sheets)是一套样式语言,用于描述 WXML 的组件样式。
WXSS 用来决定 WXML 的组件应该怎么显示。
为了适应广大的前端开发者,WXSS 具有 CSS 大部分特性。同时为了更适合开发微信小程序,WXSS 对 CSS 进行了扩充以及修改。
与 CSS 相比,WXSS 扩展的特性有:
rpx
注意:
当页面文件在同一级目录下且命名相同(后缀不同),可以互相引用却不用导入
1.
rpx(responsive pixel)
: 可以根据屏幕宽度进行自适应。规定屏幕宽为750rpx。如在iPhone6
上,屏幕宽度为375px,共有750个物理像素,则750rpx = 375px = 750物理像素,1rpx = 0.5px = 1物理像素。
设备 rpx换算px (屏幕宽度/750) px换算rpx (750/屏幕宽度) iPhone5 1rpx = 0.42px 1px = 2.34rpx iPhone6 1rpx = 0.5px 1px = 2rpx iPhone6 Plus 1rpx = 0.552px 1px = 1.81rpx
框架组件上支持使用 style、class 属性来控制组件的样式。
style
:静态的样式统一写到 class 中。style 接收动态的样式,在运行时会进行解析,请尽量避免将静态的样式写进 style 中,以免影响渲染速度
class
:用于指定样式规则,其属性值是样式规则中类选择器名(样式类名)的集合,样式类名不需要带上.
,样式类名之间用空格分隔
.normal_view{ color:#333; }
WXML 中的动态数据均来自对应 Page 的 data。
Mustache 语法{{}}视作运算标记,里面的内容表示表达式
//main.wxml <view>静态数据view> //页面显示:静态数据 <view>{{message}}view> //页面显示:Hello MINA
//main.js Page({ /** * 组件的初始数据 */ data: { message: 'Hello MINA!' } })
在组件上使用
wx:for
控制属性绑定一个数组,即可使用数组中各项的数据重复渲染该组件。默认数组的当前项的下标变量名默认为
index
,数组当前项的变量名默认为item
使用
wx:for-item
可以指定数组当前元素的变量名,使用wx:for-index
可以指定数组当前下标的变量名:// .js //定义数组 let array=[1, 2, 3, 4, 5]
// .wxml <view wx:for="{{array}}" wx:for-index="idx" wx:for-item="itemName"> {{idx}}: {{itemName}} view>
如果列表中项目的位置会动态改变或者有新的项目添加到列表中,并且希望列表中的项目保持自己的特征和状态(如 input 中的输入内容,switch 的选中状态),需要使用
wx:key
来指定列表中项目的唯一的标识符。
wx:key
的值以两种形式提供
字符串,代表在for循环的array中
item的某个property
,该property的值需要是列表中唯一的字符串或数字,且不能动态改变。保留关键字
*this
代表在 for 循环中的 item 本身,这种表示需要 item 本身是一个唯一的字符串或者数字
。
//id是posts数组中的对象里的一个属性
wx:key
的意义当数据改变触发渲染层重新渲染的时候,会校正带有 key 的组件
,框架会确保他们被重新排序,而不是重新创建
,以确保使组件保持自身的状态,并且提高列表渲染时的效率。如不提供
wx:key
,会报一个warning
, 如果明确知道该列表是静态,或者不必关注其顺序,可以选择忽略。
1.在框架中,使用
wx:if=""
来判断是否需要渲染该代码块:<view wx:if="{{recentPlayList.length}}"> True view>
2.也可以用
wx:elif
和wx:else
来添加一个 else 块:<view wx:if="{{length > 5}}"> 1 view> <view wx:elif="{{length > 2}}"> 2 view> <view wx:else> 3 view>
如bindtap
,当用户点击该组件的时候会在该页面对应的Page中找到相应的事件处理函数。
<button class="confirm-btn" bindtap="login">登录button>
login(){
//提示用户
wx.showToast({
title: '手机号不能为空',
icon:'none'
})
return;
}
点击button按钮弹出提示 手机号不能为空
JavaScript
引擎为小程序提供开发者 JavaScript
代码的运行环境以及微信小程序的特有功能。 逻辑层将数据进行处理后发送给视图层,同时接受视图层的事件反馈。
开发者写的所有代码最终将会打包成一份 JavaScript
文件,并在小程序启动的时候运行,直到小程序销毁。这一行为类似ServiceWorker,所以逻辑层也称之为 App Service。
JavaScript
的基础上,我们增加了一些功能,以方便小程序的开发:App
和 Page
方法,进行程序注册和页面注册。getApp
和 getCurrentPages
方法,分别用来获取 App
实例和当前页面栈。注意:小程序框架的逻辑层并非运行在浏览器中,因此 JavaScript
在 web 中一些能力都无法使用,如 window
,document
等。
该部分将截取官方文档
并加以注解
在小程序中所有页面的路由全部由框架进行管理
框架以
栈
的形式维护了当前的所有页面。对于路由的
触发方式
以及页面生命周期函数
如下:
路由方式 页面栈表现 触发时机 路由前页面 路由后页面 初始化 新页面入栈 小程序打开的第一个页面 onLoad, onShow 打开新页面 新页面入栈 调用 API wx.navigateTo
使用组件onHide onLoad, onShow 页面重定向 当前页面出栈,新页面入栈 调用 API wx.redirectTo
使用组件onUnload onLoad, onShow 页面返回 页面不断出栈,直到目标返回页 调用 API wx.navigateBack
使用组件
用户按左上角返回按钮onUnload onShow Tab 切换 页面全部出栈,只留下新的 Tab 页面 调用 API wx.switchTab
使用组件
用户切换 Tab各种情况请参考下表 重启动 页面全部出栈,只留下新的页面 调用 API wx.reLaunch
使用组件onUnload onLoad, onShow 3.代码示例
wx.navigateTo({ //当前页面被隐藏,缓存在栈中,最多存放10个页面 url: "/pages/posts/post" //跳转的页面路径 }) wx.redirectTo({ //当前页面被销毁 url: "/pages/posts/post" })
4.Tab 切换对应的生命周期(以 A、B 页面为 Tabbar 页面,C 是从 A 页面打开的页面,D 页面是从 C 页面打开的页面为例):
当前页面 路由后页面 触发的生命周期(按顺序) A A Nothing happend A B A.onHide(), B.onLoad(), B.onShow() A B(再次打开) A.onHide(), B.onShow() C A C.onUnload(), A.onShow() C B C.onUnload(), B.onLoad(), B.onShow() D B D.onUnload(), C.onUnload(), B.onLoad(), B.onShow() D(从转发进入) A D.onUnload(), A.onLoad(), A.onShow() D(从转发进入) B D.onUnload(), B.onLoad(), B.onShow()
navigateTo
,redirectTo
只能打开非 tabBar 页面。switchTab
只能打开 tabBar 页面。reLaunch
可以打开任意页面。- 页面底部的 tabBar 由页面决定,即只要是定义为 tabBar 的页面,底部都有 tabBar。
- 调用页面路由带的参数可以在目标页面的
onLoad
中获取。
1.创建文件夹 命名NavHeader
2.新建Component 命名NavHeader
// components/NavHeader/NavHeader.json { "component": true,// 1.将 component 字段设为 true 可将这一组文件设为自定义组件 "usingComponents": { "NavHeader" : "/components/NavHeader/NavHeader"//注册 } }
// components/NavHeader/NavHeader.wxml //2.在 wxml 文件中编写组件模板,在 wxss 文件中加入组件样式,它们的写法与页面的写法类似。具体细节和注意事项参见 组件模板和样式 。 <view class="header"> <text class="title">{{title}}text> <view> <text>{{nav}}text> <text class="more">查看更多text> view> view>
//components/NavHeader/NavHeader.wxss ///* 3.这里的样式只应用于这个自定义组件 */ .header{ padding-bottom: 20rpx; } .header .title{ font-size: 32rpx; line-height: 80rpx; color: #666; } .header .more{ float: right; border: 1rpx solid #333; padding: 10rpx 20rpx; font-size: 24rpx; border-radius: 30rpx; }
注意:在组件wxss中不应使用ID选择器、属性选择器和标签名选择器。
在自定义组件的
js
文件中,需要使用Component()
来注册组件,并提供组件的属性定义、内部数据和自定义方法。组件的属性值和内部数据将被用于组件
wxml
的渲染,其中,属性值是可由组件外部传入的。更多细节参见 Component构造器 。// components/NavHeader/NavHeader.js Component({ /** *4.组件的属性列表 两个默认值 使用时传入参数 */ properties: { title:{ type:String, value:'title默认值' }, nav:{ type:String, value:'nav默认值' } }, /** * 组件的初始数据 */ data: { }, /** * 组件的方法列表 */ methods: { } })
使用自定义组件需要在相对于 json文件中引用
//5. { "usingComponents": { "NavHeader" : "/components/NavHeader/NavHeader" } }
1、swiper 滑块视图容器。其中只可放置swiper-item组件,否则会导致未定义的行为。
2、swiper-item 仅可放置在swiper组件中,宽高自动设置为100%。xun’hua
属性 | 类型 | 默认值 | 必填 | 说明 | 最低版本 |
---|---|---|---|---|---|
indicator-dots | boolean | false | 否 | 是否显示面板指示点 | 1.0.0 |
indicator-color | color | rgba(0, 0, 0, .3) | 否 | 指示点颜色 | 1.1.0 |
indicator-active-color | color | #000000 | 否 | 当前选中的指示点颜色 | 1.1.0 |
autoplay | boolean | false | 否 | 是否自动切换 | 1.0.0 |
circular | boolean | false | 否 | 是否采用衔接滑动 | 1.0.0 |
详情见官网说明----->视图容器/swiper
分为
应⽤⽣命周期
和⻚⾯⽣命周期
关于小程序前后台的定义和小程序的运行机制,请参考运行机制章节。
1.页面生命周期表
属性 | 类型 | 说明 |
---|---|---|
data | Object | 页面的初始数据 |
options | Object | 页面的组件选项,同 Component 构造器 中的 options ,需要基础库版本 2.10.1 |
onLoad | function | 生命周期回调—监听页面加载 |
onShow | function | 生命周期回调—监听页面显示 |
onReady | function | 生命周期回调—监听页面初次渲染完成 |
onHide | function | 生命周期回调—监听页面隐藏 |
onUnload | function | 生命周期回调—监听页面卸载 |
onPullDownRefresh | function | 监听用户下拉动作 |
onReachBottom | function | 页面上拉触底事件的处理函数 |
onShareAppMessage | function | 用户点击右上角转发 |
onShareTimeline | function | 用户点击右上角转发到朋友圈 |
onAddToFavorites | function | 用户点击右上角收藏 |
onPageScroll | function | 页面滚动触发事件的处理函数 |
onResize | function | 页面尺寸改变时触发,详见 响应显示区域变化 |
onTabItemTap | function | 当前是 tab 页时,点击 tab 时触发 |
2.示例代码
//index.js Page({ data: { text: "This is page data." }, onLoad: function(options) { // Do some initialize when page load. }, onShow: function() { // Do something when page show. }, onReady: function() { // Do something when page ready. }, onHide: function() { // Do something when page hide. }, onUnload: function() { // Do something when page close. }, onPullDownRefresh: function() { // Do something when pull down. }, onReachBottom: function() { // Do something when page reach bottom. }, onShareAppMessage: function () { // return custom share data when user share. }, onPageScroll: function() { // Do something when page scroll }, onResize: function() { // Do something when page resize }, onTabItemTap(item) { console.log(item.index) console.log(item.pagePath) console.log(item.text) }, // Event handler. viewTap: function() { this.setData({ text: 'Set some data for updating view.' }, function() { // this is setData callback }) }, customData: { hi: 'MINA' } })
wx.request(Object object)
以 Promise 风格 调用:不支持
小程序插件:支持,需要小程序基础库版本不低于 1.9.6
发起 HTTPS 网络请求。使用前请注意阅读相关说明。
必要参数
url
开发者服务器接口地址
接口说明说明: 调用此接口 , 可获取 banner( 轮播图 ) 数据
➢ 接口地址 : /banner
➢ 请求方式: GET
➢ 可选参数 :type:资源类型,对应以下类型,默认为 0 即 PC
- 0 PC
- 1 android
- 2 iphone
- 3 ipa
代码示例
wx.request({ url: 'http://localhost:3000/banner',//请求路径 data: {type:2},//携带参数 success: (res)=>{//成功回调 console.log('请求成功',res) }, fail:(err) => {//失败回调 console.log('请求失败',err) } })
使用封装后代码示例
data: { bannerList:[],// 轮播图数据 recommendList:[],// 推荐歌单 topList:[],// 排行榜数据 }, Page({ /** * 页面的初始数据 */ data: { bannerList:[],// 轮播图数据 }, /** * 生命周期函数--监听页面加载 */ onLoad: async function (options) { //0 PC 1 android 2 iphone 3 ipad let bannerListData = await request('/banner',{type:2}); this.setData({ bannerList:bannerListData.banners }) }
wx.setStorageSync(string key, any data) | 微信开放文档 (qq.com)
示例代码
存储
import request from '../utils/request' async login(){ //1.收集表单项数据 let {phone,password} = this.data if(!phone){ //提示用户 wx.showToast({ title: '手机号不能为空', icon:'none' }) return; } //定义正则表达式 let phoneReg = /^1(3|4|5|6|7|8|9)\d{9}$/; if(!phoneReg.test(phone)){ wx.showToast({ title: '手机号格式错误', icon:'none' }) return; } if(!password){ wx.showToast({ title: '密码不能为空', icon:'none' }) return; } //后端验证 let result = await request('/login/cellphone',{phone,password}) if(result.code === 200){ //登录成功 wx.showToast({ title: '登录成功', }) //将用户的信息存储至本地 wx.setStorageSync('userInfo', JSON.stringify(result.profile)) //转成字符串 //跳转至个人中心personal页面 wx.reLaunch({ url: '/pages/personal/personal', }) }else if(result.code === 501){ wx.showToast({ title:'手机号错误', icon:'none' }) }else if(result.code === 502){ wx.showToast({ title:'密码错误', icon:'none' }) }else{ wx.showToast({ title:'登录失败', icon:'none' }) } }
取出
import request from '../utils/request' /pages/personal/personal.js 文件 /** * 生命周期函数--监听页面加载 */ onLoad: function (options) { //读取用户基本信息 let userInfo = wx.getStorageSync('userInfo'); //console.log('userInfo:',userInfo)//字符串 //userId:536011793 ///user/record?uid=536011793&type=1 if(userInfo){ //更新userInfo状态 this.setData({ userInfo:JSON.parse(userInfo) }) //console.log(this.data.userInfo.userId) //获取用户播放记录 this.getUserRecentPlayList(this.data.userInfo.userId) } },
由于程序请求通常使用较多所以把请求功能函数封装
代码示例
export default{ host:'http://localhost:3000', mobilehost:'http://5fdswm.natappfree.cc' }
//发送ajax请求 /* 1.封装功能函数 1.功能点明确 2.函数内部应该保留固定代码(静态的) 3.将动态的数据抽取成形参,由使用者根据自身的情况动态传入实参 2. 封装功能组件 1.功能点明确 2.组件内部保留静态的代码 3.将动态的数据抽取成props参数,由使用者根据自身的情况以标签属性的形式动态传入props数据 4.一个良好的组件应该设置组件的必要性及数据类型 */ import config from './config' //引用路径配置 拼接 export default(url,data={},method='GET') => { return new Promise((resolve,rejext) => { // 1.new Promise初始化promise实例的状态为pending wx.request({ url:config.host+url,//本地host 内网穿透mobilehost data, method, success: (res)=>{ //console.log('请求成功',res); resolve(res.data);//reso;ve修改promise的状态为成功的状态resolved }, fail:(err) => { //console.log('请求失败',err); rejext(err);//rejext修改promise的状态为失败状态 rejected } }) }) }
#在命令行参数模式如 natapp -authtoken=xxx 等相同参数将会覆盖掉此配置
#命令行参数 -config= 可以指定任意config.ini文件
[default]
authtoken= 46b400d3b504d011 #对应一条隧道的authtoken
clienttoken= #对应客户端的clienttoken,将会忽略authtoken,若无请留空,
log=stdout #log 日志文件,可指定本地文件, none=不做记录,stdout=直接屏幕输出 ,默认为none
loglevel=ERROR #日志等级 DEBUG, INFO, WARNING, ERROR 默认为 DEBUG
http_proxy= #代理设置 如 http://10.123.10.10:3128 非代理上网用户请务必留空
http://localhost:4040/http/in
获取本次外网地址
访问
更改小程序请求路径配置后使用手机端真机调试
示例代码
<scroll-view scroll-x="true" class="navScroll" enable-flex="true">
<view class="navItem">
<view class="navContent">
推荐
view>
view>
<view class="navItem">
<view class="navContent active">
世界上的另一个我
view>
view>
<view class="navItem">
<view class="navContent">
推荐
view>
view>
<view class="navItem">
<view class="navContent">
世界上的另一个我
view>
view>
<view class="navItem">
<view class="navContent">
推荐
view>
view>
<view class="navItem">
<view class="navContent">
世界上的另一个我
view>
view>
<view class="navItem">
<view class="navContent">
推荐
view>
view>
<view class="navItem">
<view class="navContent">
世界上的另一个我
view>
view>
<view class="navItem">
<view class="navContent">
推荐
view>
view>
<view class="navItem">
<view class="navContent">
世界上的另一个我
view>
view>
scroll-view>
/*导航区域 wxss*/
.navScroll{
display: flex;
white-space: nowrap;/*规定段落中的文本不进行换行*/
height: 60rpx;
}
.navScroll .navItem {
padding: 0 30rpx;
font-size: 28rpx;
height: 60rpx;
line-height: 60rpx;
}
.navScroll .navContent {
height: 60rpx;
box-sizing: border-box;
}
.navItem .active {
border-bottom: 1rpx solid #d43c33;
}