- 自适应 tabBar 组件 不是底部的哦
https://developers.weixin.qq.com/s/47VZSGmR7Q7w 这是代码片段链接 项目中有好多地方都需要用到 navbar ,一个项目中重复的使用同一段代码感觉很烦人,所以就自己写了一个,适合 2-4 个 tab,【支持多个】多个的话稍微修改一下布局就可以了 ━((′д`)爻(′д`))━!!!-图片传不上去 大家可以 打开代码链接看一下 如果感觉写的还凑合的 帮忙点个赞! 有什么可以改进的也可以 在下方评论
2019-04-17 - 发送短信验证码后60秒倒计时
微信小程序发送短信验证码后60秒倒计时功能,效果图: [图片] 完整代码 index.wxml [代码]<!--index.wxml-->[代码][代码]<view class=[代码][代码]"container"[代码][代码]>[代码][代码] [代码][代码]<view class=[代码][代码]"section"[代码][代码]>[代码][代码] [代码][代码]<text>手机号码:</text>[代码][代码] [代码][代码]<input placeholder=[代码][代码]"请输入手机号码"[代码] [代码]type=[代码][代码]"number"[代码] [代码]maxlength=[代码][代码]"11"[代码] [代码]bindinput=[代码][代码]"inputPhoneNum"[代码] [代码]auto-focus />[代码][代码] [代码][代码]<text wx:if=[代码][代码]"{{send}}"[代码] [代码]class=[代码][代码]"sendMsg"[代码] [代码]bindtap=[代码][代码]"sendMsg"[代码][代码]>发送</text>[代码][代码] [代码][代码]<text wx:if=[代码][代码]"{{alreadySend}}"[代码] [代码]class=[代码][代码]"sendMsg"[代码] [代码]>{{second+[代码][代码]"s"[代码][代码]}}</text>[代码][代码] [代码][代码]</view>[代码][代码]</view>[代码] index.wxss [代码]/**index.wxss**/[代码][代码].userinfo {[代码][代码] [代码][代码]display[代码][代码]: flex;[代码][代码] [代码][代码]flex-[代码][代码]direction[代码][代码]: column;[代码][代码] [代码][代码]align-items: [代码][代码]center[代码][代码];[代码][代码]}[代码][代码].section {[代码][代码]display[代码][代码]: flex;[代码][代码]margin[代码][代码]: [代码][代码]16[代码][代码]rpx;[代码][代码]padding[代码][代码]: [代码][代码]16[代码][代码]rpx;[代码][代码]border-bottom[代码][代码]: [代码][代码]1[代码][代码]rpx [代码][代码]solid[代码] [代码]#CFD8DC[代码][代码];[代码][代码]}[代码][代码] [代码] [代码]text {[代码][代码] [代码][代码]width[代码][代码]: [代码][代码]200[代码][代码]rpx;[代码][代码]}[代码][代码] [代码] [代码]button {[代码][代码] [代码][代码]margin[代码][代码]: [代码][代码]16[代码][代码]rpx;[代码][代码]}[代码][代码] [代码] [代码].sendMsg {[代码][代码] [代码][代码]font-size[代码][代码]: [代码][代码]12[代码][代码];[代码][代码] [代码][代码]margin-right[代码][代码]: [代码][代码]0[代码][代码];[代码][代码] [代码][代码]padding[代码][代码]: [代码][代码]0[代码][代码];[代码][代码] [代码][代码]height[代码][代码]: inherit;[代码][代码] [代码][代码]width[代码][代码]: [代码][代码]80[代码][代码]rpx;[代码][代码]}[代码]index.js [代码]//index.js[代码][代码]//获取应用实例[代码][代码]const app = getApp()[代码][代码] [代码] [代码]Page({[代码][代码] [代码][代码]data: {[代码][代码] [代码][代码]send: true,[代码][代码] [代码][代码]alreadySend: false,[代码][代码] [代码][代码]second: [代码][代码]60[代码][代码],[代码][代码] [代码][代码]disabled: true,[代码][代码] [代码][代码]phoneNum: [代码][代码]''[代码][代码] [代码][代码]},[代码][代码] [代码][代码]// 手机号部分[代码][代码] [代码][代码]inputPhoneNum: function (e) {[代码][代码] [代码][代码]let phoneNum = e.detail.value[代码][代码] [代码][代码]this.setData({[代码][代码] [代码][代码]phoneNum: phoneNum[代码][代码] [代码][代码]})[代码][代码] [代码][代码]},[代码][代码] [代码][代码]sendMsg: function () {[代码][代码] [代码][代码]var phoneNum = this.data.phoneNum;[代码][代码] [代码][代码]if(phoneNum == [代码][代码]''[代码][代码]){[代码][代码] [代码][代码]wx.showToast({[代码][代码] [代码][代码]title: [代码][代码]'请输入手机号码'[代码][代码],[代码][代码] [代码][代码]icon: [代码][代码]'none'[代码][代码],[代码][代码] [代码][代码]duration: [代码][代码]2000[代码][代码] [代码][代码]})[代码][代码] [代码][代码]return ;[代码][代码] [代码][代码]}[代码][代码] [代码][代码]//此处省略发送短信验证码功能[代码][代码] [代码][代码]this.setData({[代码][代码] [代码][代码]alreadySend: true,[代码][代码] [代码][代码]send: false[代码][代码] [代码][代码]})[代码][代码] [代码][代码]this.timer()[代码][代码] [代码][代码]},[代码][代码] [代码][代码]showSendMsg: function () {[代码][代码] [代码][代码]if (!this.data.alreadySend) {[代码][代码] [代码][代码]this.setData({[代码][代码] [代码][代码]send: true[代码][代码] [代码][代码]})[代码][代码] [代码][代码]}[代码][代码] [代码][代码]},[代码][代码] [代码][代码]hideSendMsg: function () {[代码][代码] [代码][代码]this.setData({[代码][代码] [代码][代码]send: false,[代码][代码] [代码][代码]disabled: true,[代码][代码] [代码][代码]buttonType: [代码][代码]'default'[代码][代码] [代码][代码]})[代码][代码] [代码][代码]},[代码][代码] [代码][代码]timer: function () {[代码][代码] [代码][代码]let promise = new Promise((resolve, reject) => {[代码][代码] [代码][代码]let setTimer = setInterval([代码][代码] [代码][代码]() => {[代码][代码] [代码][代码]this.setData({[代码][代码] [代码][代码]second: this.data.second - [代码][代码]1[代码][代码] [代码][代码]})[代码][代码] [代码][代码]if (this.data.second <= [代码][代码]0[代码][代码]) {[代码][代码] [代码][代码]this.setData({[代码][代码] [代码][代码]second: [代码][代码]60[代码][代码],[代码][代码] [代码][代码]alreadySend: false,[代码][代码] [代码][代码]send: true[代码][代码] [代码][代码]})[代码][代码] [代码][代码]resolve(setTimer)[代码][代码] [代码][代码]}[代码][代码] [代码][代码]}[代码][代码] [代码][代码], [代码][代码]1000[代码][代码])[代码][代码] [代码][代码]})[代码][代码] [代码][代码]promise.then((setTimer) => {[代码][代码] [代码][代码]clearInterval(setTimer)[代码][代码] [代码][代码]})[代码][代码] [代码][代码]},[代码][代码]})[代码]完整的短信验证码登录实例参考: https://blog.csdn.net/zuoliangzhu/article/details/81219900
2019-04-17 - 开启websocket服务端口,调试微信websocket接口方法
使用node环境,在vscode 工具中,创建 app.js 文件 ,代码如下,记得安装 npm install websocket 和 npm install http 模块 . 开启 websocket接口服务后,就可以去封装 官方提供的 wx.sendSocketMessage 等接口了。 [代码]const http = require("http"); const WebSocketServer = require("websocket").server; const httpServer = http.createServer((request, response) => { console.log("[" + new Date() + "] Received request for " + request.url); response.writeHead(404); response.end(); }); const wsServer = new WebSocketServer({ httpServer, autoAcceptConnections: true }); wsServer.on("connect", connection => { connection .on("message", message => { if (message.type === "utf8") { console.log(">> message content from client: " + message.utf8Data); connection.sendUTF(message.utf8Data); // 输出内容返回给前端接口调用 } }) .on("close", (reasonCode, description) => { console.log( "[" + new Date() + "] Peer " + connection.remoteAddress + " disconnected." ); }); }); httpServer.listen(8080, () => { console.log("[" + new Date() + "] Serveris listening on port 8080"); }); #小程序页面示例代码,请参考文档 const socketOpen = false const socketMsgQueue = [] wx.connectSocket({ // url: 'test.php', url :“ws://localhost:8080/” }) wx.onSocketOpen(function (res) { socketOpen = true for (let i = 0; i < socketMsgQueue.length; i++) { sendSocketMessage(socketMsgQueue[i]) } socketMsgQueue = [] }) function sendSocketMessage(msg) { if (socketOpen) { wx.sendSocketMessage({ data: msg }) } else { socketMsgQueue.push(msg) } }[代码]
2019-04-18 - 图片实现渐变/透明效果
众所周知,图片等一些盒子都可以利用opacity属性来设置不透明度,但是前两天我朋友忽然给我一个截图,截图效果如下 [图片] 图中红框圈住的位置图片或者说摄像头采集的画面出现了渐变到透明,可以清楚的看到可以看到后面小哥的胳膊,然后问我如何实现这种效果,这下把我难住了(呵 天天给我出难题),我开始在个大论坛开始寻找解决方案; 忽然在前天,日常逛论坛时看到一个文字投影的效果,而后忽然灵机一动就想,能不能变相的实现前两天我想要的那种效果,于是乎赶紧打开编辑器试了下,发现确实可以把我想要的图片或者盒子进行投影并给投影设置上渐变颜色及透明,结果出来了,只不过出来的效果他反了 [图片] 随后利用transform: rotate(180deg);控制他使出倒挂金钩此等功夫,果然不负所望,成功翻转过来 [图片] 但是我想要的只有投影,因为我想要效果目前只能用投影去实现去控制,但是他却本体与投影共同出现了,我不想看到本体,太丑了,怎么办呢,那就给他装个position: absolute; top给他爸爸装个position: relative; overflow: hidden;让他滚出~,结果显而易见,我胜利了; [图片] 我得到了我想要的结果,为了验证结果,我用文字放在他的下方 看看是否透明; [图片] 我真的成功了,哈哈(小开心一会儿),为了再次确认他真是的图片实现了渐变透明,我把渐变的透明度改成了1(也就是不透明) [图片] 事实证明,我真的成功了!!! 吹完牛皮,赶紧附上完成代码: css: [图片] html: [图片] 最终效果图: [图片] 呃…其实核心就是利用投影来完成的-webkit-box-reflect: below 0 linear-gradient(rgba(0, 0, 0, 0.2), rgba(0, 0, 0, 1) 100%); https://www.w3cschool.cn/css3/box-reflect.html 当然 肯定有大佬在我之前发现这种实现方式,不过当时我找了很久都没找到实现方式的写法,想了想 就发出来吧,如果有什么不对的地方,或者有其他方式也可以实现同等效果的话 还劳请告知,在下多谢各位大佬了!!!
2019-04-19 - 富文本组件体验小程序
简介 上周发布的 新富文本显示组件 收获了许多关注,为方便大家了解和体验,[代码]demo[代码] 小程序上线啦 [图片] 大家可以在这里查看介绍和示例或者进行自定义的测试,发现任何问题都欢迎反馈哦 立即体验 [图片] GitHub链接 Github链接
2020-12-27 - 微信小程序实现时间轴和地区列表的功能
老规矩先看效果图 [图片] 先来看左图的地区列表是如何实现的。 我们在解析数据之前,要先看下数据结构 [代码][{ "_id": "XL28U3kPDdDCJ9m0", "item": { "diqu": "北京", "list": [{ "id": "XL27oeSiwXKAQuFR", "name": "清华大学", "img": "https://ss0.baidu.com/6ONWsjip0QIZ8tyhnq/it/u=2693386884,1727296839\u0026fm=58\u0026bpow=1200\u0026bpoh=1200" }, { "id": "XL27oeSiwXKAQuF1", "name": "北京大学", "img": "https://ss2.baidu.com/6ONYsjip0QIZ8tyhnq/it/u=2152123166,2178049351\u0026fm=58\u0026bpow=1080\u0026bpoh=1080" }, { "id": "XL27oeSiwXKAQuF2", "name": "人民大学", "img": "https://ss1.baidu.com/6ONXsjip0QIZ8tyhnq/it/u=2642337058,1598432384\u0026fm=58\u0026w=121\u0026h=140\u0026img.PNG" }] } }, { "_id": "XL28U3kPDdDCJ9m1", "item": { "diqu": "杭州", "list": [{ "id": "XL27oeSiwXKAQuF3", "name": "杭州师范大学", "img": "https://ss0.baidu.com/6ONWsjip0QIZ8tyhnq/it/u=2219745018,1861674512\u0026fm=58\u0026bpow=475\u0026bpoh=475" }, { "id": "XL27oeSiwXKAQuF4", "name": "浙江大学", "img": "https://ss2.baidu.com/6ONYsjip0QIZ8tyhnq/it/u=3694367183,2414886214\u0026fm=58\u0026bpow=995\u0026bpoh=995" }] } }] [代码] 这里有两条数据,一个是北京地区的,一个是杭州地区的,正好对应我们图上的地区。然后每条json数据里面包含一个学校list,比如北京地区有清华大学,北京大学,人民大学。而每个大学对象里又包含学校id,学校名,学校校徽。 有了上面的源数据,接下来我们就看具体的实现 首先是wxml文件,其实很简单,就是一个大的列表用来显示地区,大列表里面又有一个小的列表用来显示学校。 [代码]<!--index.wxml--> <!-- 列表 --> <block wx:for="{{dataList}}" wx:key="item"> <view class='item-root'> <text class='title'>{{item.item.diqu}}</text> <block wx:for="{{item.item.list}}" wx:key="item"> <view class='img-root' bindtap='goDetail' data-item='{{item}}'> <image class='img' src='{{item.img}}'></image> <text class='xuexiao'>{{item.name}}</text> </view> </block> </view> </block> [代码] 然后是wxss文件 [代码]/* pages/myorder/myorder.wxss */ page { background: #fff; } .item-root { display: flex; flex-direction: column; } .title { width: 100%; background: gainsboro; } .img-root { display: flex; margin-left: 15px; margin-top: 5px; border-bottom: solid 1px gainsboro; } .img { width: 30px; height: 30px; } .xuexiao { margin: 5px 10px; flex: 1; } [代码] 至于如何把源数据json解析并显示到列表中,可以参考我之前写的解析本地json到列表。 《列表功能实现和本地json数据解析》: https://www.kancloud.cn/java-qiushi/xiaochengxu/767304 [图片] 视频讲解: https://edu.csdn.net/course/play/9531/202161 [图片] 到这里我们的地区列表就轻松的实现了,再来看下时间轴列表的实现 小程序时间轴列表实现 [图片] 还是先看数据源,我们拿清华大学为例 [代码]{ "_id": "XL27oeSiwXKAQuFR", "name": "清华大学", "desc": "清华大学始建与1900年,位于北京", "img": "https://ss0.baidu.com/6ONWsjip0QIZ8tyhnq/it/u=2693386884,1727296839\u0026fm=58\u0026bpow=1200\u0026bpoh=1200", "wangzhi": "http://www.tsinghua.edu.cn", "diqu": "北京市海淀区", "newsList": [{ "time": "2019年4月1日", "content": "招聘职位:英语老师,数学老师,物理老师", "title": "逸夫楼3楼大厅北京新东方专场招聘会" }, { "time": "2019年3月25日", "title": "北京京东专场招聘", "content": "招聘岗位:管培生,总裁助理,总经理" }] } [代码] 可以看到我们是顶部的学校信息,和底部的newsList组成,newsList就是我们时间轴的具体数据源。下面我们就来看看实现代码。 wxml文件如下,注释里写的很清楚了 [代码]<view class='top-root'> <view class='img-root'> <image class='img' src='{{deatil.img}}'></image> </view> <view class='top-desc-root'> <text class='xiangqing'>{{deatil.name}}</text> <text class='xiangqing'>网址:{{deatil.wangzhi}}</text> <text class='xiangqing'>地区:{{deatil.diqu}}</text> </view> </view> <!-- 时间轴 --> <view class="listview-container"> <block wx:for="{{newsList}}" wx:key="item"> <view class="playlog-item" bindtap="itemTapped"> <view class="dotline"> <!-- 竖线 --> <view class="line"></view> <!-- 圆点 --> <view class="dot"></view> <!-- 时间戳 --> </view> <view class="content"> <text class="course">{{item.time}}</text> <text class="course">{{item.title}}</text> <text class="chapter">{{item.content}}</text> </view> </view> <ad unit-id="adunit-5abb45645905fc90" wx:if="{{index % 5 == 4}}"></ad> </block> </view> [代码] wxss样式文件如下 [代码]page { background: #fff; } .top-root { display: flex; flex-wrap: nowrap; flex-direction: row; } .img-root { height: 40px; width: 40px; margin: 5px; } .img { width: 100%; height: 100%; } .top-desc-root { flex: 1; display: flex; flex-direction: column; } .xiangqing { font-size: 28rpx; color: #000; } /*时间轴*/ /*外部容器*/ .listview-container { margin: 10rpx 10rpx; } /*行样式*/ .playlog-item { display: flex; } /*时间轴*/ .playlog-item .dotline { width: 35px; position: relative; } /*竖线*/ .playlog-item .dotline .line { width: 1px; height: 100%; background: #ccc; position: absolute; top: 0; left: 15px; } /*圆点*/ .playlog-item .dotline .dot { width: 11px; height: 11px; background: #30ac63; position: absolute; top: 10px; left: 10px; border-radius: 50%; } /*时间戳*/ .playlog-item .dotline .time { width: 100%; position: absolute; margin-top: 30px; z-index: 99; font-size: 12px; color: #777; text-align: center; } /*右侧主体内容*/ .playlog-item .content { width: 100%; display: flex; flex-direction: column; border-bottom: 1px solid #ddd; margin: 3px 0; } /*章节部分*/ .playlog-item .content .chapter { font-size: 30rpx; line-height: 68rpx; color: #444; white-space: normal; padding-right: 10px; } /*课程部分*/ .playlog-item .content .course { font-size: 28rpx; line-height: 56rpx; color: #999; } [代码] 到这里时间的样式就已经实现了,我们接下来要做的就是把数据源json数据解析到页面上。方式有如下三种 1,把json放本地 2,把json导入到云开发数据 3,把json放到我们自己的服务器后台 下面我简单已放在云开发数据库并请求解析为例 先看下我云开发后台数据库 [图片] 然后写个云函数去获取云开发数据库里的json数据源,就是上图红色框里的数据 [图片] 可以看到我们成功的请求到了云数据库里的数据到本地。并成功解析并渲染到页面上了。是不是很简单。 当然,实现这些你还需要有一定的云开发知识。 同样为大家提供了云开发视频讲解:https://edu.csdn.net/course/detail/9604 有任何关于编程的问题都可以加我微信2501902696(备注编程开发) 编程小石头,码农一枚,非著名全栈开发人员。分享自己的一些经验,学习心得,希望后来人少走弯路,少填坑。 [图片]
2019-04-24 - 路由的封装
小程序提供了路由功能来实现页面跳转,但是在使用的过程中我们还是发现有些不方便的地方,通过封装,我们可以实现诸如路由管理、简化api等功能。 页面的跳转存在哪些问题呢? 与接口的调用一样面临url的管理问题; 传递参数的方式不太友好,只能拼装url; 参数类型单一,只支持string。 alias 第一个问题很好解决,我们做一个集中管理,比如新建一个[代码]router/routes.js[代码]文件来实现alias: [代码]// routes.js module.exports = { // 主页 home: '/pages/index/index', // 个人中心 uc: '/pages/user_center/index', }; [代码] 然后使用的时候变成这样: [代码]const routes = require('../../router/routes.js'); Page({ onReady() { wx.navigateTo({ url: routes.uc, }); }, }); [代码] query 第二个问题,我们先来看个例子,假如我们跳转[代码]pages/user_center/index[代码]页面的同时还要传[代码]userId[代码]过去,正常情况下是这么来操作的: [代码]const routes = require('../../router/routes.js'); Page({ onReady() { const userId = '123456'; wx.navigateTo({ url: `${routes.uc}?userId=${userId}`, }); }, }); [代码] 这样确实不好看,我能不能把参数部分单独拿出来,不用拼接到url上呢? 可以,我们试着实现一个[代码]navigateTo[代码]函数: [代码]const routes = require('../../router/routes.js'); function navigateTo({ url, query }) { const queryStr = Object.keys(query).map(k => `${k}=${query[k]}`).join('&'); wx.navigateTo({ url: `${url}?${queryStr}`, }); } Page({ onReady() { const userId = '123456'; navigateTo({ url: routes.uc, query: { userId, }, }); }, }); [代码] 嗯,这样貌似舒服一点。 参数保真 第三个问题的情况是,当我们传递的参数argument不是[代码]string[代码],而是[代码]number[代码]或者[代码]boolean[代码]时,也只能在下个页面得到一个[代码]string[代码]值: [代码]// pages/index/index.js Page({ onReady() { navigateTo({ url: routes.uc, query: { isActive: true, }, }); }, }); // pages/user_center/index.js Page({ onLoad(options) { console.log(options.isActive); // => "true" console.log(typeof options.isActive); // => "string" console.log(options.isActive === true); // => false }, }); [代码] 上面这种情况想必很多人都遇到过,而且感到很抓狂,本来就想传递一个boolean,结果不管传什么都会变成string。 有什么办法可以让数据变成字符串之后,还能还原成原来的类型? 好熟悉,这不就是json吗?我们把要传的数据转成json字符串([代码]JSON.stringify[代码]),然后在下个页面把它转回json数据([代码]JSON.parse[代码])不就好了嘛! 我们试着修改原来的[代码]navigateTo[代码]: [代码]const routes = require('../../router/routes.js'); function navigateTo({ url, data }) { const dataStr = JSON.stringify(data); wx.navigateTo({ url: `${url}?jsonStr=${dataStr}`, }); } Page({ onReady() { navigateTo({ url: routes.uc, data: { isActive: true, }, }); }, }); [代码] 这样我们在页面中接受json字符串并转换它: [代码]// pages/user_center/index.js Page({ onLoad(options) { const json = JSON.parse(options.jsonStr); console.log(json.isActive); // => true console.log(typeof json.isActive); // => "boolean" console.log(json.isActive === true); // => true }, }); [代码] 这里其实隐藏了一个问题,那就是url的转义,假如json字符串中包含了类似[代码]?[代码]、[代码]&[代码]之类的符号,可能导致我们参数解析出错,所以我们要把json字符串encode一下: [代码]function navigateTo({ url, data }) { const dataStr = encodeURIComponent(JSON.stringify(data)); wx.navigateTo({ url: `${url}?encodedData=${dataStr}`, }); } // pages/user_center/index.js Page({ onLoad(options) { const json = JSON.parse(decodeURIComponent(options.encodedData)); console.log(json.isActive); // => true console.log(typeof json.isActive); // => "boolean" console.log(json.isActive === true); // => true }, }); [代码] 这样使用起来不方便,我们封装一下,新建文件[代码]router/index.js[代码]: [代码]const routes = require('./routes.js'); function navigateTo({ url, data }) { const dataStr = encodeURIComponent(JSON.stringify(data)); wx.navigateTo({ url: `${url}?encodedData=${dataStr}`, }); } function extract(options) { return JSON.parse(decodeURIComponent(options.encodedData)); } module.exports = { routes, navigateTo, extract, }; [代码] 页面中我们这样来使用: [代码]const router = require('../../router/index.js'); // page home Page({ onLoad(options) { router.navigateTo({ url: router.routes.uc, data: { isActive: true, }, }); }, }); // page uc Page({ onLoad(options) { const json = router.extract(options); console.log(json.isActive); // => true console.log(typeof json.isActive); // => "boolean" console.log(json.isActive === true); // => true }, }); [代码] route name 这样貌似还不错,但是[代码]router.navigateTo[代码]不太好记,[代码]router.routes.uc[代码]有点冗长,我们考虑把[代码]navigateTo[代码]换成简单的[代码]push[代码],至于路由,我们可以使用[代码]name[代码]的方式来替换原来[代码]url[代码]参数: [代码]const routes = require('./routes.js'); function push({ name, data }) { const dataStr = encodeURIComponent(JSON.stringify(data)); const url = routes[name]; wx.navigateTo({ url: `${url}?encodedData=${dataStr}`, }); } function extract(options) { return JSON.parse(decodeURIComponent(options.encodedData)); } module.exports = { push, extract, }; [代码] 在页面中使用: [代码]const router = require('../../router/index.js'); Page({ onLoad(options) { router.push({ name: 'uc', data: { isActive: true, }, }); }, }); [代码] navigateTo or switchTab 页面跳转除了navigateTo之外还有switchTab,我们是不是可以把这个差异抹掉?答案是肯定的,如果我们在配置routes的时候就已经指定是普通页面还是tab页面,那么程序完全可以切换到对应的跳转方式。 我们修改一下[代码]router/routes.js[代码],假设home是一个tab页面: [代码]module.exports = { // 主页 home: { type: 'tab', path: '/pages/index/index', }, uc: { path: '/pages/a/index', }, }; [代码] 然后修改[代码]router/index.js[代码]中[代码]push[代码]的实现: [代码]function push({ name, data }) { const dataStr = encodeURIComponent(JSON.stringify(data)); const route = routes[name]; if (route.type === 'tab') { wx.switchTab({ url: `${route.path}`, // 注意tab页面是不支持传参的 }); return; } wx.navigateTo({ url: `${route.path}?encodedData=${dataStr}`, }); } [代码] 搞定,这样我们一个[代码]router.push[代码]就能自动切换两种跳转方式了,而且之后一旦页面类型有变动,我们也只需要修改[代码]route[代码]的定义就可以了。 直接寻址 alias用着很不错,但是有一点挺麻烦得就是每新建一个页面都要写一个alias,即使没有别名的需要,我们是不是可以处理一下,如果在alias没命中,那就直接把name转化成url?这也是阔以的。 [代码]function push({ name, data }) { const dataStr = encodeURIComponent(JSON.stringify(data)); const route = routes[name]; const url = route ? route.path : name; if (route.type === 'tab') { wx.switchTab({ url: `${url}`, // 注意tab页面是不支持传参的 }); return; } wx.navigateTo({ url: `${url}?encodedData=${dataStr}`, }); } [代码] 在页面中使用: [代码]Page({ onLoad(options) { router.push({ name: 'pages/user_center/a/index', data: { isActive: true, }, }); }, }); [代码] 注意,为了方便维护,我们规定了每个页面都必须存放在一个特定的文件夹,一个文件夹的当前路径下只能存在一个index页面,比如[代码]pages/index[代码]下面会存放[代码]pages/index/index.js[代码]、[代码]pages/index/index.wxml[代码]、[代码]pages/index/index.wxss[代码]、[代码]pages/index/index.json[代码],这时候你就不能继续在这个文件夹根路径存放另外一个页面,而必须是新建一个文件夹来存放,比如[代码]pages/index/pageB/index.js[代码]、[代码]pages/index/pageB/index.wxml[代码]、[代码]pages/index/pageB/index.wxss[代码]、[代码]pages/index/pageB/index.json[代码]。 这样是能实现功能,但是这个name怎么看都跟alias风格差太多,我们试着定义一套转化规则,让直接寻址的name与alias风格统一一些,[代码]pages[代码]和[代码]index[代码]其实我们可以省略掉,[代码]/[代码]我们可以用[代码].[代码]来替换,那么原来的name就变成了[代码]user_center.a[代码]: [代码]Page({ onLoad(options) { router.push({ name: 'user_center.a', data: { isActive: true, }, }); }, }); [代码] 我们再来改进[代码]router/index.js[代码]中[代码]push[代码]的实现: [代码]function push({ name, data }) { const dataStr = encodeURIComponent(JSON.stringify(data)); const route = routes[name]; const url = route ? route.path : `pages/${name.replace(/\./g, '/')}/index`; if (route.type === 'tab') { wx.switchTab({ url: `${url}`, // 注意tab页面是不支持传参的 }); return; } wx.navigateTo({ url: `${url}?encodedData=${dataStr}`, }); } [代码] 这样一来,由于支持直接寻址,跳转home和uc还可以写成这样: [代码]router.push({ name: 'index', // => /pages/index/index }); router.push({ name: 'user_center', // => /pages/user_center/index }); [代码] 这样一来,除了一些tab页面以及特定的路由需要写alias之外,我们也不需要新增一个页面就写一条alias这么麻烦了。 其他 除了上面介绍的navigateTo和switchTab外,其实还有[代码]wx.redirectTo[代码]、[代码]wx.navigateBack[代码]以及[代码]wx.reLaunch[代码]等,我们也可以做一层封装,过程雷同,所以我们就不再一个个介绍,这里贴一下最终简化后的api以及原生api的映射关系: [代码]router.push => wx.navigateTo router.replace => wx.redirectTo router.pop => wx.navigateBack router.relaunch => wx.reLaunch [代码] 最终实现已经在发布在github上,感兴趣的朋友可以移步了解:mp-router。
2019-04-26 - 如何实现一个自定义导航栏
自定义导航栏在刚出的时候已经有很多实现方案了,但是还有大哥在问,那这里再贴下代码及原理: 首先在App.js的 onLaunch中获取当前手机机型头部状态栏的高度,单位为px,存在内存中,操作如下: [代码]onLaunch() { wx.getSystemInfo({ success: (res) => { this.globalData.statusBarHeight = res.statusBarHeight this.globalData.titleBarHeight = wx.getMenuButtonBoundingClientRect().bottom + wx.getMenuButtonBoundingClientRect().top - (res.statusBarHeight * 2) }, failure() { this.globalData.statusBarHeight = 0 this.globalData.titleBarHeight = 0 } }) } [代码] 然后需要在目录下新建个components文件夹,里面存放此次需要演示的文件 navigateTitle WXML 文件如下: [代码]<view class="navigate-container"> <view style="height:{{statusBarHeight}}px"></view> <view class="navigate-bar" style="height:{{titleBarHeight}}px"> <view class="navigate-icon"> <navigator class="navigator-back" open-type="navigateBack" wx:if="{{!isShowHome}}" /> <navigator class="navigator-home" open-type="switchTab" url="/pages/index/index" wx:else /> </view> <view class="navigate-title">{{title}}</view> <view class="navigate-icon"></view> </view> </view> <view class="navigate-line" style="height: {{statusBarHeight + titleBarHeight}}px; width: 100%;"></view> [代码] WXSS文件如下: [代码].navigate-container { position: fixed; top: 0; width: 100%; z-index: 9999; background: #FFF; } .navigate-bar { width: 100%; display: flex; justify-content: space-around; } .navigate-icon { width: 100rpx; height: 100rpx; display: flex; justify-content: space-around; } .navigate-title { width: 550rpx; text-align: center; line-height: 100rpx; font-size: 34rpx; color: #3c3c3c; font-weight: bold; text-overflow: ellipsis; overflow: hidden; white-space: nowrap; } /*箭头部分*/ .navigator-back { width: 36rpx; height: 36rpx; align-self: center; } .navigator-back:after { content: ''; display: block; width: 22rpx; height: 22rpx; border-right: 4rpx solid #000; border-top: 4rpx solid #000; transform: rotate(225deg); } .navigator-home { width: 56rpx; height: 56rpx; background: url(https://qiniu-image.qtshe.com/20190301home.png) no-repeat center center; background-size: 100% 100%; align-self: center; } [代码] JS如下: [代码]var app = getApp() Component({ data: { statusBarHeight: '', titleBarHeight: '', isShowHome: false }, properties: { //属性值可以在组件使用时指定 title: { type: String, value: '青团公益' } }, pageLifetimes: { // 组件所在页面的生命周期函数 show() { let pageContext = getCurrentPages() if (pageContext.length > 1) { this.setData({ isShowHome: false }) } else { this.setData({ isShowHome: true }) } } }, attached() { this.setData({ statusBarHeight: app.globalData.statusBarHeight, titleBarHeight: app.globalData.titleBarHeight }) }, methods: {} }) [代码] JSON如下: [代码]{ "component": true } [代码] 如何引用? 需要引用的页面JSON里配置: [代码]"navigationStyle": "custom", "usingComponents": { "navigate-title": "/pages/components/navigateTitle/index" } [代码] WXML [代码]<navigate-title title="青团社" /> [代码] 按上面步骤操作即可实现一个自定义的导航栏。 如何实现通栏的效果默认透明以及滚动更换title为白色背景,如下图所示: [图片] [图片] [图片] [图片] 最后代码片段如下: https://developers.weixin.qq.com/s/wi6Pglmv7s8P。 以下为收集到的社区老哥们的分享: @Yunior: 小程序顶部自定义导航组件实现原理及坑分享 @志军: 微信小程序自定义导航栏组件(完美适配所有手机),可自定义实现任何你想要的功能 @✨o0o有脾气的酸奶💤 [有点炫]自定义navigate+分包+自定义tabbar @安晓苏 分享一个自适应的自定义导航栏组件
2020-03-10