- 自定义navigationBar顶部导航栏,兼容适配所有机型(附完整案例)
前言 navigationBar相信大家都不陌生把?今天我们就来说说自定义navigationBar,把它改变成我们想要的样子(搜索框+胶囊、搜索框+返回按钮+胶囊等)。 思路 隐藏原生样式 获取胶囊按钮、状态栏相关数据以供后续计算 根据不同机型计算出该机型的导航栏高度,进行适配 编写新的导航栏 引用到页面 正文 一、隐藏原生的navigationBar window全局配置里有个参数:navigationStyle(导航栏样式),default=默认样式,custom=自定义样式。 [代码]"window": { "navigationStyle": "custom" } [代码] 让我们看看隐藏后的效果: [图片] 可以看到原生的navigationBar已经消失了,剩下孤零零的胶囊按钮,胶囊按钮是无法隐藏的。 二、准备工作 1.获取胶囊按钮的布局位置信息 我们用wx.getMenuButtonBoundingClientRect()【官方文档】获取胶囊按钮的布局位置信息,坐标信息以屏幕左上角为原点: [代码]const menuButtonInfo = wx.getMenuButtonBoundingClientRect(); [代码] width height top right bottom left 宽度 高度 上边界坐标 右边界坐标 下边界坐标 左边界坐标 下面是官方给的示意图,方便大家理解几个坐标。 [图片] 2.获取系统信息 用wx.getSystemInfoSync()【官方文档】获取系统信息,里面有个参数:statusBarHeight(状态栏高度),是我们后面计算整个导航栏的高度需要用到的。 [代码]const systemInfo = wx.getSystemInfoSync(); [代码] 三、计算公式 我们先要知道导航栏高度是怎么组成的, 计算公式:导航栏高度 = 状态栏高度 + 44。 实例 【源码下载】 自定义导航栏会应用到多个、甚至全部页面,所以封装成组件,方便调用;下面是我写的一个简单例子: app.js [代码]App({ onLaunch: function(options) { const that = this; // 获取系统信息 const systemInfo = wx.getSystemInfoSync(); // 胶囊按钮位置信息 const menuButtonInfo = wx.getMenuButtonBoundingClientRect(); // 导航栏高度 = 状态栏高度 + 44 that.globalData.navBarHeight = systemInfo.statusBarHeight + 44; that.globalData.menuRight = systemInfo.screenWidth - menuButtonInfo.right; that.globalData.menuBotton = menuButtonInfo.top - systemInfo.statusBarHeight; that.globalData.menuHeight = menuButtonInfo.height; }, // 数据都是根据当前机型进行计算,这样的方式兼容大部分机器 globalData: { navBarHeight: 0, // 导航栏高度 menuRight: 0, // 胶囊距右方间距(方保持左、右间距一致) menuBotton: 0, // 胶囊距底部间距(保持底部间距一致) menuHeight: 0, // 胶囊高度(自定义内容可与胶囊高度保证一致) } }) [代码] app.json [代码]{ "pages": [ "pages/index/index" ], "window": { "navigationStyle": "custom" }, "sitemapLocation": "sitemap.json" } [代码] 下面为组件代码: /components/navigation-bar/navigation-bar.wxml [代码]<!-- 自定义顶部栏 --> <view class="nav-bar" style="height:{{navBarHeight}}px;"> <input class="search" placeholder="输入关键词!" style="height:{{menuHeight}}px; min-height:{{menuHeight}}px; line-height:{menuHeight}}px; left:{{menuRight}}px; bottom:{{menuBotton}}px;"></input> </view> <!-- 内容区域: 自定义顶部栏用的fixed定位,会遮盖到下面内容,注意设置好间距 --> <view class="content" style="margin-top:{{navBarHeight}}px;"></view> [代码] /components/navigation-bar/navigation-bar.json [代码]{ "component": true } [代码] /components/navigation-bar/navigation-bar.js [代码]const app = getApp() Component({ properties: { // defaultData(父页面传递的数据-就是引用组件的页面) defaultData: { type: Object, value: { title: "我是默认标题" }, observer: function(newVal, oldVal) {} } }, data: { navBarHeight: app.globalData.navBarHeight, menuRight: app.globalData.menuRight, menuBotton: app.globalData.menuBotton, menuHeight: app.globalData.menuHeight, }, attached: function() {}, methods: {} }) [代码] /components/navigation-bar/navigation-bar.wxss [代码].nav-bar{ position: fixed; width: 100%; top: 0; color: #fff; background: #000;} .nav-bar .search{ width: 60%; color: #333; font-size: 14px; background: #fff; position: absolute; border-radius: 50px; background: #ddd; padding-left: 14px;} [代码] 以下是调用页面的代码,也就是引用组件的页面: /pages/index/index.wxml [代码]<navigation-bar default-data="{{defaultData}}"></navigation-bar> [代码] /pages/index/index.json [代码]{ "usingComponents": { "navigation-bar": "/components/navigation-bar/navigation-bar" } } [代码] /pages/index/index.js [代码]const app = getApp(); Page({ data: { // 组件参数设置,传递到组件 defaultData: { title: "我的主页", // 导航栏标题 } }, onLoad() { console.log(this.data.height) } }) [代码] 效果图: [图片] 好了,以上就是全部代码了,大家可以文中复制代码,也可以【下载源码】,直接到开发者工具里运行,记得appid用自己的或者测试哦! 下面附几张其它小程序的效果图,大家也可以尝试照着做: [图片][图片] 总结 本文写了自定义navigationBar的一些基础性东西,里面涉及组件用法、参数传递、导航栏相关。 由于测试环境有限,大家在使用时如果发现有什么问题,希望及时反馈,以供及时更新帮助更多的人! 大家有什么疑问,欢迎评论区留言!
2022-06-23 - 教大家用20行js代码,开发好小程序订阅消息
微信小程序官方决定在2020-1-10全面线下小程序模板消息,要去替换为订阅消息。那对开发者而言,又要一个一个地方去修改代码兼容.... 所以我替大家写了段代码,来快速解决问题。复制下面这段代码到app.js文件最上面即可解决问题。代码的主要功能是在每一个tap类型的点击事件中触发订阅弹窗,这样用户点几次界面,你就可以发几次消息。这也是让发送次数最大化,不可能比这个次数还多了。 预期结果是:用户点几次弹窗,就会注意到有一个不再提醒按钮,一旦选了它,那你就可以随便发订阅消息了! // 记录原Page方法 const originPage = Page; // 重写Page方法 Page = (page) => { Object.keys(page).forEach(function(key){ if(key !== 'data'){ let originMethod = page[key]; page[key] = function () { let e = arguments[0]; //给所有的点击事件增加订阅消息弹窗 if(!!e && !!e.type && e.type === 'tap'){ wx.requestSubscribeMessage({ tmplIds: ['3E66jPXafsnikZoQR5uk0OUzIUVASZE5scyAu5YCHPI'], ////////这里替换为自己的模板ID///// success (res) { // console.log(res) }, fail (res) { // console.log('订阅消息失败',res) } }) } return originMethod.call(this,...arguments) } } }); return originPage(page); };
2020-01-09 - 那些被忽略的盒子模型小知识
那些被忽略的盒子模型小知识 本文是笔者在学习CSS时的一些小白总结 我们知道的盒子模型主要由4个区域组成,分别是内容区域(content),内边距区域(padding),边框区域(border)和外边距区域(margin)。 对于不了解盒子模型的朋友可以移步到这里了解一下。 [图片] Content(内容) 1. 替换元素 替换元素(replaced element),顾名思义就是内容可以被替换的元素。 我们通常会把一些特殊意义的文本替换成图片,比如一个网站的logo。 [图片] 我们会在页面上看到的不是h1标签显示的”Google“文字,而是谷歌logo的图片。使用了content的元素的内容在html标签中是不存在的。这样做就有个好处,当爬虫来访问我们的网站,爬虫可以知道我们这个主站的h1标题是”Google“而不是一个img标签,且在视觉上给用户更好的体验。 2. 伪元素::before和::after [图片] 为了实现上面显示价格,之前写react代码时候会经常这么写,感觉在逻辑上写了好多关联性不大的文本。其实可以利用[代码]::before[代码]和[代码]::after[代码]两个伪元素,把这些与逻辑不相关的写在css里,react dom则专注于数据的表现。 [代码]<div className="price-panel"> <span className="price-panel__price"> ¥ {(totalPrice / 100).toFixed(1)} </span> <span className="price-panel__discount-price"> 已省¥ {(totalDiscountPrice / 100).toFixed(1)} </span> <span className="price-panel__discount"> ( {(discount / 10).toFixed(1)} 折) </span> </div> [代码] 使用了伪元素后的react代码显然更加清晰表示数据。 HTML: [代码]<div className="price-panel"> <span className="price-panel__price"> {(totalPrice / 100).toFixed(1)} </span> <span className="price-panel__discount-price"> {(totalDiscountPrice / 100).toFixed(1)} </span> <span className="price-panel__discount"> {(discount / 10).toFixed(1)} </span> </div> [代码] SCSS: [代码].price-panel { &__price { &::before { content: '¥'; } } &__discount-price { &::before { content: '已省¥'; } } &__discount { &::before { content: '('; } &::after { content: '折)'; } } } [代码] 我们还能使用伪元素帮助实现一些本来需要多个div实现的样式,比如下面这个对话框。 [图片] HTML: [代码]<div class="dialog">Hi,I’m a bubble dialog. Can you see me?</div> [代码] CSS: [代码].dialog { background: #f0f; padding: 10px; border-radius: 10px; color: white; max-width: 250px; position: relative; overflow: visible; } .dialog::after { position: absolute; content: ''; display: inline-block; border-width: 5px 10px; border-style: solid; border-color: transparent transparent #f0f #f0f; width: 0; height: 0; right: -20px; } [代码] Padding(内边距) padding的百分比值是非常有用的。需要注意的padding的百分比值,无论是水平方向还是垂直方向都是相对于父级元素的宽度进行计算的。 如果需要弄一张16:9的等比缩放图片,可以利用padding的这个特性,设置一个[代码]padding-top[代码]或者[代码]padding-bottom[代码]为56.25%即可(100\16*9) [图片] [图片] Margin(外边距) 1. margin合并 块级元素的[代码]margin-top[代码]和[代码]margin-bottom[代码]有时候会合并为单个margin,这种现象叫margin合并。 margin合并发生两个重要元素 必须是块级元素 只发生在垂直方向。 margin合并的场景 1.1 相邻兄弟元素 [图片] 1.2 父级和第一个/最后一个子元素 在实际开发中,父子margin合并很有可能会带给我们麻烦。 如下图所示,div表现出和我们预想不一致的结果。 [图片] 那么怎么才能防止这种父子margin合并导致的和预想不一致问题呢? 解决方法如下(这里直接复制了张鑫旭老师书籍《CSS世界》的原话。): (1)对于margin-top合并(满足一个即可): 父元素设置为BFC 设置[代码]border-top[代码]的值(亲测transparent也可以的) 设置[代码]padding-top[代码]的值 父元素和第一个子元素之间添加内联元素 (2)对于margin-bottom合并(满足一个即可): 父元素设置为BFC 设置[代码]border-bottom[代码](transparent也可以的) 设置[代码]padding-bottom[代码] 父元素和最后一个子元素之间添加一个内联元素 父元素设置[代码]height[代码]、[代码]min-height[代码]或者[代码]max-height[代码] 1.3 空块级元素的margin合并 [图片] 2. margin auto 每当说到[代码]margin:auto[代码],我的第一反应是居中。但这个只是一个浅层应用的表象。 接下来我们去一起看看这个[代码]margin:auto[代码]究竟是‘何方神圣’。 [代码]margin:auto[代码]的填充规则如下: 如果一侧定值,一侧auto,则auto为剩余空间大小。注意auto并不是0的意思。 如果两侧都是auto,则平分剩余的空间 我会疑惑为什么我设置了[代码]margin: auto[代码],却在垂直方向上没有居中。 [图片] 这里《css世界》中给出的答案让人非常容易理解。假如把.son元素的height去掉,.son的高度会自动变成父元素的200px,显然不会,所以无法触发margin: auto。同理,如果把width为200px去掉,确实是会和父元素一样宽。 那么如何让垂直居中呢? 子元素使用绝对定位后设置[代码]margin: auto[代码]即可 [图片] Border(边框) 用border绘制三角形 我们可以利用border color为透明来绘制一些图形,比如三角形 [图片] 注意[代码]border-color[代码]这个属性。 [代码]/* border-color: color; 单值语法 */ border-color: red; /* border-color: vertical horizontal; 双值语法*/ border-color: red #f015ca; /* border-color: top horizontal bottom; 三值语法 */ border-color: red yellow green; /* border-color: top right bottom left; 四值语法 */ border-color: red yellow green blue; [代码] 当然,我们绘制三角形不限于这种等腰三角。 [图片] 这里绘制了一个底边分别是60px和160px的直角三角形。 参考 文章主要参考了张鑫旭老师的《css世界》并根据自己的业务做出的一些实践总结。
2019-04-28 - 对于一些骗子使用微信支付商业版的问题!?
我不是来抬杠的,那一天我遇到一个网站lcwu.cn,来看看他的网站首页[图片] 妥妥的诈骗平台,高收益,日化利息?????? 然后我就想投诉这家伙,发现微信支付一分钱是无法投诉的(难道是给的钱太少???)[图片] 今天我又试了一下,仍然无法投诉,我就想问微信客服why? 然而微信客服电话打不通?我曹这服务质量....... 然后我就跟骗子聊天那[图片] 唉,真的是嚣张啊~ 再此之前呢我也遇到过这种诈骗平台,我也是付了一分钱,然后他居然给退回来了,退了我一分钱,然后我居然能投诉了???? 然而没有这么简单~ [图片] 系统繁忙?微信客服我就想问这个几个意思?
2019-04-04 - 2019-03-15
- 项目完全使用小程序云开发的填坑之路~
产品定位:轻婚恋社交。 愿景:年轻人的交友、婚恋好助手。 主要功能: 用户信息维护 首页推荐 IM 平台积分:红豆 后续功能扩展方向(社区、用户动态等等) 技术需求: 数据存储(微信云数据库) 文件存储(微信云存储) 支付(知晓云) CMS(知晓云) 模板消息(知晓云) IM(极光IM) (目前微信小程序云开发服务提供上比较多,做的比较早的有知晓云、野狗、bmob等等,不过我把主要逻辑和数据放在了微信云开发上面,因为是亲儿子嘛。哈哈哈) 重点说下IM选型的过程,因为前期是个人项目(现在已经团队化公司化运作),用户体验、成本是最重要考虑的因素。(其实成本是最主要的考虑,哈哈,因为没钱) 选型标的:腾讯通信云、网易云信、极光IM 腾讯通信云999元/月送10万日活,网易通信云1800元/月送1万日活、极光IM基础功能全免费 (其实在选型过程中找了很多服务商的商品,但是因为价格吓到我了,所以就不列举太多了啊,比如融云、环信、野狗等) 在选型体验中,产品demo做的最好的是网易云信,几乎可以拿来就直接上线了。 [代码]腾讯通信云demo只能说还过得去(考虑到是大公司做的,其实我内心评价是烂的要命),不过如果自身产品比较成熟、规模比较大的话,腾讯通信云是最好的选择,价格划算,性能稳定。 因为实在是穷,所以选了完全免费的极光IM,极光IM的demo比腾讯通信云好,比网易云信demo差一点,不过谁让我只差钱呢,哈哈,所以前期考虑极光IM,后续如果量大会迁移到腾讯通信云上。 [代码] 言归正传说说项目中走过的坑和告诉你怎么不要掉坑 坑1、云开发限额 建议1、基本上默认的限额只是给你开发测试用的,要上线和正常使用,建议提前给微信发邮件申请扩容 邮箱是:miniprogram@tencent.com 坑2、数据库不提供联表查询 建议2、业务逻辑上涉及到多表查的,建议使用云函数来实现,因为云函数部署在靠近云数据库的机房,理论上比使用小程序直接查询性能和体验上要好的多 坑3、云开发目前没有提供open api接口 项目上会涉及到运营后台、还有数据分析啥的 建议3.1、运营后台建议在现有小程序开一个隐秘入口 建议3.2、如果是涉及到个性化推荐和数据分析,按目前小程序官方云开发提供的服务是不能满足的,所以在做相关业务数据存储的时候,建议也写一份数据到另外的第三方云服务(比如知晓云) (后续感觉官方会提供open api接口,只是不知道啥时候,可能猴年马月吧,你懂的……) 坑4、云控制台数据库提供的数据导入功能很鸡肋 详情请看链接: https://developers.weixin.qq.com/community/develop/doc/000c46047a877882bfb7a69515b400 https://developers.weixin.qq.com/community/develop/doc/000ee271fbcc7812bd67e97b355400 建议4、做一个全局数据库初始化函数,把数据导入用函数来实现。(比如创建表、初始化数据啥的) 坑5、云函数环境配置目前没有比较优雅的统一管理方式 建议5、详情请看社区中一哥们的建议: https://developers.weixin.qq.com/community/develop/doc/000e2acb0589683fced77fdf553404 总结一下他的建议:提供一个主函数入口,实现其他云函数的路由。 缺点是:如果云函数太多,就会加载很慢,因为云函数在官方定义是轻量级的,用户请求的时候才加载文件,处理完请求后可能会把资源释放。 终极坑、官方云开发目前还处于社会主义初级阶段(哈哈哈),遇到问题还会比较多 终极建议、做好项目技术选型和需求调研 如果遇到问题掉坑实在走不出来,请记得把坑的详情记录下来,发到社区。(建议不要找官方客服,那只会浪费你的时间。哈哈) (持续更新中……)
2019-02-21 - 2019-02-26
- getPhoneNumber接口的一点建议
[图片] 如果微信用户没有绑定手机号,调用getPhoneNumber接口会弹出这个框,而这个框的“取消”按钮事件我们开发者却监听不到,作为正常用户(微信用户现在都是绑定了手机号的吧),即使没绑定,也可以点击右边按钮去绑定,然后登陆我们的小程序。问题来了: 我们的项目设计只有手机号登陆,倒是可以提供一个测试账号登录给审核,但放在“拒绝”手机授权(当微信绑定的有手机号时弹出的手机授权框)后弹出,但是如果你的微信没有绑定过手机号,拒绝手机授权那个框微信不会给你弹出来,而是弹出上面那个框,而这个框我们捕捉不到用户点击取消后的事件,无法做出相应处理 ,当然正常的用户是可以点击绑定手机号继续进行,但微信的审核人员没有电话卡,所以直接拒绝了,拒绝理由是审核人员测试机无法完成此操作,而我放在拒绝手机授权时弹出的账号密码登录框也没地方弹出来,因为那个授权框根本不会弹出来 我感觉官方可以考虑在1.getPhoneNumber这个接口加上failed回调(也就是检测到微信没有绑定手机号这种情况) 2.不要弹出上面第一张这种我们开发者不可控的弹框,仍然弹出[图片],但是提示未绑定手机号,此时的“拒绝”按钮事件,我们开发者就能捕捉到了 3.给审核人员配一张电话卡吧,这就好比我要吃饭,但是连筷子都没有,肯定吃不了哇, 如果是因为这个原因拒绝吃饭,是否有点尴尬
2019-02-27 - 微信小程序开发-76种动画 animate.css
1、微信小程序动画有自己的方法:官方链接 但需要自己去写动画效果,比较麻烦。 2、本文介绍的是把animate.css这个非常棒的css库引入到小程序内使用。 animate.css包含76种动画,使用非常简单。animate.css官网 : https://daneden.github.io/animate.css/ 3、由于小程序对代码大小限制比较大,所以删除了animate.css中 所有@-webkit-部分css,减少了一半体积 再把文件后缀名改为wxss,以后出来的百度小程序、支付宝小程序、今日头条小程序估计修改对应的后缀名就可以直接使用了。 下载地址:http://nodejs999.com/animate.wxss 4、放到小程序代码中,然后@import到app.wxss文件中。 我项目是把animate.wxss文件放在utils文件夹下。 所以在app.wxss中加入 @import './utils/animate.wxss'; 即可。 就可以像animate.css一样使用了。
2018-11-01