├── README.md ├── app.js ├── app.json ├── app.wxss ├── image └── nav_bar_edit.png ├── pages ├── album │ ├── album.js │ ├── album.json │ ├── album.wxml │ └── album.wxss ├── index │ ├── index.js │ ├── index.json │ ├── index.wxml │ └── index.wxss └── types │ ├── types.js │ ├── types.json │ ├── types.wxml │ └── types.wxss └── utils ├── WxNotificationCenter.js ├── dialog.js └── util.js /README.md: -------------------------------------------------------------------------------- 1 | # 微信小程序示例-BeautifulGirl 2 | 微信小程序的一个样例,也可以说是一个福利型的小程序,主要功能是展示美女模特图片,目前的版本包括3个页面:
3 | 1.首页:相册列表页面,按照类别显示美女图片的列表
4 | 2.图片列表页:用swiper展示一个相册下的所有图片
5 | 3.相册类别编辑页面
6 | Wechat APP Sample: An app shows pictures of beautiful girls 7 | # 预览 8 | ## 首页-相册列表页面 9 | ![](https://github.com/liumulin614/fe-demo/blob/master/bed/preview/%E9%A6%96%E9%A1%B5%E6%96%B0.png) 10 | ## 图片列表展示页 11 | ![](https://raw.githubusercontent.com/liumulin614/fe-demo/master/bed/preview/2_1.png) 12 | ## 相册类别编辑页 13 | ![](https://raw.githubusercontent.com/liumulin614/fe-demo/master/bed/preview/3_1.png) 14 | -------------------------------------------------------------------------------- /app.js: -------------------------------------------------------------------------------- 1 | //app.js 2 | App({ 3 | onLaunch: function () { 4 | //调用API从本地缓存中获取数据 5 | let types = wx.getStorageSync("types"); 6 | if(!types){ 7 | wx.setStorageSync("types", this.globalData.types); 8 | } 9 | }, 10 | getUserInfo:function(cb){ 11 | var that = this 12 | if(this.globalData.userInfo){ 13 | typeof cb == "function" && cb(this.globalData.userInfo) 14 | }else{ 15 | //调用登录接口 16 | wx.login({ 17 | success: function () { 18 | wx.getUserInfo({ 19 | success: function (res) { 20 | that.globalData.userInfo = res.userInfo 21 | typeof cb == "function" && cb(that.globalData.userInfo) 22 | } 23 | }) 24 | } 25 | }) 26 | } 27 | }, 28 | globalData:{ 29 | api:{ 30 | listBaseUrl:"https://route.showapi.com/959-1?showapi_appid=25744&showapi_sign=f3807528bd5d4a4ea6b2027e8286e0dc&type=", 31 | albumBaseurl:"https://route.showapi.com/959-2?id=%id%&showapi_appid=25744&showapi_sign=f3807528bd5d4a4ea6b2027e8286e0dc", 32 | }, 33 | currentType:'', 34 | types:[ 35 | { 36 | title:"比基尼", 37 | value:"bijini", 38 | is_show:true 39 | }, 40 | { 41 | title:"制服", 42 | value:"zhifu", 43 | is_show:true 44 | }, 45 | { 46 | title:"写真艺术", 47 | value:"nvyou", 48 | is_show:true 49 | }, 50 | { 51 | title:"性格美女", 52 | value:"xingge", 53 | is_show:true 54 | }, 55 | { 56 | title:"模特", 57 | value:"mote", 58 | is_show:true 59 | }, 60 | { 61 | title:"剧照", 62 | value:"yingshi", 63 | is_show:true 64 | }, 65 | { 66 | title:"自拍", 67 | value:"tpzp", 68 | is_show:true 69 | }, 70 | { 71 | title:"丝袜", 72 | value:"siwa", 73 | is_show:true 74 | }, 75 | { 76 | title:"裙装", 77 | value:"qunzhuang", 78 | is_show:true 79 | }, 80 | { 81 | title:"情趣", 82 | value:"qingqu", 83 | is_show:true 84 | }, 85 | ] 86 | }, 87 | 88 | }) -------------------------------------------------------------------------------- /app.json: -------------------------------------------------------------------------------- 1 | { 2 | "pages":[ 3 | "pages/index/index", 4 | "pages/album/album", 5 | "pages/types/types" 6 | ], 7 | "window":{ 8 | "backgroundTextStyle":"light", 9 | "navigationBarBackgroundColor": "#BE304D", 10 | "navigationBarTitleText": "看美女", 11 | "navigationBarTextStyle":"white" 12 | }, 13 | "debug":false 14 | } 15 | -------------------------------------------------------------------------------- /app.wxss: -------------------------------------------------------------------------------- 1 | /**app.wxss**/ 2 | page{ 3 | height: 100%; 4 | } 5 | .container { 6 | min-height: 100%; 7 | box-sizing: border-box; 8 | position: relative; 9 | } 10 | -------------------------------------------------------------------------------- /image/nav_bar_edit.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/liumulin614/BeautifulGirl/e80716fc8efc2847d4bad907cb04208008648dd8/image/nav_bar_edit.png -------------------------------------------------------------------------------- /pages/album/album.js: -------------------------------------------------------------------------------- 1 | var app = getApp() 2 | var dialog = require("../../utils/dialog") 3 | 4 | Page({ 5 | data:{ 6 | album:[], 7 | title:'', 8 | id:'', 9 | countShow:true, 10 | currentIndex:1 11 | }, 12 | onLoad:function(options){ 13 | this.setData({ 14 | title:options.title, 15 | id:options.id.replace("##","."), 16 | }) 17 | dialog.loading() 18 | //请求数据 19 | var that = this 20 | wx.request({ 21 | url:app.globalData.api.albumBaseurl.replace("%id%",this.data.id), 22 | success:function(ret){ 23 | ret = ret['data'] 24 | if(ret['showapi_res_code'] == 0 && ret['showapi_res_body']){ 25 | var imgList = ret['showapi_res_body']['imgList']; 26 | var imgObjList = []; 27 | imgList.forEach(function(item,index){ 28 | imgObjList.push({ 29 | url:item, 30 | w:750, 31 | h:375 32 | }) 33 | }) 34 | that.setData({ 35 | album:imgObjList, 36 | albumUrlList:imgList, 37 | total:imgList.length, 38 | loaded:0 39 | }) 40 | }else{ 41 | dialog.toast("网络出错啦~") 42 | } 43 | }, 44 | complete:function(){ 45 | setTimeout(function(){ 46 | dialog.hide() 47 | },1000) 48 | } 49 | }) 50 | }, 51 | onReady:function(){ 52 | wx.setNavigationBarTitle({title:this.data.title}) 53 | }, 54 | imageload:function(e){ 55 | var h = e.detail.height 56 | var w = e.detail.width 57 | var index = e.currentTarget.dataset.index 58 | var album = this.data.album 59 | album[index].h = parseInt(750 * h / w) 60 | this.setData({ 61 | album:album 62 | }) 63 | 64 | 65 | }, 66 | preiviewwImage(e){ 67 | wx.previewImage({ 68 | current:e.currentTarget.dataset.src, 69 | urls:this.data.albumUrlList 70 | }) 71 | }, 72 | swiperChange:function(e){ 73 | this.setData({currentIndex:parseInt(e.detail.current)+1}); 74 | }, 75 | imageLongTap:function(e){ 76 | wx.showActionSheet({ 77 | itemList:['保存图片'], 78 | success:function(res){ 79 | if(res.tapIndex == 0){ 80 | var imageSrc = e.currentTarget.dataset.src 81 | console.log(imageSrc) 82 | wx.downloadFile({ 83 | url: imageSrc, 84 | success: function(res) { 85 | console.log(res) 86 | wx.saveFile({ 87 | tempFilePath: res.tempFilePath, 88 | success: function(res){ 89 | console.log(res.savedFilePath) 90 | dialog.toast("保存成功") 91 | }, 92 | fail: function(e) { 93 | dialog.toast("保存出错") 94 | } 95 | }) 96 | }, 97 | fail:function(e){ 98 | dialog.toast("图片下载失败") 99 | } 100 | }) 101 | } 102 | } 103 | }) 104 | }, 105 | hideCount:function(){ 106 | this.setData({countShow:false}) 107 | } 108 | }) -------------------------------------------------------------------------------- /pages/album/album.json: -------------------------------------------------------------------------------- 1 | { 2 | "enablePullDownRefresh":false 3 | } -------------------------------------------------------------------------------- /pages/album/album.wxml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | {{total}} 13 | 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /pages/album/album.wxss: -------------------------------------------------------------------------------- 1 | .image-list-wrap{ 2 | width: 100%; 3 | } 4 | .albumCount{ 5 | width: 120rpx; 6 | height:120rpx; 7 | border-radius: 50%; 8 | background-color: #BE304D; 9 | color:#ffffff; 10 | position: fixed; 11 | right:30rpx; 12 | top:30rpx; 13 | font-size:35rpx; 14 | display: flex; 15 | justify-content: center; 16 | align-items: center; 17 | } -------------------------------------------------------------------------------- /pages/index/index.js: -------------------------------------------------------------------------------- 1 | //index.js 2 | //获取应用实例 3 | var app = getApp() 4 | var dialog = require("../../utils/dialog.js") 5 | var wxNotificationCenter = require("../../utils/WxNotificationCenter.js") 6 | 7 | Page({ 8 | //加载第一个类型的列表 9 | onLoad:function(){ 10 | if(!this.data.currentType){ 11 | let that = this 12 | this.data.types.every(function(item){ 13 | if(item.is_show){ 14 | wx.setStorageSync('currentType', item.value) 15 | that.setData({currentType:item.value}) 16 | return false 17 | }else{ 18 | return true 19 | } 20 | }) 21 | } 22 | this.getList(this.data.currentType) 23 | //添加通知监听 24 | wxNotificationCenter.addNotification("typesChangeNotification",this.typesChangeNotificationHandler,this) 25 | }, 26 | //接收类别编辑页面中修改了类别标签的通知,重新处理 27 | typesChangeNotificationHandler:function(){ 28 | this.setData({ 29 | types:wx.getStorageSync('types'), 30 | currentType:wx.getStorageSync('currentType') 31 | }) 32 | this.getList(wx.getStorageSync('currentType')) 33 | }, 34 | getList:function(type){ 35 | dialog.loading() 36 | var that = this 37 | //请求数据 38 | wx.request({ 39 | url:app.globalData.api.listBaseUrl+type, 40 | success:function(ret){ 41 | ret = ret['data'] 42 | if(ret['showapi_res_code'] == 0 && ret['showapi_res_body'] && ret['showapi_res_body'] ['ret_code']==0){ 43 | that.setData({ 44 | contentList:ret['showapi_res_body']['pagebean']['contentlist'] 45 | }) 46 | }else{ 47 | setTimeout(function(){ 48 | dialog.toast("网络出错啦~") 49 | },1) 50 | } 51 | }, 52 | complete:function(){ 53 | wx.stopPullDownRefresh() 54 | setTimeout(function(){ 55 | dialog.hide() 56 | },1000) 57 | } 58 | }) 59 | }, 60 | onPullDownRefresh:function(){ 61 | this.getList(this.data.currentType) 62 | }, 63 | //点击某一个title条 64 | changeType:function(e){ 65 | var type = e.currentTarget.dataset.value 66 | if(type == this.data.currentType){ 67 | return; 68 | } 69 | this.setData({currentType:type}) 70 | app.globalData.currentType = type 71 | this.getList(type) 72 | }, 73 | gotoTypeEdit:function(e){ 74 | wx.navigateTo({ 75 | url: '../types/types?id=1', 76 | }) 77 | }, 78 | gotoAlbum:function(e){ 79 | let param = e.currentTarget.dataset, title = param.title, id=param.id 80 | var url = "../album/album?title="+title+"&id="+id.replace(".","##"); 81 | wx.navigateTo({url:url}) 82 | }, 83 | data: { 84 | contentList:[], 85 | currentType:wx.getStorageSync('currentType'), 86 | types:wx.getStorageSync('types') ? wx.getStorageSync('types') : app.globalData.types 87 | } 88 | }) 89 | -------------------------------------------------------------------------------- /pages/index/index.json: -------------------------------------------------------------------------------- 1 | { 2 | "navigationBarTitleText":"美女模特", 3 | "enablePullDownRefresh":true 4 | } -------------------------------------------------------------------------------- /pages/index/index.wxml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | {{type.title}} 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | {{item.title}} 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | -------------------------------------------------------------------------------- /pages/index/index.wxss: -------------------------------------------------------------------------------- 1 | .nav_bar{ 2 | box-sizing:border-box; 3 | position: fixed; 4 | top: 0px; 5 | left:0px; 6 | width: 100%; 7 | border-bottom: 1px solid #D5D5D5; 8 | display: flex; 9 | background-color: #ffffff; 10 | z-index: 1000; 11 | } 12 | .nav_bar_scroll{ 13 | flex:1; 14 | font-size:30rpx; 15 | width: 100rpx; 16 | height: 90rpx; 17 | box-sizing: border-box; 18 | white-space: nowrap; 19 | } 20 | .scroll_item{ 21 | display: inline-block; 22 | padding: 0 20rpx; 23 | line-height:90rpx; 24 | } 25 | .nav_bar_scroll .current{ 26 | color:#BE304D; 27 | } 28 | .edit_nav_bar{ 29 | margin: 20rpx 0 0 0; 30 | height: 50rpx; 31 | width:70rpx; 32 | border-left:1px solid #ccc; 33 | display: flex; 34 | justify-content: center; 35 | align-items: center; 36 | } 37 | .edit_nav_bar_btn{ 38 | width: 50rpx; 39 | height: 50rpx; 40 | } 41 | .content{ 42 | margin: 90rpx 0 0 0; 43 | padding: 20rpx; 44 | display: flex; 45 | justify-content: space-between; 46 | flex-wrap:wrap; 47 | } 48 | .beauty_item{ 49 | width:345rpx; 50 | margin: 0 0 20rpx 0; 51 | } 52 | .beauty_item image{ 53 | width: 100%; 54 | height: 450rpx; 55 | } 56 | .beauty_item text{ 57 | display: block; 58 | font-size:28rpx; 59 | color:#000000; 60 | line-height: 40rpx; 61 | height: 80rpx; 62 | overflow: hidden; 63 | } 64 | 65 | -------------------------------------------------------------------------------- /pages/types/types.js: -------------------------------------------------------------------------------- 1 | var app = getApp() 2 | var dialog = require("../../utils/dialog") 3 | var wxNotificationCenter = require("../../utils/WxNotificationCenter") 4 | 5 | Page({ 6 | data:{ 7 | types:[] 8 | }, 9 | onLoad:function(){ 10 | this.setData({ 11 | types:wx.getStorageSync('types') 12 | }) 13 | }, 14 | changeTypeStatus:function(e){ 15 | var value = e.currentTarget.dataset.value 16 | var currentType = wx.getStorageSync('currentType') 17 | var showCount = 0, isCurrentHide = false 18 | var types = this.data.types.map(function(item){ 19 | if(item.value == value){ 20 | item.is_show = !item.is_show 21 | if(value == currentType && !item.is_show){ 22 | isCurrentHide = true; 23 | } 24 | } 25 | if(item.is_show){ 26 | showCount++; 27 | } 28 | return item 29 | }) 30 | //当前选中的被隐藏了 31 | if(showCount < 1){ 32 | dialog.toast("不能全部隐藏") 33 | return; 34 | } 35 | if(isCurrentHide){ 36 | types.every(function(item){ 37 | if(item.is_show){ 38 | wx.setStorageSync('currentType', item.value) 39 | return false 40 | }else{ 41 | return true 42 | } 43 | }) 44 | } 45 | this.setData({types:types}) 46 | wx.setStorageSync("types", types) 47 | wxNotificationCenter.postNotificationName("typesChangeNotification") 48 | } 49 | }) -------------------------------------------------------------------------------- /pages/types/types.json: -------------------------------------------------------------------------------- 1 | { 2 | "navigationBarTitleText":"编辑标签" 3 | } -------------------------------------------------------------------------------- /pages/types/types.wxml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 点击可切换标签状态[深色显示,灰色为隐藏] 4 | 5 | 6 | 7 | 8 | {{type.title}} 9 | 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /pages/types/types.wxss: -------------------------------------------------------------------------------- 1 | .tips{ 2 | box-sizing: border-box; 3 | background-color: #E6E6E6; 4 | line-height: 80rpx; 5 | font-size:30rpx; 6 | padding: 0 20rpx; 7 | width: 750rpx; 8 | } 9 | .type-content{ 10 | padding: 25rpx 25rpx; 11 | display: flex; 12 | flex-flow:row wrap; 13 | } 14 | .type-item{ 15 | width:155rpx; 16 | text-align: center; 17 | font-size:30rpx; 18 | line-height: 80rpx; 19 | margin: 20rpx 10rpx; 20 | } 21 | .type-item-show{ 22 | background-color: #BE304D; 23 | color:#ffffff; 24 | } 25 | .type-item-hide{ 26 | background-color: #E6E6E6; 27 | color:#C4C4C4; 28 | } -------------------------------------------------------------------------------- /utils/WxNotificationCenter.js: -------------------------------------------------------------------------------- 1 | /** 2 | * author: Di (微信小程序开发工程师) 3 | * organization: WeAppDev(微信小程序开发论坛)(http://weappdev.com) 4 | * 垂直微信小程序开发交流社区 5 | * 6 | * github地址: https://github.com/icindy/WxNotificationCenter 7 | * 8 | * for: 微信小程序通知广播模式类,降低小程序之间的耦合度 9 | * detail : http://weappdev.com/t/wxnotificationcenter/233 10 | */ 11 | // 存放 12 | var __notices = []; 13 | var isDebug = false; 14 | /** 15 | * addNotification 16 | * 注册通知对象方法 17 | * 18 | * 参数: 19 | * name: 注册名,一般let在公共类中 20 | * selector: 对应的通知方法,接受到通知后进行的动作 21 | * observer: 注册对象,指Page对象 22 | */ 23 | function addNotification(name, selector, observer) { 24 | if (name && selector) { 25 | if(!observer){ 26 | console.log("addNotification Warning: no observer will can't remove notice"); 27 | } 28 | //console.log("addNotification:" + name); 29 | var newNotice = { 30 | name: name, 31 | selector: selector, 32 | observer: observer 33 | }; 34 | 35 | addNotices(newNotice); 36 | 37 | } else { 38 | console.log("addNotification error: no selector or name"); 39 | } 40 | } 41 | 42 | function addNotices(newNotice) { 43 | // if (__notices.length > 0) { 44 | // for (var i = 0; i < __notices.length; i++) { 45 | // var hisNotice = __notices[i]; 46 | // //当名称一样时进行对比,如果不是同一个 则放入数组,否则跳出 47 | // if (newNotice.name === hisNotice.name) { 48 | // if (!cmp(hisNotice, newNotice)) { 49 | // __notices.push(newNotice); 50 | // } 51 | // return; 52 | // }else{ 53 | // __notices.push(newNotice); 54 | // } 55 | 56 | // } 57 | // } else { 58 | 59 | // } 60 | 61 | __notices.push(newNotice); 62 | } 63 | 64 | /** 65 | * removeNotification 66 | * 移除通知方法 67 | * 68 | * 参数: 69 | * name: 已经注册了的通知 70 | * observer: 移除的通知所在的Page对象 71 | */ 72 | 73 | function removeNotification(name,observer) { 74 | for (var i = 0; i < __notices.length; i++){ 75 | var notice = __notices[i]; 76 | if(notice.name === name){ 77 | if(notice.observer === observer){ 78 | __notices.splice(i,1); 79 | return; 80 | } 81 | } 82 | } 83 | 84 | 85 | } 86 | 87 | /** 88 | * postNotificationName 89 | * 发送通知方法 90 | * 91 | * 参数: 92 | * name: 已经注册了的通知 93 | * info: 携带的参数 94 | */ 95 | 96 | function postNotificationName(name, info) { 97 | if(__notices.length == 0){ 98 | console.log("postNotificationName error: u hadn't add any notice."); 99 | return; 100 | } 101 | 102 | for (var i = 0; i < __notices.length; i++){ 103 | var notice = __notices[i]; 104 | if(notice.name === name){ 105 | notice.selector(info); 106 | } 107 | } 108 | 109 | } 110 | 111 | // 用于对比两个对象是否相等 112 | function cmp(x, y) { 113 | // If both x and y are null or undefined and exactly the same 114 | if (x === y) { 115 | return true; 116 | } 117 | 118 | // If they are not strictly equal, they both need to be Objects 119 | if (! (x instanceof Object) || !(y instanceof Object)) { 120 | return false; 121 | } 122 | 123 | // They must have the exact same prototype chain, the closest we can do is 124 | // test the constructor. 125 | if (x.constructor !== y.constructor) { 126 | return false; 127 | } 128 | 129 | for (var p in x) { 130 | // Inherited properties were tested using x.constructor === y.constructor 131 | if (x.hasOwnProperty(p)) { 132 | // Allows comparing x[ p ] and y[ p ] when set to undefined 133 | if (!y.hasOwnProperty(p)) { 134 | return false; 135 | } 136 | 137 | // If they have the same strict value or identity then they are equal 138 | if (x[p] === y[p]) { 139 | continue; 140 | } 141 | 142 | // Numbers, Strings, Functions, Booleans must be strictly equal 143 | if (typeof(x[p]) !== "object") { 144 | return false; 145 | } 146 | 147 | // Objects and Arrays must be tested recursively 148 | if (!Object.equals(x[p], y[p])) { 149 | return false; 150 | } 151 | } 152 | } 153 | 154 | for (p in y) { 155 | // allows x[ p ] to be set to undefined 156 | if (y.hasOwnProperty(p) && !x.hasOwnProperty(p)) { 157 | return false; 158 | } 159 | } 160 | return true; 161 | }; 162 | 163 | module.exports = { 164 | addNotification: addNotification, 165 | removeNotification: removeNotification, 166 | postNotificationName: postNotificationName 167 | } -------------------------------------------------------------------------------- /utils/dialog.js: -------------------------------------------------------------------------------- 1 | var dialog = {} 2 | 3 | dialog.loading = function(title = "加载中"){ 4 | wx.showToast({title:title,icon:'loading',duration:10000}) 5 | } 6 | 7 | dialog.hide = function(){ 8 | wx.hideToast(); 9 | } 10 | 11 | dialog.toast = function(title="提示您"){ 12 | wx.showToast({title:title,icon:'success'}) 13 | } 14 | 15 | 16 | module.exports = dialog -------------------------------------------------------------------------------- /utils/util.js: -------------------------------------------------------------------------------- 1 | function formatTime(date) { 2 | var year = date.getFullYear() 3 | var month = date.getMonth() + 1 4 | var day = date.getDate() 5 | 6 | var hour = date.getHours() 7 | var minute = date.getMinutes() 8 | var second = date.getSeconds() 9 | return [year, month, day].map(formatNumber).join('/') + ' ' + [hour, minute, second].map(formatNumber).join(':') 10 | } 11 | 12 | function formatNumber(n) { 13 | n = n.toString() 14 | return n[1] ? n : '0' + n 15 | } 16 | 17 | module.exports = { 18 | formatTime: formatTime 19 | } 20 | --------------------------------------------------------------------------------