小程序中,不需要主动来引入样式文件;
尺寸单位
rpx
根据屏幕宽度进行自适应,规定所有屏幕宽为750rpx
;
以前用的px
像素,最好改成rpx
,百分比也可以;
text
相当于web的span标签,行内元素,不会换行;
view
相当于web的div标签,块级元素、会换行;
checkbox
就是以前的复选框标签,使用bool
类型充当属性,checked
block
,占位符的标签,写代码的时候可以看到这标签存在,页面渲染,小程序会把它移除掉;当循环某些数据,如果不想额外地加一层外边的标签,就用上block
标签占位;
小程序中使用less
,原生小程序不支持less
;
vscode+Easy Less
vscode
设置中加入以下配置:
"less.compile":{
"outExt": ".wxss"
}
WXML页面里的动态数据,都是来自js文件Page的data,数据绑定就是通过双大括号{{}}
将变量包起来,在WXML页面里将数据值显示出来;
一定要注意小程序中的异步问题,有的语句逻辑没问题,但是异步执行时达不到预期结果!
小程序tabBar
不显示的原因分析:
在微信小程序中启动页面一定要包含在tabBar
中,并且启动页必须是tabBar
的list属性中的第一个元素,才能正常显示,我就是没有把启动页面放进去,所以tabBar
一直显示不出来;
value抓取的是字符串 我怎么转换成数字类型?
你要先判断value里面是不是全部为数字字符串,如果是则用parseInt()
、parseFloat()
或者number()
进行转换,汉字或者英文字母是没法转为数字类型的
微信小程序报错:Cannot read property ‘forceUpdate‘ of undefined
320px
、高度240px
;scaleToFill
强行裁剪,而aspectFit
保持纵横比,完全显示长边;注意,top、bottom
这些都是在box里面图片的位置;
小程序自动支持懒加载,就是滑到这里再加载lazy-load
;图片懒加载,在即将进入一定范围(上下三屏)时才开始加载,默认false
;
swiper
轮播图,滑块视图容器。其中只可放置swiper-item
组件,否则会导致未定义的行为;
如何控制好轮播图的大小:
得到原图大小:a像素 x b像素;
wxss
设定
swiper {
width: 100%;
height: calc(100vw*b/a);
}
image {
width: 100%;
}
设定image根据宽度自适应调整
注意url
要把里面的变成反斜杠/
,并且page
前加一个/
,删除后缀;
https://developers.weixin.qq.com/miniprogram/dev/component/button.html
现在只有企业级小程序才能获取用户手机号!
实现获取用户信息:
getUserProfile
方法:
<button class="login-bn" type='primary' size="mini" open-type="getUserProfile" bindtap='getUserProfile'>
<image src='/assets/images/me.png'>image>
<text>\n授权登录text>
button>
getUserProfile: function (e) {
wx.getUserProfile({
desc: '业务需要',
success: res => {
//拿到信息处理业务
}
})
},
picker滚动选择器,现支持三种选择器,通过mode来区分,分别是普通选择器(mode=selector),时间选择器(mode=time),日期选择器(mode=date),默认是普通选择器。
https://www.php.cn/xiaochengxu-404796.html
我的实现:选择距离范围
<view>
<view>
可签到范围
view>
<picker bindchange="bindPickerChange" value="{{index}}" range="{{array}}">
<view>当前选择:{{array[index]}}view>
picker>
view>
data: {
index: 0,
array: ['50m', '100m', '200m', '500m'],
},
bindPickerChange: function (e) {
console.log('picker发送选择改变,携带值为', e.detail.value)
this.setData({
index: e.detail.value
})
起止时间设定
<view>
<view>选择时间view>
<picker mode="time" value="{{start_time}}" bindchange="bindStartTimeChange">
<view>开始时间:{{start_time}}view>
picker>
<picker mode="time" value="{{end_time}}" bindchange="bindEndTimeChange">
<view>结束时间:{{end_time}}view>
picker>
view>
data: {
// 时间选择
start_time: '07:00',
end_time: '09:00'
},
// 起止时间确定函数
bindStartTimeChange: function (e) {
console.log("开始时间", e.detail.value);
this.setData({
start_time: e.detail.value
})
},
bindEndTimeChange: function (e) {
console.log("结束时间", e.detail.value);
this.setData({
end_time: e.detail.value
})
}
就是把switch、picker、radio等组件封装起来,其实没什么很大的意义,可能我还不会用,暂时就感觉提交和重置有些用;
注意重置函数 formReset() 应该先 setData() 把数据都设置为初始值,然后 this.onLoad() 重新加载页面!
formReset(e) {
// console.log("重置",e.detail.value);
this.setData({
// 活动名
name: "",
// 距离范围
index: 0,
array: ['50m', '100m', '200m', '500m', '1000m'],
distance: "50m",
// 周期
cycle: "",
isOnce: true,
//日期选择
date: new Date().toLocaleDateString(),
// 时间选择
start_time: '07:00',
end_time: '09:00',
// 位置信息
address: "",
m_name: "",
m_latitude: null,
m_longitude: null,
})
this.onLoad()
}
想要通过 变量控制 隐藏/显示 某个按钮,必须把变量放在按钮所在的 view 里面,否则隐藏后,里面即使没有按钮,也会出现view框空着
列表渲染wx:for
wx:for="{{数组或者对象}}" wx:for-item="循环项的名称" wx:for-item="循环项的索引"
<view>
<view wx:for="{{list}}" wx:for-item="item" wx:for-index="index">
索引:{{index}}->值:{{item.name}}
view>
view>
wx:key="唯一值"来提高性能
:
wx:key
绑定一个普通的字符串的时候,那么这个字符串名称,肯定是循环数组中的对象的唯一属性;
wx:key="*this"
表示你的数组是一个普通数组,*this
表示循环项,比如[1,2,3,44,5]
或者['111',223,'ew ds ']
出现数组嵌套循环时,注意一下绑定的名称不要重名;
对象单层循环wx:for="{{数组或者对象}}"
,默认item
表示对象的值;
最好把item
和index
改成value
和key
;
Page({
/**
* 页面的初始数据
*/
data: {
msg:"hello world",
person:{
age:74,
height:145,
weight:200,
name:"富婆"
},
isChecked:false,
list:[
{
id:1,
name:"猪八戒"
},
{
id:2,
name:"天蓬元帅"
},
{
id:3,
name:"悟能"
}
]
},
}
<view>
<view wx:for="{{list}}">索引:{{index}}->值:{{item.name}}view>
<view wx:for="{{person}}">{{index}}->{{item}}view>
view>
添加block
标签后
:
保留当前页面,跳转到应用内的某个页面
wx.navigateTo({
url: 'index'
})
关闭当前页面,跳转到应用内的某个页面
wx.redirectTo({
url: 'index'
})
关闭所有页面,打开到应用内的某个页面
wx.reLaunch({
url: 'index'
})
跳转到 tabBar 页面,并关闭其他所有非 tabBar 页面
wx.switchTab({
url: '/index'
})
wx.showToast 提示框 如果icon
不设置为"none"
则会显示对勾,表示成功;
wx.showToast({
title: '失败',//提示文字
duration:2000,//显示时长
mask:true,//是否显示透明蒙层,防止触摸穿透,默认:false
icon:'success', //图标,支持"success"、"loading"
success:function(){ },//接口调用成功
fail: function () { }, //接口调用失败的回调函数
complete: function () { } //接口调用结束的回调函数
})
wx.showModual提示框,有确定 取消 按钮的提示框,有标题和内容;
wx.showModal({
title: '删除图片',
content: '确定要删除该图片?',
showCancel: true,//是否显示取消按钮
cancelText:"否",//默认是“取消”
cancelColor:'skyblue',//取消文字的颜色
confirmText:"是",//默认是“确定”
confirmColor: 'skyblue',//确定文字的颜色
success: function (res) {
if (res.cancel) {
//点击取消,默认隐藏弹框
} else {
//点击确定
temp.splice(index, 1),
that.setData({
tempFilePaths: temp,
})
}
},
fail: function (res) { },//接口调用失败的回调函数
complete: function (res) { },//接口调用结束的回调函数(调用成功、失败都会执行)
})
wx.showLoading()
注:wx.showLoading 应与 wx.hideLoading 配对使用
wx.hideLoading(Object object)
隐藏 loading 提示框
wx.showActionSheet(Object object)
显示操作菜单
Date.now()
可以获取,但不是序列形式,就是这种1617246508998
;
详细的就是下面:
var myDate = new Date();
myDate.getYear(); //获取当前年份(2位)
myDate.getFullYear(); //获取完整的年份(4位,1970-????)
myDate.getMonth(); //获取当前月份(0-11,0代表1月)
myDate.getDate(); //获取当前日(1-31)
myDate.getDay(); //获取当前星期X(0-6,0代表星期天)
myDate.getTime(); //获取当前时间(从1970.1.1开始的毫秒数)
myDate.getHours(); //获取当前小时数(0-23)
myDate.getMinutes(); //获取当前分钟数(0-59)
myDate.getSeconds(); //获取当前秒数(0-59)
myDate.getMilliseconds(); //获取当前毫秒数(0-999)
myDate.toLocaleDateString(); //获取当前日期
var mytime=myDate.toLocaleTimeString(); //获取当前时间
myDate.toLocaleString( ); //获取日期与时间
注意myDate.toLocaleString( )
得到的是带上午、下午的日期和时间,如果要转换成Fri Apr 02 2021 07:00:30 GMT+0800 (中国标准时间)
这种进行时间的比较,就要这么做:
// 得到当前时间并格式化
var TIME=util.formatTime(new Date())
let time=String(TIME)
console.log(time);
console.log(new Date(time));
选择位置,进去时默认当前位置,这个貌似不用腾讯地图的SDK也能实现
onChangeAddress: function (e) {
wx.chooseLocation()
.then(res => {
// res既包含 address信息,也包含经纬度信息(经纬度需要返回以计算距离)
// console.log(res);
// res.name为地址名称
// console.log(res.name);
this.setData({
m_name: res.name,
address: "( " + res.address + " )",
m_latitude: res.latitude,
m_longitude: res.longitude
})
// console.log(this.data.m_latitude, this.data.m_longitude);
})
},
// index.js
Page({
data: {
text: 'init data',
num: 0,
array: [{text: 'init data'}],
object: {
text: 'init data'
}
},
changeText: function() {
// this.data.text = 'changed data' // 不要直接修改 this.data
// 应该使用 setData
this.setData({
text: 'changed data'
})
},
changeNum: function() {
// 或者,可以修改 this.data 之后马上用 setData 设置一下修改了的字段
this.data.num = 1
this.setData({
num: this.data.num
})
},
changeItemInArray: function() {
// 对于对象或数组字段,可以直接修改一个其下的子字段,这样做通常比修改整个对象或数组更好
this.setData({
'array[0].text':'changed data'
})
},
changeItemInObject: function(){
this.setData({
'object.text': 'changed data'
});
},
addNewField: function() {
this.setData({
'newField.text': 'new data'
})
}
})
新增组件
找到要放入这个组件的页面,进入json
文件导入:
{
"usingComponents": {
"Tabs": "../../components/Tabs/Tabs"
}
}
在wxml
里面把这个组件当作标签使用
;
methods: {
handleItemTap: function (e) {
// console.log(e)
// 获取索引
const index = e.currentTarget.dataset.index;
// 获取data的原数组
let list = this.data.tabs;
//循环处理
list.forEach((v, i) => i == index ? v.isActive = true : v.isActive = false);
this.setData({
tabs: list
})
}
}
<view class="tabs">
<view class="tabs_title">
<view wx:for="{{tabs}}" wx:key="id" class="title_item {{item.isActive?'active':''}}" bindtap="handleItemTap" data-index="{{index}}">
{{item.name}}
view>
view>
<view class="tabs_content">内容view>
view>
[ ].forEach
遍历数组的时候,修改了v,也会导致原数组被修改;let xxx=JSON.parse()
;不要直接修改this.data.数据
父(页面)向子(组件)传递数据
在Tabs.js
的方法中,我要拿到 data 区的数据,但是这里我把它放在了 properties 区,是不是就不能拿到了,实际上可以拿到 它会先在 data 区查找 找不到再去 properties 区;
现在这种情况就是,父传给子,子修改了,但是没传给父,看这个 appdata 里面的 tabs 并没有发生变化,说明子没给父传递最新的数据;
所以这里我修改 子把索引传给父 父再得到索引进行处理 处理函数写在父的 js 文件里;(按道理也能子处理完列表 再传给父列表 )
触发属性名=‘bind’+事件名 然后再等于一个回调函数;这个回调函数在父的 js 中应该被定义;
![在这里插入图片描述](https://img-blog.csdnimg.cn/20210330192144637.png
getBetweenDateStr: function () {
// start 和 end 作为参数
var start='2021-01-01';
var end= '2021-03-01';
var result = [];
var beginDay = start.split("-");
var endDay = end.split("-");
var diffDay = new Date();
var dateList = new Array;
var i = 0;
diffDay.setDate(beginDay[2]);
diffDay.setMonth(beginDay[1] - 1);
diffDay.setFullYear(beginDay[0]);
result.push(start);
while (i == 0) {
var countDay = diffDay.getTime() + 24 * 60 * 60 * 1000;
diffDay.setTime(countDay);
dateList[2] = diffDay.getDate();
dateList[1] = diffDay.getMonth() + 1;
dateList[0] = diffDay.getFullYear();
if (String(dateList[1]).length == 1) {
dateList[1] = "0" + dateList[1]
};
if (String(dateList[2]).length == 1) {
dateList[2] = "0" + dateList[2]
};
result.push(dateList[0] + "-" + dateList[1] + "-" + dateList[2]);
if (dateList[0] == endDay[0] && dateList[1] == endDay[1] && dateList[2] == endDay[2]) {
i = 1;
}
};
console.log(result);
return result;
},
https://blog.csdn.net/haeasringnar/article/details/81223966
var new_date_str = '2017-07-07'.replace(/-/g, '/')
var newdate = new Date(new_date_str)
console.log(newdate)//可以输出对应的日期对象,注意传入字符串也可以是'2017-7-7'
//日期随便放,时间有就行
// 先把-用/代替
var new_time_str1 = '2017-07-07 07:00:00'.replace(/-/g, '/')
var new_time_str2 = '2017-07-07 09:00:00'.replace(/-/g, '/')
var new_time_str = '2017-07-07 08:59:00'.replace(/-/g, '/')
// 转换成时间格式
var newtime1 = new Date(new_time_str1)
var newtime2 = new Date(new_time_str2)
var newtime = new Date(new_time_str)
console.log(newtime1) //可以输出对应的时间对象,注意这里传入的日期可以忽略,随便输入即可,但时间要给定。
console.log(newtime2) //可以输出对应的时间对象,注意这里传入的日期可以忽略,随便输入即可,但时间要给定。
console.log(newtime) //可以输出对应的时间对象,注意这里传入的日期可以忽略,随便输入即可,但时间要给定。
console.log(newtime > newtime1);
substring
stringObject.substring(start,stop)
不取最后一位字符的操作就是stringObject.substring(start,stringObject.length-1)
判断某个变量是否有值,可以直接用if(xxxx)
判断,因为 js 中,没有值亦为 false;
Array(5).fill({name:'linda', age: 18, sex: 1})
//结果
[ { name: 'linda', age: 18, sex: 1 },
{ name: 'linda', age: 18, sex: 1 },
{ name: 'linda', age: 18, sex: 1 },
{ name: 'linda', age: 18, sex: 1 },
{ name: 'linda', age: 18, sex: 1 } ]
var employeesData = [
{ name: "王小明", mobile: "13900008789" },
{ name: "陈霞", mobile: "13900008789" },
{ name: "张悦", mobile: "13900008789" }
]
var queryData = employeesData.filter(function(fp) {
return fp.name === "王小明"
})
console.log(queryData)
注意:queryData是一个数组,并且对它的操作相当于对原数组的操作
js对json数组的操作-查、删、改、增
微信小程序提示 this.setData is not a function 解决方案之一:是因为此时的 this 已不再是全局的 this
微信小程序如何修改指定的 json 数据?
https://segmentfault.com/q/1010000011018876/a-1020000011023388#
传多个参数给另一个页面时,一定要用 & 把参数分割开!
如何在阿里巴巴矢量库中引用相应图标:
进入网站https://www.iconfont.cn/
选择自己要用的图标并加购;
创建项目然后选择Font class
,点击查看在线链接;
生成代码,在浏览器中打开,全选复制;
全局 app.wxss
中导入 @import "./styles/iconfont.wxss"
;
然后就可以在项目任意 .wxml
文件里面使用:
注意 iconfont
是母体,class
里面必须先写这个 再写后面你要用的名称!
http://www.ruanyifeng.com/blog/2015/07/flex-grammar.html
flex 弹性容器
采用 Flex 布局的元素,称为 Flex 容器(flex container),简称"容器"。它的所有子元素自动成为容器成员,称为 Flex 项目(flex item),简称"项目";
容器默认存在两根轴:水平的主轴(main axis)和垂直的交叉轴(cross axis);主轴的开始位置(与边框的交叉点)叫做main start,结束位置叫做main end;交叉轴的开始位置叫做cross start,结束位置叫做cross end;
项目默认沿主轴排列。单个项目占据的主轴空间叫做main size,占据的交叉轴空间叫做cross size;
容器的属性
以下6个属性设置在容器上:
flex-direction
flex-direction属性决定主轴的方向(即项目的排列方向)。
.box {
flex-direction: row | row-reverse | column | column-reverse;
}
row(默认值):主轴为水平方向,起点在左端。
row-reverse:主轴为水平方向,起点在右端。
column:主轴为垂直方向,起点在上沿。
column-reverse:主轴为垂直方向,起点在下沿。
flex-wrap
flex-wrap属性
默认情况下,项目都排在一条线(又称"轴线")上;flex-wrap属性定义,如果一条轴线排不下,如何换行?
.box{
flex-wrap: nowrap | wrap | wrap-reverse;
}
它可能取三个值。
(1)nowrap(默认):不换行。
(2)wrap:换行,第一行在上方。
(3)wrap-reverse:换行,第一行在下方。
flex-flow
flex-flow属性是flex-direction属性和flex-wrap属性的简写形式,默认值为row nowrap;
.box {
flex-flow: || ;
}
justify-content
justify-content属性定义了项目在主轴上的对齐方式;
.box {
justify-content: flex-start | flex-end | center | space-between | space-around;
}
它可能取5个值,具体对齐方式与轴的方向有关。下面假设主轴为从左到右:
flex-start(默认值):左对齐
flex-end:右对齐
center: 居中
space-between:两端对齐,项目之间的间隔都相等。
space-around:每个项目两侧的间隔相等。所以,项目之间的间隔比项目与边框的间隔大一倍。
align-items
align-items属性定义项目在交叉轴上如何对齐;
.box {
align-items: flex-start | flex-end | center | baseline | stretch;
}
它可能取5个值。具体的对齐方式与交叉轴的方向有关,下面假设交叉轴从上到下。
flex-start:交叉轴的起点对齐。
flex-end:交叉轴的终点对齐。
center:交叉轴的中点对齐。
baseline: 项目的第一行文字的基线对齐。
stretch(默认值):如果项目未设置高度或设为auto,将占满整个容器的高度。
align-content
align-content属性定义了多根轴线的对齐方式。如果项目只有一根轴线,该属性不起作用;
.box {
align-content: flex-start | flex-end | center | space-between | space-around | stretch;
}
flex-start:与交叉轴的起点对齐。
flex-end:与交叉轴的终点对齐。
center:与交叉轴的中点对齐。
space-between:与交叉轴两端对齐,轴线之间的间隔平均分布。
space-around:每根轴线两侧的间隔都相等。所以,轴线之间的间隔比轴线与边框的间隔大一倍。
stretch(默认值):轴线占满整个交叉轴。
项目的属性
以下6个属性设置在项目上:
order
order属性定义项目的排列顺序。数值越小,排列越靠前,默认为0;
.item {
order: ;
}
flex-grow
flex-grow属性定义项目的放大比例,默认为0,即如果存在剩余空间,也不放大;
.item {
flex-grow: ; /* default 0 */
}
如果所有项目的flex-grow属性都为1,则它们将等分剩余空间(如果有的话)。如果一个项目的flex-grow属性为2,其他项目都为1,则前者占据的剩余空间将比其他项多一倍;
flex-shrink
flex-shrink属性定义了项目的缩小比例,默认为1,即如果空间不足,该项目将缩小;
.item {
flex-shrink: ; /* default 1 */
}
如果所有项目的flex-shrink属性都为1,当空间不足时,都将等比例缩小。如果一个项目的flex-shrink属性为0,其他项目都为1,则空间不足时,前者不缩小;
负值对该属性无效。
flex-basis
flex-basis属性定义了在分配多余空间之前,项目占据的主轴空间(main size)。浏览器根据这个属性,计算主轴是否有多余空间。它的默认值为auto,即项目的本来大小。
.item {
flex-basis: | auto; /* default auto */
}
它可以设为跟width或height属性一样的值(比如350px),则项目将占据固定空间。
flex
flex属性是flex-grow, flex-shrink 和 flex-basis的简写,默认值为0 1 auto。后两个属性可选。
.item {
flex: none | [ <'flex-grow'> <'flex-shrink'>? || <'flex-basis'> ]
}
该属性有两个快捷值:auto (1 1 auto) 和 none (0 0 auto)。
建议优先使用这个属性,而不是单独写三个分离的属性,因为浏览器会推算相关值。
.item {
flex: none | [ <'flex-grow'> <'flex-shrink'>? || <'flex-basis'> ]
}
该属性有两个快捷值:auto (1 1 auto) 和 none (0 0 auto)。
建议优先使用这个属性,而不是单独写三个分离的属性,因为浏览器会推算相关值。
align-self
align-self属性允许单个项目有与其他项目不一样的对齐方式,可覆盖align-items属性。默认值为auto,表示继承父元素的align-items属性,如果没有父元素,则等同于stretch。
.item {
align-self: auto | flex-start | flex-end | center | baseline | stretch;
}
该属性可能取6个值,除了auto,其他都与align-items属性完全一致。
https://blog.csdn.net/wyll19980812/article/details/115453910
微信小程序修改整个页面背景色:
目的:防止进入页面时每次都要提示登录,记住用户登录状态
关键是 从缓存中获取wx.getStorageSync('user')
,存入缓存:wx.setStorageSync('user', res.userInfo),
如果缓存没有该字段,可以直接判 false ;
onLoad: function (options) {
// 把本地缓存的用户信息给 user 变量
let user = wx.getStorageSync('user')
console.log(user);
// 如果存在本地缓存,直接赋值
if (user) {
this.setData({
user_name: user.nickName,
user_avator_url: user.avatarUrl,
show_button: false
})
}
// 如果没有,则要用户登录,并缓存至本地
else {
var that = this;
wx.showModal({
title: '提示',
content: '您尚未登录,请问是否立即登录',
success: function (res) {
if (res.confirm) {
// 点击确定,调用信息函数
that.getUserProfile()
} else {
console.log('点击取消回调')
}
}
})
}
},
getUserProfile: function () {
wx.getUserProfile({
desc: '授权登录以使用签到功能',
success: res => {
// console.log(res.userInfo);
// 添加至本地缓存,在Storage中可查看
wx.setStorageSync('user', res.userInfo),
this.setData({
show_button: false,
user_name: res.userInfo.nickName,
user_avator_url: res.userInfo.avatarUrl
})
this.onLoad()
}
})
},
本地的轮播图,亦可以用云上的数据!
拿到轮播图API接口;
建立轮播图数组;
在 onLoad 里,发送异步请求获取轮播图数据, wx.request ,设置不校验域名合法性(详情-本地设置-勾选不校验合法域名)最好做一个后台接口,或者使用云开发
拿到数据赋给轮播图数组;
申请开发者密钥(key):申请密钥
开通webserviceAPI服务:控制台 -> key管理 -> 设置(使用该功能的key)-> 勾选webserviceAPI -> 保存
(小程序SDK需要用到webserviceAPI的部分服务,所以使用该功能的KEY需要具备相应的权限)
下载微信小程序JavaScriptSDK,微信小程序JavaScriptSDK v1.1 JavaScriptSDK v1.2
安全域名设置,在小程序管理后台 -> 开发 -> 开发管理 -> 开发设置 -> “服务器域名” 中设置request合法域名,添加https://apis.map.qq.com;
获取当前位置:
// 引入SDK核心类
var QQMapWX = require('../../libs/qqmap-wx-jssdk.js');
var qqmapsdk;
Page({
data: {
latitude: '',
longitude: ''
},
onLoad: function () {
// 实例化API核心类
qqmapsdk = new QQMapWX({
key: 'MC2BZ-AYGLS-ID5OG-6VDXT-CBI5F-KYBOQ'
});
},
onShow: function () {
var that = this;
// 调用接口
wx.getLocation({
type: 'wgs84',
success: function (res) {
console.log(res);
//逆向解析
qqmapsdk.reverseGeocoder({
location: {
latitude: res.latitude,
longitude: res.longitude
},
success: function (result) {
console.log(result);
console.log(result.result.address);
that.setData({
latitude: result.result.location.lat,
longitude: result.result.location.lng
})
}
})
}
})
}
})
在 page 上显示当前位置
把 latitude 和 longitude 就是刚刚得到的经纬度 传到组件上 然后用小程序内置地图显示;
https://segmentfault.com/a/1190000014833073
需求分析: 一些小程序打开后,以文字形式显示用户所在位置,如果用户觉得不准,可以打开地图,在地图上自己选择位置,选择完成后,显示的用户的位置会发生变化.今天我们就来看一下如何实现这个功能
// index.wxml
// 显示位置信息(默认显示自动定位后的位置信息)
<view class='address' bindtap='onChangeAddress'>
{{address}}
view>
// 点击这块可以改变位置(改为自己确定后的地址)
// index.js
var QQMapWX = require('../../libs/qqmap-wx-jssdk.js'); // 首先引入腾讯地图的API
var qqmapsdk;
Page({
/**
* 页面的初始数据
*/
data: {
address: "", // 地址信息
src:"" ,
m_latitude: null,
m_longitude: null
},
/**
* 生命周期函数--监听页面加载
*/
onLoad: function (options) {
/*
判断是第一次加载还是从position页面返回
如果从position页面返回,会传递用户选择的地点
如果不是从position页面返回,而是第一次进入,则会自动定位用户的位置,显示用户的位置
*/
if (options.address != null && options.address != '') {
//设置变量 address 的值
this.setData({
address: options.address
});
} else {
// 实例化API核心类
qqmapsdk = new QQMapWX({
//此key需要自己申请
key: 'MNXBZ-G5TWD-GY...'
});
var that = this;
// 调用接口
qqmapsdk.reverseGeocoder({
// 这里没有写location选项,是因为默认就是当前位置
success: function (res) {
// 获取默认下的地址
that.setData({
address: res.result.address
});
},
fail: function (res) {
//console.log(res);
},
complete: function (res) {
//console.log(res);
}
});
},
// 点击跳转至
onChangeAddress: function (e) {
wx.navigateTo({
url: "/pages/position/position"
});
}
}
// position.wxml
<view class="page-body">
<view class="page-section page-section-gap">
<map id="qqMap" style="width: 100%; height: 300px;" latitude="{{latitude}}" longitude="{{longitude}}" show-location>map>
view>
view>
// position.js
var QQMapWX = require('../../libs/qqmap-wx-jssdk.js');
var qqmapsdk;
Page({
data: {
latitude: 0,//地图初次加载时的纬度坐标
longitude: 0, //地图初次加载时的经度坐标
name:"" //选择的位置名称
},
onLoad: function () {
// 实例化API核心类
qqmapsdk = new QQMapWX({
key: 'MNXBZ-G5TWD-GYF42-HHZJL-2W2J3-PVBX4'
});
this.moveToLocation();
},
//移动选点
moveToLocation: function () {
var that = this;
// 打开地图选择位置
wx.chooseLocation({
success: function (res) {
// res.name为地址名称
console.log(res.name);
//选择地点之后返回到原来页面
wx.navigateTo({
url: "/pages/index/index?address="+res.name
});
},
fail: function (err) {
console.log(err)
}
});
}
});
这里我稍作了改进,就是我不仅仅要返回 address 还要把 name、latitude、longitude 都返回,我开始想 打包成 json 包整体返回,但是发现这样就把 json 转换成了字符串 麻烦,后来在网上找到了 携带多参数的页面调整解决方案:
小程序wx.navigateTo跳转时传多个参数及获取
就是这个 &
害得我忙活了这么久
moveToLocation: function () {
var that = this;
// 打开地图选择位置
wx.chooseLocation({
success: function (res) {
// res既包含 address信息,也包含经纬度信息(经纬度需要返回以计算距离)
console.log(res);
// res.name为地址名称
// console.log(res.name);
//选择地点之后返回到原来页面
wx.navigateTo({
// 多个参数一定要以 & 分割
url: "/pages/addActivity/addActivity?address=" + res.address + "&latitude=" + res.latitude + "&longitude=" + res.longitude+"&name="+res.name
});
},
fail: function (err) {
console.log(err)
}
});
}
以下为我的实现:目的是在 location 页选择位置后 能将 名称、地址、经纬度这些信息 返回给上一页
// pages/addActivity/addActivity.wxml
<view class='address' bindtap='onChangeAddress'>
{{name}}{{address}}
view>
// pages/addActivity/addActivity.js
var QQMapWX = require('../../libs/qqmap-wx-jssdk.js');
var qqmapsdk;
Page({
/**
* 页面的初始数据
*/
data: {
address: "", // 地址信息
name: "",
m_latitude: null,
m_longitude: null
},
onLoad: function (options) {
// console.log(options);
// 如果我从location页面得到了地址参数,那么直接显示
if (options.address != null && options.address != '') {
this.setData({
name: options.name,
address: '( ' + options.address + ' )',
m_latitude: options.latitude,
m_longitude: options.longitude
})
} else {//如果初次加载,此时地址为空,我要获得当前地址
// 实例化API核心类
qqmapsdk = new QQMapWX({
key: 'MC2BZ-AYGLS-ID5OG-6VDXT-CBI5F-KYBOQ'
});
var that = this;
// 调用接口
qqmapsdk.reverseGeocoder({
// 这里没有写location选项是因为默认就是当前位置
success: function (res) {
that.setData({
address: '( ' + res.result.address + ' )',
name: res.result.formatted_addresses.recommend,
m_latitude: res.result.location.lat,
m_longitude: res.result.location.lng
});
},
fail: function (res) {
// console.log(res);
},
complete: function (res) {
// console.log(res);
}
})
}
},
// 点击跳转至选择地址页面
onChangeAddress: function (e) {
wx.navigateTo({
url: "/pages/position/position"
});
},
// 获得活动名称
getActivityName: function (e) {
},
onShow: function () {
},
})
position.js 就是上面写了的那个
数据量足够多,且现实的20条数据比屏幕要长(把 view 的height 调高点即可)
有页面触底事件处理函数
/**
* 页面上拉触底事件的处理函数
*/
onReachBottom: function () {
console.log("加载更多");
},
数据库方法 collection().skip(n)
跳过n条数据;collection().limit(n)
限制每一页显示n条数据;
完整代码:
onReachBottom: function () {
// 滑动页面加载
console.log("加载更多");
wx.cloud.database().collection('address-book')
.skip(this.data.page_num * 20)
.get()
.then(res => { //请求成功
// console.log("请求成功", res);
console.log(res);
this.setData({
list: this.data.list.concat(res.data),
page_num: this.data.page_num + 1
})
if (res.data.length == 0) {
wx.showToast({
title: '已全部加载完成',
})
}
})
.catch(err => { //请求失败
console.log("请求失败");
})
},
见我的文章:微信小程序实现日历功能(附加签到、迟到、未签的状态显示)
// 扫码签到
handleScanSignIn: function () {
wx.scanCode({
//人到才能扫码,所以禁止相册扫码
onlyFromCamera: true,
scanType: ['barCode', 'qrCode', 'datamatrix', 'pdf417'],
success: res => {
// 需要完善,扫管理员给出的码才算签到成功
if (res.errMsg == 'scanCode:ok') {
wx.showToast({
icon: '',
title: '签到成功'
})
}
},
fail: res => {
// 接口调用失败
wx.showToast({
icon: 'none',
title: '签到失败,请稍后再试!'
})
},
complete: res => {
// 接口调用结束
console.log(res)
}
});
},
参考我的文章:
微信小程序在地图上标点 markers & 画圈显示范围 circles
数据库表 => 集合,集合须为拼音、英文,不能是汉字;
数据库查不到东西可能使权限没开;
进入控制台是管理员,而模拟小程序的使用却不是管理员;
传统方法容易出现 this 指向的问题;
推荐新写法;
addItem: function () {
db.collection('tm_vehicle_info').add({ // .add() 在集合上新增记录
data: {
vehicle_id: 4,
vehicle_name: 'Jeep',
model_code: 2,
speed: 690,
image_url: '/images/vehicle/Jeep.png',
},
success: res => {
console.log(res)
},
fail: err => {
wx.showToast({
icon: "none",
title: '插入记录失败',
})
console.log(err)
}
})
}
update 可以搭配 where 使用,但是 set 不能;update和set是只更新data域提供的数据,该记录其它字段不发生变化!
set的好处就是 有就修改 没有则新增!
testFunction: function () {
wx.cloud.database().collection('address-book').where({
_id: "1"
}).update({
data:{
tel:"12345678912"
}
})
},
所以 索引_id最好是open_id,这样可以直接将微信用户和数据库用户绑定!
https://blog.csdn.net/wyll19980812/article/details/115443374
优势
以获取openid
为例,php
需要很多步:
而云函数只需要两三步;
获得的云数据库记录条数也有优势:
云函数属于管理端,在云函数中运行的代码拥有受限的数据库读写权限和云文件读写权限。需特别注意,云函数运行环境即是管理端。与云函数中的传入的openld
对应的微信用户是否是小程序的管理员/开发者无关。
// 云函数入口文件
const cloud = require('wx-server-sdk')
// 云函数初始化
cloud.init({
// env: 'cloud1-0gbwed2xdbe13cb4' 固定云开发环境
env: cloud.DYNAMIC_CURRENT_ENV //动态获取当前云开发环境
})
云函数调用
每个用户的 openid 都不一样,在创建商品时,可以是管理员1创建,也可以管理员2创建,openid 得以区分;
对于已经部署了的云函数,可以这样调用
onLoad: function (options) {
wx.cloud.callFunction({
// 云函数名 getData
name: "getData",
success(res) {
console.log("请求成功",res);
},
fail(err) {
console.log("请求失败",res);
}
})
},
返回以下信息:
注意 用 then 和 catch 更方便;
其中就包括 openid ;
云函数返回大量数据,而本地只能返回部分;
万一数据库中有几百条怎么整?
云函数获取数据
云函数只要有改动就要重新部署, 否则还是用的之前的版本;
云函数里面有云函数的写法,比如不用wx
写法!
使用云函数时,都能够对数据库进行更新,而小程序直接操作云数据库时只能管理员创建更新,除非修改权限!
要传递的数据在callFunction 中 以data的形式传递,云函数会用 event 来接受数据!
// 通过云函数 addRecord 向 activity-list 传递记录
let parameter = {
_name: this.data.name,
_address: this.data.address,
_distance: this.data.distance,
_start_time: this.data.start_time,
_end_time: this.data.end_time,
_latitude: this.data.m_latitude,
_longitude: this.data.m_longitude
}
console.log(parameter);
wx.cloud.callFunction({
name: "addRecord",
data: parameter
})
.then(res => {
console.log("访问成功");
})
Database.createCollection(collectionName: string): Promise
创建集合,如果集合已经存在会创建失败,参数就一个collectionName: string
const cloud = require('wx-server-sdk')
cloud.init({
env: cloud.DYNAMIC_CURRENT_ENV
})
const db = cloud.database()
exports.main = async (event, context) => {
return await db.createCollection('todos')
}
在小程序端不能批量添加
只能使用for循环添加,但是容易造成资源用量爆表
在云函数中可以实现批量添加
//云函数
var a={age:22},b={age:23}
var list=[a,b]
db.collection('age').add({data:list}).then()
//这样就行了
exports.main = async (event, context) => {
return cloud.database().collection('address-book').count()
}
https://www.imooc.com/article/292184?block_id=tuijian_wz#comment
自己修改后的代码:
js代码
Page({
data: {
person_list: [],
fileUrl: "",
},
toExcel: function () {
// console.log(this.data.person_list);
wx.cloud.callFunction({
name: "toExcel",
data: {
userdata: this.data.person_list
}
})
.then(res => {
console.log("保存成功", res);
this.getFileUrl(res.result.fileID)
})
.catch(err => {
})
},
//获取云存储文件下载地址,这个地址有效期一天
getFileUrl: function (fileID) {
wx.cloud.getTempFileURL({
fileList: [fileID]
})
.then(res => {
console.log("文件下载链接", res.fileList[0].tempFileURL);
this.setData({
fileUrl: res.fileList[0].tempFileURL
})
wx.showModal({
title: "提示",
content: "excel文件下载链接:" + this.data.fileUrl,
confirmText: "复制链接"
})
.then(res => {
if (res.confirm) {
// 点击确定,复制下载链接
this.copyFileUrl()
} else {
console.log("用户取消");
}
})
})
.catch(err => [])
},
//复制excel文件下载链接
copyFileUrl: function () {
wx.setClipboardData({
data: this.data.fileUrl,
})
.then(res => {
wx.getClipboardData({
success: (option) => {
console.log("复制成功", res.data);
},
})
})
}
})
wxml代码:
<view class="excel-button">
<button bindtap="toExcel">导出至excel表button>
view>
云函数getData
代码:
// 云函数入口文件
const cloud = require('wx-server-sdk')
// 云函数初始化
cloud.init({
// env: 'cloud1-0gbwed2xdbe13cb4' 固定云开发环境
env: cloud.DYNAMIC_CURRENT_ENV //动态获取当前云开发环境
})
// 云函数入口函数
exports.main = async (event, context) => {
return cloud.database().collection('address-book').get()
}
云函数toExcel
代码,注意toExcel
需要安装node-xlsx类库(node类库),在该函数中打开终端,输入npm install node-xlsx
即可
// 云函数入口文件
const cloud = require('wx-server-sdk')
cloud.init({
// env: 'cloud1-0gbwed2xdbe13cb4' 固定云开发环境
env: cloud.DYNAMIC_CURRENT_ENV //动态获取当前云开发环境
})
//操作excel用的类库
const xlsx = require('node-xlsx');
// 云函数入口函数
exports.main = async (event, context) => {
try {
let {
userdata
} = event
//1,定义excel表格名
let dataCVS = 'attendance.xlsx'
//2,定义存储数据的
let alldata = [];
let row = ['num', 'name', 'state']; //表属性
alldata.push(row);
for (let key in userdata) {
let arr = [];
arr.push(userdata[key].num);
arr.push(userdata[key].name);
if (userdata[key].state == -1) {
arr.push("未到")
} else if (userdata[key].state == 0) {
arr.push("迟到")
} else {
arr.push("正常")
}
alldata.push(arr)
}
//3,把数据保存到excel里
var buffer = await xlsx.build([{
name: "mySheetName",
data: alldata
}]);
//4,把excel文件保存到云存储里
return await cloud.uploadFile({
cloudPath: dataCVS,
fileContent: buffer, //excel二进制文件
})
} catch (e) {
console.error(e)
return e
}
}
把图片上传到云存储,拿到 fileId,下次能根据fileId拿到临时url
//发布物品的响应事件
bindSubmitThing: function () {
var that = this;
// var studentId = that.data.studentId;
var studentId = "2016302030120"
if (!studentId) {
wx.showModal({
title: '提示',
content: '请验证您的学生身份',
success: function (res) {
if (res.confirm) {
console.log('用户点击确定')
wx.navigateTo({
url: '../my/my',
})
} else if (res.cancel) {
console.log('用户点击取消')
}
}
})
} else {
this.setData({
buttonLoadingThing: true
})
var thingImage = that.data.thingImage; //图片
var thingName = that.data.thingName; //名字
var thingConditionIndex = that.data.thingConditionIndex; //成色索引值
var thingConditions = that.data.thingConditions[thingConditionIndex]; //成色
var thingCampusIndex = that.data.thingCampusIndex; //校区索引值
var thingCampus = that.data.thingCampus[thingCampusIndex]; //校区
var thingDescribe = that.data.thingDescribe || '无备注或描述'; //备注
var thingPhoneNumber = that.data.thingPhoneNumber; //电话
var thingPrice = that.data.thingPrice; //价格
var studentId = that.data.studentId;
studentId = "2016302030120"
// 图片上传到云存储,并复制 fileId + 其它信息存到数据库中方便索引,下次查看图像
var cloudPath = "img/" + new Date().getTime() + "-" + Math.floor(Math.random() * 1000) //云储存的路径及文件名;
console.log(cloudPath);
console.log(thingImage);
wx.cloud.uploadFile({
cloudPath,
filePath: thingImage
})
.then(res => {
console.log(res);
wx.cloud.database().collection('all-things').add({
data: {
thingImage: res.fileID,
thingName: thingName,
thingConditions: thingConditions,
thingCampus: thingCampus,
thingDescribe: thingDescribe,
thingPhoneNumber: thingPhoneNumber,
thingPrice: thingPrice,
studentId: studentId
}
})
.then(res => {
console.log("加入表 all-things 的res:", res);
wx.showToast({
title: '发布成功',
icon: 'succes',
duration: 2500,
mask: true
})
that.setData({
buttonLoadingThing: false,
thingImage: '',
thingName: '',
thingDescribe: '',
thingPrice: '',
thingPhoneNumber: '', //电话号码
})
})
.catch(res => {
console.log(JSON.stringify(res));
wx.showToast({
title: '发布失败',
icon: 'loading',
duration: 2000
})
that.setData({
buttonLoadingThing: false
})
})
})
.catch(res => {
console.log(JSON.stringify(res));
wx.showToast({
title: '发布失败',
icon: 'loading',
duration: 2000
})
that.setData({
buttonLoadingThing: false
})
})
}
},
微信小程序update失败的问题
VM820 WAService.js:2 TypeError: {(intermediate value)}.update is not a function
原因是默认数据库权限是管理者可写,所以我们要改成所有人可写,或者在你的json文件上加一个openid 字段,标注你自己的openid
云函数中使用console.log();
在控制台不打印结果 解决方案
云函数打印内容不回在控制台显示,而是在云函数的日志中有记录
云函数打印不出内容,日志中也不显示,解决方案:
需要在console.log(x,123) 标识符:123
微信小程序遇到的程序异步执行导致数据库读写异常的问题
见我的这篇文章https://blog.csdn.net/wyll19980812/article/details/115423805
Error: tunneling socket could not be established, cause=connect ECO微信小程序本地调试预览出错