1.运行环境不同,网页运行在浏览器的环境,小程序在微信环境中
2.API不同,小程序没有DOM,BOM,但是可以提供各种API进行定位,扫码,支付
3.开发模式不同,小程序开发账号,开发工具
4.不需要下载就可以使用,(实际是包很小 下载很快看不出来下载)
setting 中保存了编译相关的配置
projectname 中保存的是项目名称
appid 中保存的是小程序的账号 ID
微信现已开放小程序内搜索,效果类似于 PC 网页的 SEO。sitemap.json 文件用来配置小程序页面是否允许微信索引。
当开发者允许微信索引时,微信会通过爬虫的形式,为小程序的页面内容建立索引。当用户的搜索关键字和页面的索引匹配成功的时候,小程序的页面将可能展示在搜索结果中。
(注意: 默认开启的,如需要关闭 sitemap 的索引提示,可在小程序项目配置文件 project.config.json 的 setting 中配置字段 checkSiteMap 为 false
)
用于设置小程序的状态栏、导航条、标题、窗口背景色。
navigationBar系列 | Value |
---|---|
navigationBarBackgroundColor | 导航栏背景颜色,如 #000000 |
navigationBarTextStyle | 导航栏标题颜色,仅支持 black / white |
navigationBarTitleText | 导航栏标题文字内容 |
navigationStyle | 导航栏样式(仅支持以下值:default 默认,custom 自定义,只保留右上角胶囊按钮) |
background系列 | Value (开启下拉刷新显示) |
---|---|
backgroundColor | 窗口的背景色 |
backgroundTextStyle | 下拉 loading 的样式,(仅支持 dark / light) |
其他 | Value |
---|---|
enablePullDownRefresh | 是否开启全局的下拉刷新(true/false)。(数据更新后关闭下拉刷新:wx.stopPullDownRefresh()) |
onReachBottomDistance | 页面上拉触底事件触发时距页面底部距离,50px。 |
如果小程序是一个多 tab 应用(客户端窗口的底部或顶部有 tab 栏可以切换页面),可以通过 tabBar 配置项指定 tab 栏的表现,以及 tab 切换时显示的对应页面。
项目 | Value |
---|---|
color | 文字默认颜色,仅支持十六进制颜色 |
selectedColor | 文字选中时的颜色,仅支持十六进制颜色 |
backgroundColor | 背景色,仅支持十六进制颜色 |
borderStyle | tabbar 上边框的颜色, 仅支持 black / white |
list | tab 的列表,详见 list 属性说明,最少 2 个、最多 5 个 tab |
position | tabBar 的位置,仅支持 bottom / top |
custom | 自定义 tabBar,见详情 |
其中 list 接受一个数组,只能配置最少 2 个、最多 5 个 tab。tab 按数组的顺序排序,每个项都是一个对象,其属性值如下:
项目 | Value |
---|---|
pagePath | 页面路径,必须在 pages 中先定义 |
text | tab 上按钮文字 |
iconPath | 图片路径,icon 大小限制为 40kb,建议尺寸为 81px * 81px,不支持网络图片。当 position 为 top 时,不显示 icon。 |
selectedIconPath | 选中时的图片路径,icon 大小限制为 40kb,建议尺寸为 81px * 81px,不支持网络图片。当 position 为 top 时,不显示 icon。 |
WXML是小程序框架设计的一套标签语言,用来构建小程序页面结构,相当于HTML
一套样式语言
rpx尺寸单位,只支持部分css选择器
在dpr为2的情况下1px等于2rpx
375设计稿1px=2
网页运行在浏览器中,小程序运行在微信中
小程序的运行环境分成渲染层和逻辑层,其中 WXML 模板和 WXSS 样式工作在渲染层,JS 脚本工作在逻辑层。其中,渲染层和逻辑层分别由2个线程管理:渲染层的界面使用了WebView 进行渲染;逻辑层采用JsCore线程运行JS脚本。
// page.js
Page({
data: {
message: 'Hello MINA!',
classname:'active'
}
})
<view> {{message}} </view>
<view class="{{classname}}"> 123</view>//属性绑定
data: {
name:'张三'
},
this.setData({
name:'李四'
})
data: {
user_info:{
name: 'li',
age: 10
},
cars:['nio', 'bmw', 'wolks']
},
this.setData({
['user_info.age']: 20,
['cars[0]']: 'tesla'
})
<view wx:if="{{length > 5}}"> 1 </view>
<view wx:elif="{{length > 2}}"> 2 </view>
<view wx:else> 3 </view>
<view hidden="{{true}}">123</view>
hidden | wx:if |
---|---|
hidden控制display属性,如选项卡 | 控制渲不渲染, 如以上来决定显不显示 |
有更高的初始渲染消耗 | if有更高的切换消耗 |
data:[
{id:'001',message:'a'},
{id:'002',message:'b'}
]
<view wx:for="{{array}}" wx:for-index="idx" wx:for-item="itemName" wx:key="id">
{{idx}}: {{itemName.message}}
</view>
(*this 选中选项可以跟随变化)
*this 代表在 for 循环中的 item 本身,这种表示需要 item 本身是一个唯一的字符串或者数字
(index 选中选项不跟随变化)
并不是一个组件,它仅仅是一个包装元素,不会在页面中做任何渲染,只接受控制属性。
wx:if vs hidden
用于重复的静态资源,不像component
1.创建tmp组件存放目录,内部包含wxml和wxss文件
2.用template标签定义一个代码片段,使用name属性指定模板的名称
//tmp1.wxml
<template name="a">
<view>
<image src="{{item.img}}"></image>
<text>{{item.name}}</text>
</view>
</template>
<view>111</view>
2.引入模板的样式,使用@import
//page1.wxss
@import '/tmp/tmp1/tmp1.wxss';
3.引入模板结构并且使用
//page1.wxml
<import src="/tmp/tmp1/tmp1"></import>//import:用来引用模板文件里面定义的模板内容块
<include src="/tmp/tmp1/tmp1">//include:用来引用目标文件内除了模板代码块的其他内容,显示111 的内容
<block wx:for="{{list}}" wx:key="id">
<template is="a" data="{{item}}"></template>
</block>
使用 is 属性声明需要的使用的模板利用data属性向模板传入需要的数据信息
WXML 提供两种文件引用方式 import和include
import可以在该文件中使用目标文件定义的template
<import src="item.wxml"/>
<template is="item" data="{{text: 'forbar'}}"/>
include 可以将目标文件除了 template , wxs外的整个代码引入,相当于是拷贝到 include 位置
<include src="header.wxml"/>//111
<template name="lis">
<view class="lis">
<image src="{{item.img}}"></image>
<text>{{item.name}}</text>
</view>
</template>
<view>111</view>
事件 | Value |
---|---|
tap | 类似click |
input | 文本框输入(获取值:e.detail.value) |
change | checkbox-group中选中项发生改变时,detail = {value:[选中的 checkbox 的value的数组]} |
touchstart | 手指触摸动作开始 |
touchmove | 手指触摸后移动 |
touchcancel | 手指触摸动作被打断,如来电提醒,弹窗 |
touchend | 手指触摸动作结束 |
除 bind 外,也可以用 catch 来绑定事件。与 bind 不同, catch 会阻止事件向上冒泡。
<view catchtap="tapName"> Click me! </view>
event | Value |
---|---|
type | 事件类型 |
target | 触发事件组价的属性值集合 |
currenttarget | 事件绑定的当前组件 |
detail | 额外信息 |
touches | 触摸点信息 |
targetTouches | 当前元素目标上的触摸点 |
changedTouches | 发生改变的触摸点,几个手指发送了变化 |
<view id="tapTest" data-hi="Weixin" bindtap="tapName" mark:id="1001"> Click me! </view>
tapName(e){
e.currentTarget.dataset.hi //Weixin
e.mark.id //1001
}
(为什么不用target是因为嵌套多了不一定点到元素),注意驼峰命名和-命名会转变
target是触发事件的元素,事件会冒泡到父级元素去,
currentTarget是绑定事件的元素
e.currentTarget.dataset.名字
e.mark.名字
命名不会大小写转换
mark | dataset |
---|---|
mark 会包含从触发事件的节点到根节点上所有的 mark: 属性值 | dataset 仅包含一个节点的 data- 属性值。 |
如果存在同名的 mark ,父节点的 mark 会被子节点覆盖。 | |
在自定义组件中接收事件时, mark 不包含自定义组件外的节点的 mark 。 | |
不会字符和大小写转换 | 会大小写转换 |
项目 | Value |
---|---|
view | 相当于div |
swiper | 滑块视图容器,只可放置swiper-item组件(轮播图) |
swiper-item | 仅可放置在swiper组件中,宽高自动设置为100%(滚动列表),scroll-x,scroll-y |
scroll-view | 可滚动视图区域 |
movable-area | 可移动区域 |
movable-view | 可移动容器,direction=‘all、vertical、horizontal、none’,bindchange拖动过程中触发的事件 |
text | 文本(长按选中文本,selectable) |
rich-text | 通过nodes属性把字符串渲染成对应ui结构 |
button | 按钮 open-type属性可以调用微信提供的功能 |
navigator | 导航相当于a |
image | 图片默认300*240 (mode属性指定模式,scaleToFill宽高拉伸填满,aspectFit图片长边显示,aspectFill图片短边,widthFix宽不变高自适应,heightFix高不变宽自适应) |
input | 输入框 |
picker | 从底部弹起的滚动选择器。 |
picker-view | 嵌入页面的滚动选择器。其中只可放置 picker-view-column组件,其它节点不会显示。 |
progress | 进度条percent(百分比0~100),stroke-width="4"宽度, activeColor="red"已走颜色 |
swiper
indicator-dots 指示点
indicator-color 指示点颜色
indicator-active-color 当前选中的指示点颜色
autoplay 是否自动切换
interval 自动切换时间间隔
duration 滑动动画时长
circular 是否采用衔接滑动
input
value 输入框的初始内容
type input 的类型
password 是否是密码类型
placeholder输入框为空时占位符
disabled是否禁用
maxlength 最大输入长度,设置为 -1 的时候不限制最大长度
confirm-type设置键盘右下角按钮的文字,仅在type='text’时生效(send 右下角按钮为“发送”,search 右下角按钮为“搜索”,next 右下角按钮为“下一个”,go 右下角按钮为“前往”,done 右下角按钮为“完成”)
bindinput eventhandle键盘输入时触发,
bindconfirm 点击完成按钮时触
可移动的视图容器,在页面中可以拖拽滑动。movable-view必须在 movable-area 组件中,并且必须是直接子节点,
项目 | Value |
---|---|
direction | movable-view的移动方向,属性值有all、vertical(垂直)、horizontal(水平) |
x | x偏移 |
y | y偏移 |
bindchange | 拖动过程中触发的事件,event.detail = {x, y, source} |
通过e.detail.source==‘touch’判断是否是拖拽过去的
项目 | Value |
---|---|
scroll-x | 允许横向滚动 |
scroll-y | 允许纵向滚动 |
scroll-top | 设置竖向滚动条位置 |
scroll-left | 设置横向滚动条位置 |
scroll-with-animation | 在设置滚动条位置时使用动画过渡 1.0.0 |
refresher-enabled | 开启自定义下拉刷新 |
bindrefresherrefresh | 自定义下拉刷新被触发 |
refresher-triggered | 设置当前下拉刷新状态,true 表示下拉刷新已经被触发,false 表示下拉刷新未被触发 |
bindscroll | 滚动时触发,event.detail = {scrollLeft, scrollTop, scrollHeight, scrollWidth, deltaX, deltaY} |
bindscrolltolower | 滚动到底部/右边时触发 |
scroll-view要设置 scroll-x=“true” style=" white-space: nowrap;"
子组件设置style=“display: inline-block”
<scroll-view class="t2" scroll-x="true"
style=" white-space: nowrap; display: flex" >
<view class="t2" style="display: inline-block"></view>
<view class="t2" style="display: inline-block"></view>
<view class="t2" style="display: inline-block"></view>
</scroll-view>
必须设置高度
<scroll-view scroll-y >
<view>1</view>
<view>2</view>
<view>3</view>
</scroll-view>
WXS(WeiXin Script)是小程序的一套脚本语言
//注意:函数内判断是否有值,没有就return要不会报错
function fnA(str){
if(!str){return}//注意:判断时候有值,没有就return要不会报错
return str+'A'
}
module.exports = {//导出
//必须用key:value的写法
fnA:fnA
};
{{m1.fnA(123)}}
<wxs module="m1" src="/util/1.wxs"></wxs>
<view>{{wxs1.reverse(123)}}</view>
<wxs module="wxs1">
function reverse(str){
if(!str){
return
}
return str+'1111111'
}
module.exports={reverse:reverse}
</wxs>
//2.wxs
function fnB(str){
return str+'B'
}
module.exports = {
fnB:fnB
};
//1.wxs 1里面引入2
var fnA=require('./2.wxs')
function fnB(str){
return str+'B'
}
module.exports = {
fnB:fnB
fnA:fnA.fnA
};
//page.wxml
<wxs></wxs>
<navigator open-type="" url="/pages/home/home"></navigator>
传参:url=“/pages/home/home?id=10”
open-type | Value |
---|---|
navigate | 对应 wx.navigateTo 或 wx.navigateToMiniProgram (跳转普通页面) |
redirect | 对应 wx.redirectTo |
switchTab | 对应 wx.switchTab (跳转tabBar页面) |
reLaunch | 对应 wx.reLaunch |
navigateBack | 对应 wx.navigateBack 或 wx.navigateBackMiniProgram |
项目 | Value |
---|---|
事件监听 | 以on开头监听事件触发 (wx.onWIndowResize())窗口大小 |
同步 | 以sync结尾 (wx.setStorageSync(‘key’,‘value’))本地存储输入内容 |
异步 | 类似于jq中的$.ajax,需要success来接收结果(wx.request())网络请求 |
保留当前页面,跳转到应用内的某个页面。但是不能跳到 tabbar 页面。使用 wx.navigateBack 可以返回到原页面。小程序中页面栈最多十层
// 隐藏当前页面,跳转非tabBar页面
// 传值:?后面传入数据多个数据用&链接
// 取值,在另一个页面onLoad函数参数中取值
wx.navigateTo({
url: '/pages/page6/page6?id=1001',
})
卸载当前页面跳转,不允许跳转到 tabbar 页面。
// 卸载当前页面跳转,不允许跳转到 tabbar 页面。
wx.redirectTo({
url: '/pages/page6/page6?id=1002',
})
// 卸载当前页面,跳tabbar页面,不能传参
wx.switchTab({
url: '/pages/page1/page1',
})
关闭所有页面,打开到应用内的某个页面,可以打开tabBar页面
//卸载当前页面,跳转应用中任意页面,可穿值
wx.reLaunch({
url: '/pages/page4/page4?id=1',
})
关闭当前页面,返回上一页面或多级页面。可通过 getCurrentPages 获取当前的页面栈,决定需要返回几层。如果 delta 大于现有页面数,则返回到首页。
项目 | Value |
---|---|
navigateTo | 页面不是很多,推荐wx.navigateTo,后退不需要重新渲染 |
redirectTo | 相当于重定向跳转,销毁当前的页面 |
reLaunch | 销毁内存中所有保留的页面 |
官方规定小程序最多只能有五个页面同时存在,意思是在不关闭页面的情况下,最多新开五个页面,页面深度为5。
wx.navigateTo会增加页面栈大小,直到页面栈大小为5,wx.redirectTo不会增加页面栈大小;wx.navigateBack会减少页面栈大小,直到页面栈大小为1
wx.showLoading({
title: '加载中...',
mask:true, // 设置蒙层,下面的东西不能点
})
setTimeout(()=>{
wx.hideLoading()
},3000)
wx.showToast({
title: '警告',
icon:'error',
duration:3000,
mask:true,
image:'/images/jd1.png'
})
setTimeout(()=>{
wx.hideToast()
},1000)
//方式一:利用回调函数拿到模态框执行结果
wx.showModal({
title:'删除',
content:'您确认删除吗',
success:(res)=>{
if(res.confirm){
console.log('点击了确认按钮')
}
}
})
// 方式二:利用promise.then拿到模态框结果
wx.showModal({
title:'删除',
content:"您确定删除吗"
}).then((res)=>{
if(res.confirm){
console.log('点击了确认按钮')
}})
// 方式三:利用async和await (onModal加async),因为showModal支持promise,大部分api都支持promise
async onModal(){
const res= await wx.showModal({
title:'删除',
content:"您确定删除吗",
})
if(res.confirm){
console.log('点击了确认按钮')
}
},
不要在按完取消逻辑下写业务逻辑
async onSheet(){
const res=await wx.showActionSheet({
itemList:['1','2','3']
})
console.log(res.tapIndex)//用户点击的按钮序号,从上到下的顺序,从0开始
},
wx.showNavigationBarLoading()
setTimeout(()=>{
wx.hideNavigationBarLoading()
},3000)
wx.setNavigationBarTitle({
title: '导航栏新标题',
})
wx.setNavigationBarColor({
backgroundColor:'#000000',//仅支持 #ffffff 和 #000000
fontColor:'#ffffff',
animation: {//动画效果
duration: 400,
timingFunc: 'easeIn'
}
})
wx.hideHomeButton()
sync,当数据比较少,不会影响下面的程序的时候用同步
wx.setStorageSync('a', 123)
wx.setStorageSync('obj', {name:123})
wx.setStorage({
key:'car',
data:[{name:'张三',age:12}],
})
const a= wx.getStorageSync('a')
//方法一,利用回调函数取数据
wx.getStorage({
key:'b',
success:(res)=>{
console.log(res.data)
}
})
//方法二:利用promise
wx.getStorage({key:'b'}).then((res)=>{console.log(res.data)})
//方式三:async+await
async get(){
const res=await wx.getStorage({key:'car'})
console.log(res)
}
wx.removeStorageSync('a')
wx.removeStorage({
key: 'b',
})
wx.clearStorageSync()
wx.clearStorage()
const bgm=wx.getBackgroundAudioManager()
Page({})
//app.json
{
"requiredBackgroundModes": ["audio", "location"]
}
项目 | Value |
---|---|
src | 音频的数据源。当设置了新的 src 时,会自动开始播放 |
startTime | 音频开始播放的位置(单位:s)。 |
title | 音频标题,(必填) |
epname | 专辑名 |
singer | 歌手名 |
coverImgUrl | 封面图 URL |
webUrl | 页面链接 |
protocol | 音频协议。 |
playbackRate | 播放速度。范围 0.5-2.0,默认为 1。 |
duration | 当前音频的长度(单位:s) |
currentTime | 当前音频的播放位置(单位:s) |
paused | 当前是否暂停或停止。(只读) |
buffered | 音频已缓冲的时间,仅保证当前播放时间点到此时间点内容已缓冲。(只读 |
onLoad(options) {
// 设置src和title
bgm.title="起风了"//名字
bgm.src="http://music.163.com/song/media/outer/url?id=167827.mp3"//音乐地址,用网络地址
bgm.singer="买辣椒也用卷"//歌手名字
bgm.coverImgUrl="https://scpic.chinaz.net/files/pic/pic9/202009/apic27858.jpg"//封面图
bgm.playbackRate=2.0//播放倍速
setTimeout(()=>{
console.log(bgm.duration)//总时长
console.log(bgm.currentTime)//当前播放时长
console.log(bgm.paused)//是否暂停
},5000)
// 监听背景音乐时间
// 监听背景音频是否可以播放
bgm.onCanplay(()=>{
console.log("音乐可以播放")
})
//2.监听有音乐播放
bgm.onPlay(()=>{
console.log("音乐在播放")
})
//3.监听音乐暂停
bgm.onPause(()=>{
console.log("音乐暂停")
})
//4.监听音乐播放过程
bgm.onTimeUpdate(()=>{
console.log( bgm.currentTime)
})
//5.监听音乐自然播放结束
bgm.onEnded(()=>{
console.log("音乐播完了")
})
//6.音频跳转中
bgm.onSeeking(()=>{
console.log('音频跳转中,请稍后')
})
//7.音乐跳转完成(真机测试)
bgm.onSeeked(()=>{
console.log('音频跳转完')
})
//8.监听下一首播放(真机测试)
bgm.onNext(()=>{
console.log('下一首')
})
},
play(){
bgm.play()//暂停
},
pause(){
bgm.pause()//播放
},
stop(){
bgm.stop()//停止关闭音乐,从头开始播放
},
seek(){
bgm.seek(200)//跳转播放位置
},
bgm | const bgm=wx.getBackgroundAudioManager() |
---|---|
bgm.play() | 播放音乐 |
bgm.pause() | 暂停音乐 |
bgm.seek(number currentTime) | 跳转到指定位置 |
bgm.stop() | 停止音乐 |
bgm.onCanplay(function callback) | 监听背景音频进入可播放状态事件。 但不保证后面可以流畅播放 |
bgm.onWaiting(function callback) | 监听音频加载中事件。当音频因为数据不足,需要停下来加载时会触发 |
bgm.onError(function callback) | 监听背景音频播放错误事件 |
bgm.onPlay(function callback) | 监听背景音频播放事件 |
bgm.onPause(function callback) | 监听背景音频暂停事件 |
bgm.onSeeking(function callback) | 监听背景音频开始跳转操作事件 |
bgm.onSeeked(function callback) | 监听背景音频完成跳转操作事件 |
bgm.onEnded(function callback) | 监听背景音频自然播放结束事件 |
bgm.onStop(function callback) | 监听背景音频停止事件 |
bgm.onTimeUpdate(function callback) | 监听背景音频播放进度更新事件,只有小程序在前台时会回调。 |
bgm.onNext(function callback) | 监听用户在系统音乐播放面板点击下一曲事件(仅iOS) |
bgm.onPrev(function callback) | 监听用户在系统音乐播放面板点击上一曲事件(仅iOS) |
小程序必须使用 HTTPS/WSS 发起网络请求
不支持Promise
开发阶段可以在详情——本地设置中——勾选不校验 就可以避开https
项目 | Value |
---|---|
url | 接口地址 |
data | 请求的参数 |
header | 设置请求的 header |
timeout | 超时时间,单位为毫秒。默认值为 60000 |
method | HTTP 请求方法(OPTIONS,GET ,POST,DELETE )… |
dataType | 返回的数据格式 (json)返回的数据为 JSON.parse后的 |
responseType | 响应的数据类型 (text 响应的数据为文本,arraybuffer 一段二进制数据,用来模拟内存里面的数据) |
success | 接口调用成功的回调函数 |
fail | 接口调用失败的回调函数 |
complete | 接口调用结束的回调函数(调用成功、失败都会执行) |
object.success | 成功的回调函数 |
---|---|
data | 返回的数据 |
statusCode | HTTP 状态码 |
header | HTTP Response Header |
cookies | 返回的 cookies,格式为字符串数组 |
object.fail | 失败的回调函数 |
---|---|
errMsg | 错误信息 |
errno | errno 错误码 |
wx.request({
url: 'http://t.talelin.com/v2/movie/top250',
method:'GET',
data:{
start:0,count:2
},
success:(res)=>{
console.log('数据',res.data)
}
})
//request.js
class Base{
constructor(){
this.baseUrl='http://t.talelin.com/v2/movie/'//基础路径
}
request(url,data={},method="GET"){
return new Promise((resolve,reject)=>{
wx.request({
url: this.baseUrl+url,
data,
method,
success:(res)=>{
// 获取http状态码 只要以2开头就可以
const code=res.statusCode
if(code>=200&&code<300){
resolve(res.data)
}else{
reject(code)
}
},
fail:(err)=>[
//失败两种,服务器没找到,不允许
reject (err)
],
})
})
}
}
export default Base;
//page.js
import Base from '../../utils/request'
const base=new Base()
async getData2(){
const res=await base.request('top250')
console.log(res)
},
onPageScroll(e){
console.log(e)
},
项目 | Value |
---|---|
scrollTop | 滚动到页面的目标位置,单位 px |
duration | 滚动动画的时长,单位 ms |
selector | 选择器(类似于 CSS 的选择器 id,class,子代,后代) |
offsetTop | 偏移距离,需要和 selector 参数搭配使用,可以滚动到 selector 加偏移距离的位置,单位 px |
success | 接口调用成功的回调函数 |
fail | 接口调用失败的回调函数 |
complete | 接口调用结束的回调函数(调用成功、失败都会执行) |
wx.pageScrollTo({
scrollTop: 0,
duration: 300
})
在组件里面用this.createSelectorQuery()
在页面里面用wx.createSelectorQuery()
const query = wx.createSelectorQuery();
集合:const el=query.selectAll(‘.traffic’)
单个:const el= query.select(‘.tripinfotitlelist’)
//1.全部查询(跟上4.)
el.boundingClientRect(()=>{})
//2.自身查询(就不用写第四个)
el.fields({size:true},res=>{
console.log(res)//只查询size属性
}).exec()
size:宽高
daraset:自定义dataset
rect:布局 left,top...
//3.canvas节点查询
el.node((res)=>{}).exec()
query.exec(function (res) {
//res就是 所有标签为mjltest的元素的信息 的数组
});
<canvas type="2d" class="myCanvas">canvas>
<button bindtap="onDrawImg">绘制图形button>
<button bindtap="onDrawImg1">绘制图形1画布变大button>
onDrawImg(){
const query=wx.createSelectorQuery();
const el=query.select('.myCanvas');
el.node((res)=>{
// 获取canvas实例
const canvas=res.node;
// 获取画布绘制环境
const ctx=canvas.getContext("2d");
// 绘制图形
ctx.fillStyle="pink";
ctx.fillRect(50,50,100,100);
// 画圆
ctx.arc(100,100,50,0,2*Math.PI);
ctx.stroke(); // 描边
});
query.exec();
},
onDrawImg1(){
const query=wx.createSelectorQuery();
const el=query.select('.myCanvas');
el.fields({size:true,node:true},(res)=>{
// 获取canvas实例
const canvas=res.node;
// 将画布尺寸设置成跟画板尺寸一样大
canvas.width=res.width;
canvas.height=res.height;
// 获取画布绘制环境
const ctx=canvas.getContext("2d");
// 画扇形
ctx.beginPath();
ctx.moveTo(150,150);
ctx.arc(150,150,100,0,(45*Math.PI)/180,false);
ctx.closePath();
ctx.fill();
});
query.exec();
},
当画板变大时候,画布会自动拉满,图形就会变形
因此要手动修改大小,h5中width和height写在标签内的原因
enablePullDownRefresh:true 在页面.json 或app.json中设置
在页面Page()构造器中的全局事件onPullDownRefresh()处理逻辑
在json中设置背景的样式
API
(1)wx.startPullDownRefresh()触发下拉刷新,调用后触发下拉刷新动画,效果与用户手动下拉刷新一致
(2)wx.stopPullDownRefresh()可以停止当前页面的下拉刷新
需要手动设置wx.stopPullDownRefresh() 下拉窗口才会回去
<scroll-view
scroll-top='{{y}}' //滚动到某个位置
scroll-with-animation //缓冲滚动到某个位置
scroll-y //允许纵向滚动
bindscroll="onScroll" //滚动时候触发:ScrollLeft, scrollTop...
bindscrolltolower="onReachBottom" //触底事件处理函数
refresher-enabled //开启自定义下拉刷新
bindrefresherrefresh="onPullDownRefresh" //下拉刷新处理函数
refresher-triggered="{{flag}}" //下拉刷新的状态控制,用于关闭下拉框
>
<block wx:for="{{list}}" wx:key="*this">
<view class="item">{{item}}</view>
</block>
</scroll-view>
页面 | 局部(scroll-view) |
---|---|
上拉加载 : onReachBottom() | bindscrolltolower=“fn” |
下拉刷新(开启): json/“enablePullDownRefresh”: true, | refresher-enabled |
下拉刷新时间: onPullDownRefresh | bindrefresherrefresh=“fn” |
关闭下拉刷新: wx.stopPullDownRefresh() | refresher-triggered=“{{flag}}” |
项目 | Value |
---|---|
count | 最多可以选择的文件个数(默认9个) |
mediaType | [‘image’, ‘video’]文件类型 |
sourceType | [‘album’, ‘camera’]图片和视频选择的来源 |
camera | 仅在 sourceType 为 camera 时生效,使用前置或后置摄像头 |
object.success 回调函数
tempFiles// 本地临时文件列表
tempFilePath//本地临时文件路径 (本地路径)
size//本地临时文件大小,单位 B
success(res) {
console.log(res.tempFiles.tempFilePath)
console.log(res.tempFiles.size)
}
<button bind:tap="chooseImg">选择本地图片</button>
async chooseImg(){
const res=await wx.chooseMedia({//默认最多9个
count:3
})
const arr=res.tempFiles.map(item=>{//过滤出照片的地址
return item.tempFilePath
})
console.log(arr)
},
bindlongpress=“saveImg”
bindlongpress:手机触摸后超过350ms离开,如果指定回调就用回调,tap事件不会触发
保存图片到系统相册。
saveImg(e){//长按保存图片
const src=e.mark.src
wx.saveImageToPhotosAlbum({
filePath:src ,
})
},
在新页面中全屏预览图片。预览的过程中用户可以进行保存图片、发送给朋友等操作。
wx.previewImage({
current: '', // 当前显示图片的 http 链接
urls: [] // 需要预览的图片 http 链接列表
})
和普通页面的区别
1.组件的json文件要声明component:true
2.组件的js文件调用component()函数,普通页面调用page()
3.组件的方法函数定义在methods中,普通页面和data平级
4.组件生命周期定义在lifetimes
修改样式隔离app.wxss 或页面的 wxss 中使用了标签名选择器(或一些其他特殊选择器)来直接指定样式,这些选择器会影响到页面和全部组件。通常情况下这是不推荐的做法。指定特殊的样式隔离选项 styleIsolation 。
项目 | Value |
---|---|
isolated | 表示启用样式隔离,在自定义组件内外,使用 class 指定的样式将不会相互影响(一般情况下的默认值); |
apply-shared | 表示页面影响自定义组件,但自定义组件不会影响页面; |
shared | 表示页面样式影响自定义组件,自定义组件的样式也会影响页面和其他设置了 apply-shared 或 shared 的自定义组件。(这个选项在插件中不可用。) |
/写法一
Component({
options: {
styleIsolation: 'isolated'
}
})
//写法二在json中
{
"styleIsolation": "isolated"
}
//全局 app.json中
{
"usingComponents":{
"c-text":"components/text/text"
}
}
//局部 页面.json中
{
"usingComponents":{
"c-text":"/components/text/text"
}
}
<c-text></c-text>
//父
<c-book1 book="{{bookData}}"></c-book1>
//子
properties: {
book:Object
},
properties: {//完整定义
book:{
type:Object,
value:{}//默认值
}
},
流程:父组件绑定自定义属性=要传递是数据,子组件在properties中定义该属性,接收传递下来的数据,讲数据绑定到子组件页面上
//父
<c-book1 wx:if="{{flag}}" book="{{bookData}}" bind:getId="fn"></c-book1>
fn(e){
console.log(e.detail)//传来的值
}
//子
<view class="book" bindtap="onTap">
methods: {
onTap(){
//通知父组件事件被触发,携带数据
this.triggerEvent('getId',{id:id},{bubbles:true})
// 第一个参数:父组件的事件名字
//第二个参数:要携带的数据
//第三参数:是否冒泡
},
},
流程:给子组件绑定一个事件,在事件处理程序中利用this.triggerEvent(‘父组件的自定义事件名’,{要传递的数据})激活父组件的自定义事件,在父组件事件处理程序中e.detail拿到数据
lifetimes:{}中写
lifetimes:{} | Value |
---|---|
created(){} | 组件实例被创建 |
attached(){} | 组件进入页面 |
ready(){} | 组件在页面布局完成 |
moved(){} | 组件位置发生变化 |
detached(){} | 组件在页面销毁 |
lifetimes:{
created(){
console.log('组件实例被创建')
},
attached(){
console.log('组件进入页面')
},
ready(){
console.log('组件在页面布局完成')
},
moved(){
console.log('组件位置发生变化')
},
detached(){
//利用wx:if
console.log('组件在页面销毁')
}
}
项目 | Value |
---|---|
show | 组件所在页面被展示时执行 |
hide | 被隐藏时执行 |
resize | 尺寸发生变化时 |
Component({
pageLifetimes:{
hide(){},
show(){},
resize(size){}
}
})
单插槽:组件中利用slot标签占位,使用组件在组件内部写子元素。
//组件.wxml
<c-tag content="{{txt1}}">
<text>+1</text>
</c-tag>
//插槽.wxml
<view>
<!-- 插槽占位符slot -->
<slot></slot>
</view>
多插槽:组件利用slot标签的name属性指定插槽名字,使用时候在组件的js中开启多插槽支持 options:{ //开启多插槽 multipleSlots:true },
使用组件时在组件内部写元素用slot="footer"属性区分
//组件.wxml
<c-tag content="{{txt2}}">
<image src="/images/jd.png" slot="avatar" class="img"></image>
<text slot="add">+1</text>
</c-tag>
//插槽.wxml
<view>
<slot name="avatar"></slot>
<text>{{content}}</text>
<slot name="add"></slot>
</view>
包含组件的属性和方法,声明周期
一个组价可以有多个behavior,behavior也可以引用behavior
export default Behavior({
//组件公共的属性
properties:{
content:String
},
//组件的公共的方法
methods:{
onTap(){
console.log(this.properties.content)
}
},
lifetimes:{}
})
import bh from '../behaviors/bh'
Component({
//整合公共逻辑
behaviors:[bh]
})
//1.wxml 页面
<c-tag1 content="tag1的标题" ex-green="green" img="/images/1.jpg"></c-tag1>
<c-tag1 content="tag1的标题" ex-pink="pink" img="/images/1.jpg"></c-tag1>
//1.wxss 页面
.green{
background-color: chartreuse !important;
}
.pink{
background-color: pink !important;
}
// 组件.wxml
<text class="title ex-green ex-pink" bindtap="onTap">{{content}}</text>
// 组件.js
import bh from '../behaviors/bh'
Component({
//整合公共逻辑
behaviors:[bh],
//接收外部传入的样式类
externalClasses:["ex-green","ex-pink"],
})
//监听单一值
properties: {
a:{
type:Number,
value:0,
observer(newVal,oldVal){
console.log('新值'+newVal+'旧值'+oldVal)
}
},
}
//多个属性用,号隔开
observers:{
'a,b,obj.c':function(newA,newB,newC){
console.log(newA,newB,newC)
},
}
//监听对象的多个属性
observers:{
'obj.**':function(newObj){
console.log(newObj.a)
},
}
详情点链接
"requiredBackgroundModes": ["audio","location"],
"requiredPrivateInfos": [ "getLocation","choosePoi" ],
"permission": {
"scope.userLocation": {
"desc": "你的位置信息将用于小程序位置接口的效果展示"
}
}
const res=await wx.getLocation();
console.log("地理位置",res);
// 获取当前位置的经纬度
const {latitude,longitude}=res;
// 以当前点为中心展开一片地图
wx.openLocation({
latitude,
longitude,
})
项目 | Value |
---|---|
type | wgs84 返回 gps 坐标,gcj02 返回可用于 wx.openLocation 的坐标 |
altitude | 传入 true 会返回高度信息,由于获取高度需要较高精确度,会减慢接口返回速度 |
isHighAccuracy | 开启高精度定位 (true/false) |
highAccuracyExpireTime | 高精度定位超时时间(ms),指定时间内返回最高精度,该值3000ms以上高精度定位才有效果 |
success | 接口调用成功的回调函数 |
success成功回调 | Value |
---|---|
latitude | 纬度,范围为 -90~90,负数表示南纬 |
longitude | 经度,范围为 -180~180,负数表示西经 |
speed | 速度,单位 m/s |
accuracy | 位置的精确度,反应与真实位置之间的接近程度,可以理解成10即与真实位置相差10m,越小越精确 |
altitude | 高度,单位 m |
success回调 | Value |
---|---|
type | 选择城市时,值为 1,选择精确位置时,值为 2 |
city | 城市名称 |
name | 位置名称 |
address | 详细地址 |
latitude | 纬度,浮点数 |
longitude | 经度,浮点数 |
async choosePoint(){
const res=await wx.choosePoi();
console.log("您的位置是",res);
},
项目 | Value |
---|---|
latitude | 纬度 |
longitude | 经度 |
scale | 缩放比例,范围5~18 |
name | 位置名 |
address | 地址的详细说明 |
success | 接口调用成功的回调函数 |
wx.getLocation({
type: 'gcj02', //返回可以用于 wx.openLocation 的经纬度
success (res) {
const latitude = res.latitude
const longitude = res.longitude
wx.openLocation({
latitude,
longitude,
scale: 18
})
}
})
wx.chooseAddress({
success (res) {
console.log(res.userName)//收件人姓名
console.log(res.postalCode)//邮编
console.log(res.provinceName)//一级地址
console.log(res.cityName)//二级地址
console.log(res.countyName)//三级地址
console.log(res.detailInfo)//详细地址
console.log(res.nationalCode)//新选择器详细收获地址
console.log(res.telNumber)//收获地址国家码
}
})
项目 | Value |
---|---|
longitude | 中心经度 1.0.0 |
latitude | 中心纬度 1.0.0 |
markers | 标记点 |
circles | 圆 |
polyline | 路线 |
<map name="myMap"
longitude="{{lng}}"
latitude="{{lat}}"
markers="{{markers}}"
circles="{{circles}}">map>
showMarker(){//展示标记点
const marker={
id:1,
latitude:this.data.lat,
longitude:this.data.lng,
iconPath:'https:....',
width:30,
height:30,
}
this.setData({
markers:[marker],
})
},
showCircle(){//展示圆圈
const circle={
latitude:this.data.lat,
longitude:this.data.lng,
radius:200,
}
this.setData({
circles:[circle],
})
},
//第一步引入腾讯地图
const QQMap=require('../../utils/qqmap-wx-jssdk')
//实例化腾讯地图
const qqmap=new QQMap({key:'DGKBZ-VZ4CV-CETPR-UDGJ5-CO5V6-****'})
async getAddress(){//坐标转地址
const res=await wx.getLocation();
const {latitude,longitude}=res;
//使用腾讯地图将坐标点转为具体地址
qqmap.reverseGeocoder({
location:{latitude,longitude},
success:res=>{
console.log('当前坐标点对应的地址是',res)
}
})
},
qqmap.geocoder({
address:'北京市昌平区......',
success:res=>{
const {lat:latitude,lng:longitude}=res.result.location;
//以当前经纬度展开地图
wx.openLocation({
latitude,
longitude
})
//利用腾讯地图搜索周边
qqmap.search({
keyword:"餐饮",
location:{latitude, longitude},
success:res=>{
console.log('搜索结果',res)
}
})
}
})
//利用腾讯地图搜索周边
qqmap.search({
keyword:"餐饮",
location:{latitude, longitude},
success:res=>{
console.log('搜索结果',res)
}
})
qqmap.getCityList({
success:res=>{
console.log("城市列表",res)
}
})
wx.login({
success (res) {
if (res.code) {
//发起网络请求
wx.request({
url: 'https://example.com/onLogin',
data: {
code: res.code
}
})
} else {
console.log('登录失败!' + res.errMsg)
}
}
})
用户第一次登录之后若再次登录,则进行自动登录或登录态过期需要手动授权登录,自动登录需要检查用户信息及登录态是否过期
wx.checkSession({
success () {
//session_key 未过期,并且在本生命周期一直有效
},
fail () {
// session_key 已经失效,需要重新执行登录流程
wx.login() //重新登录
}
})
wx.getUserProfile({
desc: '用于完善会员资料', // 声明获取用户个人信息后的用途,后续会展示在弹窗中,请谨慎填写
success: (res) => {
this.setData({
userInfo: res.userInfo,
hasUserInfo: true
})
}
})
1.获取身份信息
登录wx.login拿到code码
wx.login({
success:(res)=>{
const code=res.code
wx.request({
url:'登录接口',
data:{code},
success:(res)=>{
//获取身份令牌,保存到本地
const token=res.data.token
wx.setStorageSync('token',token)
}
})
}
})
//获取我的订单列表
wx.request({
url:'订单请求地址',
header:{//因为get在地址栏后面数据不安全,所以在请求头里面携带数据
token:wx.getStorageSync('token')
},
success:(res)=>{
if(验证通过){
//返回订单数据
}else{
//验证不通过(没有token,token过期,权限不够)
重新获取token(走上面12-19的步骤)或者换一个权限高的
}
}
})
见下面
如果第一次用需要注册
//app.js
onLaunch(){
// 初始化云能力
wx.cloud.init({
env:'lianxi-6g94su9j2e6cd4d9'//id
})
}
//页面.js
//获取数据库
const db=wx.cloud.database();
//获取集合
const userList=db.collection("userList")
userList.add({
data:{name:"张三",age:"20",sex:"男"}
})
userList.doc('6842667962df62750a10484a5676d23c').remove()
userList.doc("0a4ec1f962df6289124ce78e2f9a7038").update({
data:{age:23}
})
userList.doc('6842667962df62750a10484a5676d23c').set({
data:{age:20}
})
没有_openid就只读不能改
const res=await userList.get()
console.log(res.data)
const res1=await userList.doc('0a4ec1f962df6289124ce78e2f9a7038').get()
console.log(res1.data)
const res2=await userList.where({
sex:‘男’
}).get()
console.log(res2.data)
const res3=await userList.limit(3).get()
console.log(res3.data)
4.4+4.5可以做分页效果
const res4=await userList.skip(2).get()
console.log(res4.data)
const res5=await userList.orderBy('age','asc').get()
console.log(res5.data)
const res6=await userList.field({name:true}).get()
console.log(res6.data)
//总结:这几个方法可以任意组合 const res7=await userList.where({ sex:'男'}) .orderBy('age','asc') .limit(2) .field({name:true,age:true}) .get() console.log(res7.data)
//先获取数据操作符
const _=db.command;
//条件可以是范围20岁以上的(_.gt(20)大于20)
const res8=await userList.where({ age:_.gt(20)}).get();
console.log("年级超过20岁的同学",res8.data)
和 get() 区别只返回数量,不会返回对象数组
async onTotal(){
const res=await userList.count()
console.log(res)
},
"cloudfunctionRoot": "functions/",
右键新建Node.js云函数
// 云函数入口文件
const cloud = require('wx-server-sdk')
//云能力初始化
cloud.init({
env:'lianxi-6g94su9j2e6c****'
})
// 云函数入口函数
//传入的都在event
exports.main = async (event, context) => {
const s=event.a+event.b
return s
}
// 云函数入口文件
const cloud = require('wx-server-sdk')
cloud.init({
env:'lianxi-6g94su9j2e6cd4d9'
})
//获取数据库
const db=cloud.database()
//获取集合
const userList=db.collection("userList")
// 云函数入口函数
exports.main = async (event, context) => {
return await userList.get()
}
//可以利用success回调/promise.then/async+await拿到数据
wx.cloud.callFunction({//要调用的那个云函数
name:'add',
data:{a:1,b:3},
success:(res)=>{//使用回调拿到
console.log(res)
}
})
wx.cloud.callFunction({
name:'getID',
success:(res)=>{
console.log(res.result)//和数据库的openid相同
}
})
//getID的云函数的index.js
// 云函数入口函数
exports.main = async (event, context) => {
const wxContext = cloud.getWXContext()
return wxContext.OPENID //openid
}
如果上传至同一路径则是覆盖写
项目 | Value |
---|---|
filePath | 要上传文件资源的路径 |
cloudPath | 云存储路径 |
async uploadFiles(){
const res=await wx.chooseMedia();
// 获取多张图片路径数组
const pathArr=res.tempFiles.map(item=>{
return item.tempFilePath;
});
// 创建匹配后缀的正则表达式
const reg= /\.\w+$/;
const arr=[];
pathArr.forEach(path=>{
// 获取当前这张图片的后缀
const suffix=reg.exec(path)[0];
const p= wx.cloud.uploadFile({
filePath:path,
cloudPath:`***/img${Math.random()}${suffix}`,//保存到***下的文件夹里面
})
arr.push(p)
})
//当图片所有图片都成功拿到结果,执行下一次操作
const result=await Promise.all(arr)//上传多个图片要,都上传完才能拿到所有的
const imgArr=result.map((item)=>{
return item.fileID
})
this.setData({imgArr})
},
//选择本地文件
const res = await wx.chooseMessageFile();
console.log("选择结果", res);
// 选择上传的第一个文件
const file = res.tempFiles[0];
// 拿到该文件的名字和路径
const { name, path } = file;
// 将该文件上传至云存储
const result = await wx.cloud.uploadFile({
filePath: path,
cloudPath: "2009b/" + name,
});
console.log("上传结果", result);
const res=await wx.cloud.downloadFile({
fileID:'cloud://lianxi-6***1241440970242.png',})
//res 拿到一个本地的临时id
//将下载的图片保存到相册
wx.saveImageToPhotosAlbum({
filePath: res.tempFilePath,
})
// 打开该文件
wx.openDocument({
filePath: path,
});
wx.cloud.deleteFile({
fileList: [
"cloud://cloud1-7***.docx",
"cloud://cloud1-7gna5m2cd***.jpg",
],
});
async geturl() {
const res = await wx.cloud.getTempFileURL({
fileList: [
"cloud://cloud***477825.jpg",
],
});
console.log("真实链接", res);
},
<view>
<text>a输入的值</text>
<input type="text" confirm-type="search" bindconfirm="onComfirm1"/>
// confirm-type="search" 修改确认按钮文字
//bindconfirm按确认按钮之后
</view>
//App.js
App({
globalData:{
userInfo:123
}
})
整个小程序只有一个 App 实例,是全部页面共享的。开发者可以通过 getApp 方法获取到全局唯一的 App 实例,获取 App 上的数据或调用开发者注册在 App 上的函数。
//组件.js 写法一
onLoad(options) {
getApp().globalData.userInfo=456
getApp().globalData.abc=45555556
console.log(getApp().globalData.userInfo)
},
//组件.js 写法二
var app = getApp();
Page({
...
app.globalData.userInfo
...
});
缓存中的数据一直存在,全局中的数据只在小程序运行的时候存在,关掉之后就没有了,用于存(背景音乐id,是否有歌曲等)
//stars=48
<block wx:for="{{5}}" wx:key="*this">
<image src="{{stars>(index+1)*10?'/images/icon/star.png':'/images/icon/no-star.png'}}"></image>
</block>
//使用wxs
<block wx:for="{{util.toArr(stars)}}">//wxs处理数据传入48返回[ true,true,true,true,false],根据数组判断图片是否显示
<image src="{{item?'/images/icon/star.png':'/images/icon/no-star.png'}}"></image>
</block>
//util.wxs
function toArr(num){
if(!num){
return
}
var arr=[]
var num1=Math.floor(num/10)
for(var i=0;i<num1;i++){
arr.push(true)
}
// arr.fill(false,num1-1)
var num2=5-arr.length
for(var i=0;i<num2;i++){
arr.push(false)
}
return arr
}
module.exports={toArr:toArr}
<view class="v1"></view>
.v1{
width:50rpx;
height: 50rpx;
background-image: url("data:image/svg+xml;base64,PHN2ZyB4bW...");
background-repeat: no-repeat;
background-size: 100% 100%;
}
开发文档地址:https://dev.qweather.com/docs/api/
登录账号->登录控制台->应用管理->创建应用->添加数据key
小程序管理后台->开发>开发管理->开发设置->修改->合法域名配置request字段
<view class="iconfont icon-shoujitaobao"></view>
let dataTime
let yy = new Date().getFullYear()//年
let mm = new Date().getMonth()+1//月
let dd = new Date().getDate()//日
let hh = new Date().getHours()//
let mf = new Date().getMinutes()<10?'0'+new Date().getMinutes():new Date().getMinutes()
let ss = new Date().getSeconds()<10?'0'+new Date().getSeconds():new Date().getSeconds()
dataTime = `${yy}-${mm}-${dd} ${hh}:${mf}:${ss}`;
//2022-10-23 12:23:43
.cont{
display: flex;
justify-content: space-between;
flex-wrap: wrap;
}
// 这里使用伪元素
.cont::after {
display:block;
content: '';
width: 400px;
}
wx.showToast({
title: '123',
icon:'loading',
duration:5000,
success:()=>{
setTimeout(()=>{
wx.showToast({
title: '678',
duration:4000
})
},5000)
}
})