个人案例
- 店小two
一个方便老板管理店铺,方便会员消费的小程序
店小two扫码体验
- 关于CSS中 background-image:url('')的问题
在我们的页面CSS中. 我们页面背景图 ground-image:url ('') 这里面我放图片的本地路径 手机端不显示 但是在开发工具内是可以的. 开发工具中效果: [图片] 手机端效果 分2部分 页面预览效果: 1:[图片] 代码呈现: [图片]
2019-04-12 - wx.getPrivacySetting接口needAuthorization一直返回false
wx.getPrivacySetting接口needAuthorization一直返回false,privacyContractName字段未返回。 在基础库2.33.0和3.0.0上都存在。 在微信-设置中取消授权后(如摄像头等),needAuthorization依然是false。
2023-08-15 - 微信小程序中安全区域计算和适配
前言 自从iphoneX问世之后,因为iphoneX、iphoneXR和后续全面屏手机设备,因为物理Home键被底部小黑条代替了,这时候很多前端小伙伴在开发的过程都会遇到 “全面屏”和“非全面屏”的兼容性问题,普遍问题就是底部按钮或者选项卡与底部黑线重叠 解释 根据官方解释: 安全区域指的是一个可视窗口范围,处于安全区域的内容不受圆角(corners)、齐刘海(sensor housing)、小黑条(Home Indicator)的影响。 具体区域如图展示 [图片] 适配方案 当前有效的解决方式有几种 使用已知底部小黑条高度34px/68rpx来适配 使用苹果官方推出的css函数env()、constant()适配 使用微信官方API,getSystemInfo()中的safeArea对象进行适配 使用已知底部小黑条高度34px/68rpx来适配 这种方式是根据实践得出,通过物理方式测出iPhone底部的小黑条(Home Indicator)高度是34px,实际在开发者工具选中真机获取到高度也是34px,所以直接根据该值,设置margin-bottom、padding-bottom、height也能实现。同时这样做要有一个前提,需要判断当前机型是需要适配安全区域的机型。 但是这种方案相对来说是不推荐使用的。比较是一个比较古老原始的方案 使用苹果官方推出的css函数env()、constant()适配 这种方案是苹果官方推荐使用env(),constant()来适配,开发者不需要管数值具体是多少。 env和constant是IOS11新增特性,有4个预定义变量: safe-area-inset-left:安全区域距离左边边界的距离 safe-area-inset-right:安全区域距离右边边界的距离 safe-area-inset-top:安全区域距离顶部边界的距离 safe-area-inset-bottom :安全距离底部边界的距离 具体用法如下: Tips: constant和env不能调换位置 [代码] padding-bottom: constant(safe-area-inset-bottom); /*兼容 IOS<11.2*/ padding-bottom: env(safe-area-inset-bottom); /*兼容 IOS>11.2*/ [代码] 其实利用这个能解决大部分的适配场景了,但是有时候开发需要自定义头部信息,这时候就没办法使用css来解决了 使用微信官方API,getSystemInfo()中的safeArea对象进行适配 通过 wx.getSystemInfo获取到各种安全区域信息,解析出具体的设备类型,通过设备类型做宽高自适应,话不多说,直接上代码 代码实现 [代码] const res = wx.getSystemInfoSync() const result = { ...res, bottomSafeHeight: 0, isIphoneX: false, isMi: false, isIphone: false, isIpad: false, isIOS: false, isHeightPhone: false, } const modelmes = result.model const system = result.system // 判断设备型号 if (modelmes.search('iPhone X') != -1 || modelmes.search('iPhone 11') != -1) { result.isIphoneX = true; } if (modelmes.search('MI') != -1) { result.isMi = true; } if (modelmes.search('iPhone') != -1) { result.isIphone = true; } if (modelmes.search('iPad') > -1) { result.isIpad = true; } let screenWidth = result.screenWidth let screenHeight = result.screenHeight // 宽高比自适应 screenWidth = Math.min(screenWidth, screenHeight) screenHeight = Math.max(screenWidth, screenHeight) const ipadDiff = Math.abs(screenHeight / screenWidth - 1.33333) if (ipadDiff < 0.01) { result.isIpad = true } if (result.isIphone || system.indexOf('iOS') > -1) { result.isIOS = true } const myCanvasWidth = (640 / 375) * result.screenWidth const myCanvasHeight = (1000 / 667) * result.screenHeight const scale = myCanvasWidth / myCanvasHeight if (scale < 0.64) { result.isHeightPhone = true } result.navHeight = result.statusBarHeight + 46 result.pageWidth = result.windowWidth result.pageHeight = result.windowHeight - result.navHeight if (!result.isIOS) { result.bottomSafeHeight = 0 } const capsuleInfo = wx.getMenuButtonBoundingClientRect() // 胶囊热区 = 胶囊和状态栏之间的留白 * 2 (保持胶囊和状态栏上下留白一致) * 2(设计上为了更好看) + 胶囊高度 const navbarHeight = (capsuleInfo.top - result.statusBarHeight) * 4 + capsuleInfo.height // 写入胶囊数据 result.capsuleInfo = capsuleInfo; // 安全区域 const safeArea = result.safeArea // 可视区域高度 - 适配横竖屏场景 const screenHeight = Math.max(result.screenHeight, result.screenWidth) const height = Math.max(safeArea.height, safeArea.width) // 状态栏高度 const statusBarHeight = result.statusBarHeight // 获取底部安全区域高度(全面屏手机) if (safeArea && height && screenHeight) { result.bottomSafeHeight = screenHeight - height - statusBarHeight if (result.bottomSafeHeight < 0) { result.bottomSafeHeight = 0 } } // 设置header高度 result.headerHeight = statusBarHeight + navbarHeight // 导航栏高度 result.navbarHeight = navbarHeight [代码]
2022-11-04 - 使用van-circle组件,模拟器显示没问题,到了真机上样式显示不出来,需要刷新,怎么办?
[图片][图片]
2023-01-13 - rich-text组件 中富文本框图片不能自适应?
[图片] 用了标签 rich-text 但是图片 莫名超过去,不会自适应,请问大佬们怎么结局
2022-09-07 - 小程序EventChannel的一些理解和使用实践
EventChannel是什么通过官方文档和示例,实际可以发现EventChannel借助wx.navigateTo方法,在两个页面之间构建起了数据通道,互相可以通过“派发事件”及“注册这些事件的监听器”来实现基于事件的页面通信。 具体看下下面的官方示例: wx.navigateTo({ url: 'test?id=1', events: { // 为指定事件添加一个监听器,获取被打开页面传送到当前页面的数据 acceptDataFromOpenedPage: function(data) { console.log(data) }, someEvent: function(data) { console.log(data) } ... }, success: function(res) { // 通过 eventChannel 向被打开页面传送数据 res.eventChannel.emit('acceptDataFromOpenerPage', { data: 'test' }) } }) events: 注册将在目标页面触发(派发)的同名事件的监听器 success:跳转后进行可通过res.eventChannel 触发自定义事件 //test.js Page({ onLoad: function(option){ console.log(option.query) const eventChannel = this.getOpenerEventChannel() eventChannel.emit('acceptDataFromOpenedPage', {data: 'test'}); eventChannel.emit('someEvent', {data: 'test'}); // 监听 acceptDataFromOpenerPage 事件,获取上一页面通过 eventChannel 传送到当前页面的数据 eventChannel.on('acceptDataFromOpenerPage', function(data) { console.log(data) }) } }) 通过this.getOpenerEventChannel()获取eventChannel对象, 使用eventChannel.emit() 可以在任意时刻触发(派发)事件。当前页面即可执行对应的事件处理函数。 使用eventChannel.on() 即可监听上个页面emit的事件。 使用示例A页面为订单页面,B页面为填写发票信息页面,A页面跳转B页面携带开票金额(amount),A页面如果已填写,再次跳转B页面,需要携带发票信息(invoice),方便直接编辑B页面填写后返回更新A页面的发票信息(invoice)简单的实现是 A到B的传值使用query实现,B到A的传值使用globalData实现。 // A页面 onShow(){ if(globalData.temp_invoice_info){ this.setData({ invoice:globalData.temp_invoice_info },()=>{ globalData.temp_invoice_info=null; }) } }, //跳转填写发票表单信息 toFillOutInvoiceInfo() { wx.navigateTo({ url: `/pages/invoice/invoice-info-form/invoice-info-form?amount=${ this.data.detail.amount }&invoice=${ this.data.invoice.invoice_title ? JSON.stringify(this.data.invoice) : "" }`, }); }, //B页面 onLoad(options){ this.data.options = options; if (this.data.options.invoice) { this.setData({ invoice: JSON.parse(this.data.options.invoice) }) } }, submit(){ globalData.temp_invoice_info = this.data.invoice; wx.navigateBack(); } 如下EventChannel的实现 //A页面(注意这里需要使用箭头函数(访问this)) //跳转填写发票表单信息 toFillOutInvoiceInfo() { wx.navigateTo({ url: `/pages/invoice/invoice-info-form/invoice-info-form`, events:{ updateInvoice:(result)=>{ this.setData({invoice:result}) } }, success:(res)=>{ const params = { amount: this.data.amount, invoice:this.data.invoice.invoice_title ? JSON.stringify(this.data.invoice) : "" } res.eventChannel.emit('sendQueryParams',params) } }); }, //B页面 onLoad(){ this.getOpenerEventChannel().once('sendQueryParams',(params)=>{ const {amount,invoice} = parmas; this.setData({amount,invoice}) }) } submit(){ this.getOpenerEventChannel().emit('updateInvoice',this.data.invoice); wx.navigateBack(); } 还有一个额外的地方就是EventChannel可以在A-B-C多个页面直接建立数据通道。官方示例。 //注意this.getOpenerEventChannel() 只能在navigateTo模板页面使用,其他更多页面使用时, //可以保存在getApp()全局实例中以备其他页面使用 // 保留AB通道事件,已备C页面给A页面发送数据 // B页面 const eventChannel = this.getOpenerEventChannel() getApp().pageBEventChannel = eventChannel //C页面 getApp().pageBEventChannel.emit('PageAacceptDataFromPageC', { data: 'Page C->A' }); 有不对或扩展的地方欢迎大家批评交流。
2022-08-11 - onShareAppMessage 怎么判断是否分享成功呢?
success:function 方法没有办法监听分享成功事件呢, 想记录一下文章分享的次数 // 自定义分享 onShareAppMessage() { let _this = this; _this.share(); return { title: this.articleInfo.title, path: '/pagesA/articleDetail/articleDetail?id=' + this.articleInfo.id, imageUrl: this.articleInfo.image, success:function(res) { _this.share(); }, fail: function () { uni.showToast({ title: '分享失败', icon: 'none', duration: 2000 }); }, complete: function (c) { }, } },
2022-03-18 - 云储存文件如何批量下载到本地
[图片] 云储存文件上传下载文档地址,https://docs.cloudbase.net/cli-v1/storage 首先确保你已经操作了以上 3 步~~~ 然后你可以选择在桌面新建一个 downloads 文件夹,然后选择打开桌面的命令提示符, [图片] //通过 --mode 指定你的云环境id tcb --mode '你的云环境id' [图片] 环境部署成功后,下载云储存文件到本地(下载 dianXiaoTwo云储存文件 到 本地downloads文件 中) // tcb storage download '云环境文件路径' '本地文件路径' --dir tcb storage download dianXiaoTwo downloads --dir [图片] [图片]
2022-10-13 - pull 报错cannot read property 'pull'
https://developers.weixin.qq.com/miniprogram/dev/wxcloud/reference-sdk-api/database/command/Command.pull.html 云函数、云开发控制台直接查询都无效 提示RuntimeError: cannot read property 'pull' [图片] 云开发控制台代码 db.collection('user_organizer') .where({ organizerid:'6af880a55eb22d14002249487d04b579', }) .update({ data:{ members:_.pull({ userid:'11111' }) } })
2020-05-09 - 小程序云开发where条件怎么根据时间筛选
小程序云开发过程中,碰到需要查询大于或小于某个时间的数据,该如何写where条件?db.collection(...).where(???)where里现在只会用条件 key:val 即key=val
2019-07-24 - 云开发-云函数实现联表查询和分页
相关api 官方参考文档 [代码]Aggregate.lookup Aggregate.limit Aggregate.skip Aggregate.count [代码] 实现原理 基于 [代码]aggregate[代码] 操作集合 使用 [代码]count[代码] 获取总数量和页数 使用 [代码]limit[代码] 限制一次返回的数量 使用 [代码]skip[代码] 实现发送下一页的数据 使用 [代码]lookup[代码] 实现联表 示例 假设 [代码]orders[代码] 集合有以下数据 [代码][ {"_id":4,"book":"novel 1","price":30,"quantity":2}, {"_id":5,"book":"science 1","price":20,"quantity":1}, {"_id":6} ] [代码] 假设 [代码]books[代码] 集合有以下数据 [代码][ {"_id":"book1","author":"author 1","category":"novel","stock":10,"time":1564456048486,"title":"novel 1"}, {"_id":"book3","author":"author 3","category":"science","stock":30,"title":"science 1"}, {"_id":"book4","author":"author 3","category":"science","stock":40,"title":"science 2"}, {"_id":"book2","author":"author 2","category":"novel","stock":20,"title":"novel 2"}, {"_id":"book5","author":"author 4","category":"science","stock":50,"title":null}, {"_id":"book6","author":"author 5","category":"novel","stock":"60"} ] [代码] 实现 [代码]orders[代码] 和 [代码]books[代码] 联表查询和分页的关键代码 [代码]const pageSize = 10 // 每页数据量,可以作为云函数的入参传入 const currPage = 1 // 查询的当前页数,可以作为云函数的入参传入 const db = cloud.database() const $ = db.command.aggregate // 定义联表实例 const aggregateInstance = db.collection('orders').aggregate() .lookup({ from: 'books', localField: 'book', foreignField: 'title', as: 'bookList', }) const { totalCount } = await aggregateInstance.count('totalCount').end() // 计算总页数 const totalPage = totalCount === 0 ? 0 : totalCount <= pageSize ? 1 : parseInt(totalCount / pageSize) + 1 // 分页查询数据 const data = await aggregateInstance.replaceRoot({ newRoot: $.mergeObjects([ $.arrayElemAt(['$bookList', 0]), '$$ROOT' ]) }) .project({ bookList: 0 }) .limit(pageSize) .skip(currPage * pageSize) .end() return {currPage, pageSize, totalPage, totalCount, data} [代码] 预期输出结果 [代码]{ currPage: 1, pageSize: 10, totalPage: 1, totalCount: 3, data: [ { "_id": 4, "title": "novel 1", "author": "author 1", "category": "novel", "stock": 10, "book": "novel 1", "price": 30, "quantity": 2 }, { "_id": 5, "category": "science", "title": "science 1", "author": "author 3", "stock": 30, "book": "science 1", "price": 20, "quantity": 1 }, { "_id": 6, "category": "science", "author": "author 4", "stock": 50, "title": null }] } [代码] 如有错误,欢迎拍砖 (▽)
2020-03-25 - 小程序调试模式正常,关闭调试模式就发生异常
小程序调试模式正常,关闭调试模式就发生异常,不能正常访问我的服务,debug下没有任何报错信息,request合法域名那里也配置了。
2020-08-06 - 云函数模糊查询问题?
await db.collection(cname).where({ _openid: OPENID, // 模糊查询 activity_title: db.RegExp({ regexp: searchValue, //从搜索栏中获取的value作为规则进行匹配。 options: 'i', //大小写不区分 }) }).orderBy('createTime', 'desc')。。。。。 请教:以上云函数中的代码 错误提示: regexp must be a string 传入的是个空字符串,该怎么写?
2019-08-09 - WeUI 引用组件使用 “ext-class” 给组件自定义样式的时候,样式没有生效
WeUI 引用组件使用 “ext-class” 给组件自定义样式的时候,样式没有生效
2020-01-20 - 小程序搜索功能,云开发搜索,小程序云开发模糊搜索,同时搜索多个字段
今天来给大家讲讲小程序的搜索功能。我这里后台数据库用的是小程序云开发的云数据库。所以我们搜索的时候就要借助云开发来实现。 一,需求 比如我这里有如下的一些数据 [图片] 我们想实现如下搜索需求 1,搜索标题(title)包含‘小石头’的数据 2,搜索标题(title)或者描述(desc)包含‘小石头’的数据 3,搜索标题(title)描述(desc)都包含‘小石头’的数据 我们知道数据库查询的时候有个where语句,但是where语句是查询某个字段全部包含你输入的内容时才可以,所以单纯用where语句来做搜索的话,结果太单一。所以我们今天就来学习下模糊搜索功能的实现。我们以上面三个需求为例,来一个个讲解。 二,实现原理 我们做模糊搜索的时候,其实就是查询某个字段里是否包含我们的搜索词。而模糊搜索需要借助RegExp,来看看RegExp是什么。 [图片] 官方文档:https://developers.weixin.qq.com/miniprogram/dev/wxcloud/reference-sdk-api/database/Database.RegExp.html 再来看看官方示例 [图片] 可能看官方示例会有点糊涂,那么我们接下来就结合具体代码来给大家做下讲解。 三,模糊搜索的代码实现 3-1,模糊搜索单个字段 需求:搜索标题(title)包含‘小石头’的数据 代码如下 [图片] 查询结果如下: [图片] 可以看到我们成功的查询到了标题里包含‘小石头的数据’ 3-2,模糊搜索多个字段(满足一个即可) 需求:搜索标题(title)或者描述(desc)包含‘小石头’的数据 由于我们要查询多个字段,所以我们这里用到了command高级操作符里的or [图片] 代码如下: [图片] 查询结果: [图片] 我们来分析下这两条数据 1,标题和描述都包含‘小石头’,符合 2,虽然标题里没有‘小石头’,但是描述里有,所以也符合。 3,title和desc里都没有‘小石头’,所以不符合。 [图片] 3-3,模糊搜索多个字段(要同时满足) 需求:搜索标题(title)描述(desc)都包含‘小石头’的数据 由于我们要查询多个字段,所以我们这里用到了command高级操作符里的and [图片] 代码如下: [图片] 查询结果: [图片] 我们来分析下这两条数据 1,标题和描述都包含‘小石头’,符合 2,虽然desc里没有‘小石头’,但是title里没有,所以也不符合。 3,title和desc里都没有‘小石头’,所以也不符合。 [图片] 四,源码 为例方便大家使用,我把完整的代码贴到这里,后面大家使用时,直接复制这里的代码,略微改造下就可以了。 [代码] //我这里简单起见就把搜索词写死,正常应该用户输入的 let searchKey = '小石头' let db = wx.cloud.database() let _ = db.command db.collection('news') .where(_.or([ {//标题 title: db.RegExp({ //使用正则查询,实现对搜索的模糊查询 regexp: searchKey, options: 'i', //大小写不区分 }), }, {//描述 desc: db.RegExp({ regexp: searchKey, options: 'i', }), } ])).get() .then(res => { console.log('查询成功', res) }) .catch(res => { console.log('查询失败', res) }) [代码] 到这里就讲完了,我后面会专门在云开发入门的课程里作为实战案例录制视频给到大家的: 《小程序云开发入门视频》
2021-02-08 - 小程序云开发中collection().get()为什么无法获取数据?
[图片] [图片] db能输出 但是里面的collection输出没有显示 在数据库里面权限也设置了[图片] 但是结果还是无数据 [图片]
2020-07-03 - 开发者工具的云开发如何一次删除多条记录或者清空数据库?
开发者工具的云开发如何一次删除多条记录或者清空数据库?
2019-09-23