├── .gitattributes ├── LICENSE ├── README.md ├── app.js ├── app.json ├── app.wxss ├── components ├── menu │ ├── menu.js │ ├── menu.json │ ├── menu.wxml │ └── menu.wxss └── movemenu │ ├── movemenu.js │ ├── movemenu.json │ ├── movemenu.wxml │ └── movemenu.wxss ├── images ├── add.png ├── buy.png ├── home.png ├── key.png └── top.png ├── pages ├── index │ ├── index.js │ ├── index.json │ ├── index.wxml │ └── index.wxss └── logs │ ├── logs.js │ ├── logs.json │ ├── logs.wxml │ └── logs.wxss ├── project.config.json ├── show.gif ├── sitemap.json └── utils └── util.js /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 apple 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # 微信小程序可折叠菜单 2 | 3 | ![作品显示](show.gif) 4 | 5 | 6 | 1. 把components/menu文件拉入项目中 7 | 8 | 2. 在.json文件中,添加 9 | 10 | ``` 11 | { 12 | "usingComponents": { 13 | "menu": "/components/menu/menu" 14 | } 15 | } 16 | ``` 17 | 18 | 3. 在.wxml 文件,添加以下代码 19 | 20 | >bindmenuItemClick为按钮点击的时候的回调方法 mainmodel是显示的按钮,menulist为折叠的菜单的数组数据 21 | 22 | ``` 23 | 24 | 25 | ``` 26 | 4. 在.js里面实现方法 27 | 28 | ``` 29 | ,menuItemClick:function(res){ 30 | console.log(res); 31 | //获取点击事件的信息 32 | let clickInfo = res.detail.iteminfo 33 | console.log(clickInfo); 34 | // 根据不同类型进行判别处理 35 | //事件的处理 代码 36 | 37 | } 38 | ``` 39 | >data中根据自己的情况添加数据 40 | 41 | ``` 42 | menulist:[ 43 | { 44 | "id":"1", 45 | "url":"../../images/top.png", 46 | "title":"顶部", 47 | }, 48 | { 49 | "id": "2", 50 | "url": "../../images/add.png", 51 | "title": "添加", 52 | }, 53 | { 54 | "id": "3", 55 | "url": "../../images/buy.png", 56 | "title": "购物车", 57 | }, 58 | ], 59 | mainmodel:{ 60 | "url": "../../images/home.png", 61 | "title": "菜单", 62 | } 63 | ``` 64 | 65 | 完毕!O(∩_∩)O~~ 66 | -------------------------------------------------------------------------------- /app.js: -------------------------------------------------------------------------------- 1 | //app.js 2 | App({ 3 | onLaunch: function () { 4 | // 展示本地存储能力 5 | var logs = wx.getStorageSync('logs') || [] 6 | logs.unshift(Date.now()) 7 | wx.setStorageSync('logs', logs) 8 | 9 | // 登录 10 | wx.login({ 11 | success: res => { 12 | // 发送 res.code 到后台换取 openId, sessionKey, unionId 13 | } 14 | }) 15 | // 获取用户信息 16 | wx.getSetting({ 17 | success: res => { 18 | if (res.authSetting['scope.userInfo']) { 19 | // 已经授权,可以直接调用 getUserInfo 获取头像昵称,不会弹框 20 | wx.getUserInfo({ 21 | success: res => { 22 | // 可以将 res 发送给后台解码出 unionId 23 | this.globalData.userInfo = res.userInfo 24 | 25 | // 由于 getUserInfo 是网络请求,可能会在 Page.onLoad 之后才返回 26 | // 所以此处加入 callback 以防止这种情况 27 | if (this.userInfoReadyCallback) { 28 | this.userInfoReadyCallback(res) 29 | } 30 | } 31 | }) 32 | } 33 | } 34 | }) 35 | }, 36 | globalData: { 37 | userInfo: null 38 | } 39 | }) -------------------------------------------------------------------------------- /app.json: -------------------------------------------------------------------------------- 1 | { 2 | "pages": [ 3 | "pages/index/index", 4 | "pages/logs/logs" 5 | ], 6 | "window": { 7 | "backgroundTextStyle": "light", 8 | "navigationBarBackgroundColor": "#fff", 9 | "navigationBarTitleText": "WeChat", 10 | "navigationBarTextStyle": "black" 11 | }, 12 | "sitemapLocation": "sitemap.json" 13 | } -------------------------------------------------------------------------------- /app.wxss: -------------------------------------------------------------------------------- 1 | /**app.wxss**/ 2 | .container { 3 | height: 100%; 4 | display: flex; 5 | flex-direction: column; 6 | align-items: center; 7 | justify-content: space-between; 8 | padding: 200rpx 0; 9 | box-sizing: border-box; 10 | } 11 | -------------------------------------------------------------------------------- /components/menu/menu.js: -------------------------------------------------------------------------------- 1 | // components/menu/menu.js 2 | Component({ 3 | /** 4 | * 组件的属性列表 5 | */ 6 | properties: { 7 | mainmodel: { 8 | type: Object, 9 | value: {} 10 | }, 11 | menulist: { 12 | type: Object, 13 | value: [] 14 | } 15 | }, 16 | 17 | /** 18 | * 组件的初始数据 19 | */ 20 | data: { 21 | showmenus:true, 22 | }, 23 | 24 | /** 25 | * 组件的方法列表 26 | */ 27 | methods: { 28 | showclick:function(){ 29 | console.log("showclick") 30 | let isshow = !this.data.showmenus; 31 | console.log(isshow) 32 | this.setData({ 33 | showmenus: isshow, 34 | }) 35 | }, 36 | itemclick:function(e){ 37 | this.showclick(); 38 | console.log(e.currentTarget.dataset); 39 | let info = e.currentTarget.dataset.item; 40 | if (info){ 41 | this.triggerEvent('menuItemClick', { 42 | "iteminfo":info 43 | }) 44 | } 45 | } 46 | 47 | 48 | } 49 | }) 50 | -------------------------------------------------------------------------------- /components/menu/menu.json: -------------------------------------------------------------------------------- 1 | { 2 | "component": true, 3 | "usingComponents": {} 4 | } -------------------------------------------------------------------------------- /components/menu/menu.wxml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /components/menu/menu.wxss: -------------------------------------------------------------------------------- 1 | /* components/menu/menu.wxss */ 2 | 3 | 4 | 5 | .menu_box{ 6 | position: fixed; 7 | bottom: 150rpx; 8 | right: 30rpx; 9 | /* background-color: red; */ 10 | text-align: center; 11 | } 12 | .menu_main{ 13 | top: 10rpx; 14 | width: 100rpx; 15 | height: auto; 16 | background-color: rgb(214, 216, 221); 17 | } 18 | .menu_img{ 19 | margin-top: 10rpx; 20 | width: 50rpx; 21 | height: 50rpx; 22 | /* background-color: red; */ 23 | } 24 | .menu_title{ 25 | display: block; 26 | width: 100%; 27 | text-align: center; 28 | font-size: 30rpx; 29 | 30 | } 31 | -------------------------------------------------------------------------------- /components/movemenu/movemenu.js: -------------------------------------------------------------------------------- 1 | // components/menu/menu.js 2 | Component({ 3 | /** 4 | * 组件的属性列表 5 | */ 6 | properties: { 7 | mainmodel: { 8 | type: Object, 9 | value: {} 10 | }, 11 | menulist: { 12 | type: Object, 13 | value: [] 14 | } 15 | }, 16 | 17 | /** 18 | * 组件的初始数据 19 | */ 20 | data: { 21 | showmenus:true, 22 | }, 23 | 24 | /** 25 | * 组件的方法列表 26 | */ 27 | methods: { 28 | showclick:function(){ 29 | console.log("showclick") 30 | let isshow = !this.data.showmenus; 31 | console.log(isshow) 32 | this.setData({ 33 | showmenus: isshow, 34 | }) 35 | }, 36 | itemclick:function(e){ 37 | this.showclick(); 38 | console.log(e.currentTarget.dataset); 39 | let info = e.currentTarget.dataset.item; 40 | if (info){ 41 | this.triggerEvent('menuItemClick', { 42 | "iteminfo":info 43 | }) 44 | } 45 | } 46 | 47 | 48 | } 49 | }) 50 | -------------------------------------------------------------------------------- /components/movemenu/movemenu.json: -------------------------------------------------------------------------------- 1 | { 2 | "component": true, 3 | "usingComponents": {} 4 | } -------------------------------------------------------------------------------- /components/movemenu/movemenu.wxml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /components/movemenu/movemenu.wxss: -------------------------------------------------------------------------------- 1 | /* components/menu/menu.wxss */ 2 | movable-view { 3 | pointer-events: auto; 4 | } 5 | 6 | movable-area { 7 | pointer-events: none; 8 | } 9 | .menuarea{ 10 | position: fixed; 11 | left: .0rpx; 12 | right: .0rpx; 13 | top: .0rpx; 14 | bottom: .0rpx; 15 | height: 100%; 16 | width: 100%; 17 | } 18 | 19 | .menu_box{ 20 | position: fixed; 21 | bottom: 150rpx; 22 | right: 30rpx; 23 | /* background-color: red; */ 24 | text-align: center; 25 | } 26 | .menu_main{ 27 | top: 10rpx; 28 | width: 100rpx; 29 | height: auto; 30 | background-color: rgb(214, 216, 221); 31 | } 32 | .menu_img{ 33 | margin-top: 10rpx; 34 | width: 50rpx; 35 | height: 50rpx; 36 | /* background-color: red; */ 37 | } 38 | .menu_title{ 39 | display: block; 40 | width: 100%; 41 | text-align: center; 42 | font-size: 30rpx; 43 | 44 | } 45 | -------------------------------------------------------------------------------- /images/add.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WMSmile/floatmenu/ea499933489dc71afa28112888b8bd97c5fcc53f/images/add.png -------------------------------------------------------------------------------- /images/buy.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WMSmile/floatmenu/ea499933489dc71afa28112888b8bd97c5fcc53f/images/buy.png -------------------------------------------------------------------------------- /images/home.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WMSmile/floatmenu/ea499933489dc71afa28112888b8bd97c5fcc53f/images/home.png -------------------------------------------------------------------------------- /images/key.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WMSmile/floatmenu/ea499933489dc71afa28112888b8bd97c5fcc53f/images/key.png -------------------------------------------------------------------------------- /images/top.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WMSmile/floatmenu/ea499933489dc71afa28112888b8bd97c5fcc53f/images/top.png -------------------------------------------------------------------------------- /pages/index/index.js: -------------------------------------------------------------------------------- 1 | //index.js 2 | //获取应用实例 3 | const app = getApp() 4 | 5 | Page({ 6 | data: { 7 | motto: 'Hello World', 8 | userInfo: {}, 9 | hasUserInfo: false, 10 | canIUse: wx.canIUse('button.open-type.getUserInfo'), 11 | menulist:[ 12 | { 13 | "id":"1", 14 | "url":"../../images/top.png", 15 | "title":"顶部", 16 | }, 17 | { 18 | "id": "2", 19 | "url": "../../images/add.png", 20 | "title": "添加", 21 | }, 22 | { 23 | "id": "3", 24 | "url": "../../images/buy.png", 25 | "title": "购物车", 26 | }, 27 | ], 28 | mainmodel:{ 29 | "url": "../../images/home.png", 30 | "title": "菜单", 31 | } 32 | }, 33 | //事件处理函数 34 | bindViewTap: function() { 35 | wx.navigateTo({ 36 | url: '../logs/logs' 37 | }) 38 | }, 39 | onLoad: function () { 40 | if (app.globalData.userInfo) { 41 | this.setData({ 42 | userInfo: app.globalData.userInfo, 43 | hasUserInfo: true 44 | }) 45 | } else if (this.data.canIUse){ 46 | // 由于 getUserInfo 是网络请求,可能会在 Page.onLoad 之后才返回 47 | // 所以此处加入 callback 以防止这种情况 48 | app.userInfoReadyCallback = res => { 49 | this.setData({ 50 | userInfo: res.userInfo, 51 | hasUserInfo: true 52 | }) 53 | } 54 | } else { 55 | // 在没有 open-type=getUserInfo 版本的兼容处理 56 | wx.getUserInfo({ 57 | success: res => { 58 | app.globalData.userInfo = res.userInfo 59 | this.setData({ 60 | userInfo: res.userInfo, 61 | hasUserInfo: true 62 | }) 63 | } 64 | }) 65 | } 66 | }, 67 | getUserInfo: function(e) { 68 | console.log(e) 69 | app.globalData.userInfo = e.detail.userInfo 70 | this.setData({ 71 | userInfo: e.detail.userInfo, 72 | hasUserInfo: true 73 | }) 74 | } 75 | ,menuItemClick:function(res){ 76 | console.log(res); 77 | //获取点击事件的信息 78 | let clickInfo = res.detail.iteminfo 79 | console.log(clickInfo); 80 | // 根据不同类型进行判别处理 81 | //事件的处理 代码 82 | 83 | } 84 | }) 85 | -------------------------------------------------------------------------------- /pages/index/index.json: -------------------------------------------------------------------------------- 1 | { 2 | "usingComponents": { 3 | "menu": "/components/menu/menu", 4 | "movemenu": "/components/movemenu/movemenu" 5 | } 6 | } -------------------------------------------------------------------------------- /pages/index/index.wxml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 10 | 11 | 悬浮折叠菜单 12 | 13 | 14 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /pages/index/index.wxss: -------------------------------------------------------------------------------- 1 | /**index.wxss**/ 2 | .userinfo { 3 | display: flex; 4 | flex-direction: column; 5 | align-items: center; 6 | } 7 | 8 | .userinfo-avatar { 9 | width: 128rpx; 10 | height: 128rpx; 11 | margin: 20rpx; 12 | border-radius: 50%; 13 | } 14 | 15 | .userinfo-nickname { 16 | color: #aaa; 17 | } 18 | 19 | .usermotto { 20 | margin-top: 100px; 21 | } -------------------------------------------------------------------------------- /pages/logs/logs.js: -------------------------------------------------------------------------------- 1 | //logs.js 2 | const util = require('../../utils/util.js') 3 | 4 | Page({ 5 | data: { 6 | logs: [] 7 | }, 8 | onLoad: function () { 9 | this.setData({ 10 | logs: (wx.getStorageSync('logs') || []).map(log => { 11 | return util.formatTime(new Date(log)) 12 | }) 13 | }) 14 | } 15 | }) 16 | -------------------------------------------------------------------------------- /pages/logs/logs.json: -------------------------------------------------------------------------------- 1 | { 2 | "navigationBarTitleText": "查看启动日志" 3 | } -------------------------------------------------------------------------------- /pages/logs/logs.wxml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | {{index + 1}}. {{log}} 5 | 6 | 7 | -------------------------------------------------------------------------------- /pages/logs/logs.wxss: -------------------------------------------------------------------------------- 1 | .log-list { 2 | display: flex; 3 | flex-direction: column; 4 | padding: 40rpx; 5 | } 6 | .log-item { 7 | margin: 10rpx; 8 | } 9 | -------------------------------------------------------------------------------- /project.config.json: -------------------------------------------------------------------------------- 1 | { 2 | "description": "项目配置文件", 3 | "packOptions": { 4 | "ignore": [] 5 | }, 6 | "setting": { 7 | "urlCheck": true, 8 | "es6": true, 9 | "postcss": true, 10 | "minified": true, 11 | "newFeature": true 12 | }, 13 | "compileType": "miniprogram", 14 | "libVersion": "2.3.2", 15 | "appid": "wx425b9026d4883ccf", 16 | "projectname": "floatmenu", 17 | "debugOptions": { 18 | "hidedInDevtools": [] 19 | }, 20 | "isGameTourist": false, 21 | "simulatorType": "wechat", 22 | "simulatorPluginLibVersion": {}, 23 | "condition": { 24 | "search": { 25 | "current": -1, 26 | "list": [] 27 | }, 28 | "conversation": { 29 | "current": -1, 30 | "list": [] 31 | }, 32 | "game": { 33 | "currentL": -1, 34 | "list": [] 35 | }, 36 | "miniprogram": { 37 | "current": -1, 38 | "list": [] 39 | } 40 | } 41 | } -------------------------------------------------------------------------------- /show.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WMSmile/floatmenu/ea499933489dc71afa28112888b8bd97c5fcc53f/show.gif -------------------------------------------------------------------------------- /sitemap.json: -------------------------------------------------------------------------------- 1 | { 2 | "desc": "关于本文件的更多信息,请参考文档 https://developers.weixin.qq.com/miniprogram/dev/framework/sitemap.html", 3 | "rules": [{ 4 | "action": "allow", 5 | "page": "*" 6 | }] 7 | } -------------------------------------------------------------------------------- /utils/util.js: -------------------------------------------------------------------------------- 1 | const formatTime = date => { 2 | const year = date.getFullYear() 3 | const month = date.getMonth() + 1 4 | const day = date.getDate() 5 | const hour = date.getHours() 6 | const minute = date.getMinutes() 7 | const second = date.getSeconds() 8 | 9 | return [year, month, day].map(formatNumber).join('/') + ' ' + [hour, minute, second].map(formatNumber).join(':') 10 | } 11 | 12 | const formatNumber = n => { 13 | n = n.toString() 14 | return n[1] ? n : '0' + n 15 | } 16 | 17 | module.exports = { 18 | formatTime: formatTime 19 | } 20 | --------------------------------------------------------------------------------