├── 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 | 
10 | ## 图片列表展示页
11 | 
12 | ## 相册类别编辑页
13 | 
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 |
--------------------------------------------------------------------------------