ylbtech-小程序-demo:小熊の日记

1、CHANGELOG.md

# 2016-10-12* 更新开发者工具至`v0.10.101100`
* 修改`new`页的数据绑定方式 & 修改多行文本框输入时的bug# 2016-10-13* 完善日志编辑页

2、README.md

# 微信小程序之小熊の日记 ### 关于 ##* 我是一名后端程序员,做这个仅仅是因为觉得微信小程序好玩;
* 没有明确的产品意图,东抄抄西抄抄只是为了验证和学习微信小程序;
* 大体是想做一个个人/家庭日常记录的app;
* 持续开发中,有兴趣请持续关注## 预览 ##* 概览<p align="center"><img src="./files/preview.gif" alt="截频演示" width="100%">
</p>## 功能特点 ##* 功能完备,实用导向
* Server端API支持
* 涵盖众多组件、API使用,适用于学习微信小程序
* 多行文本模拟实现
* tab切换
* 模态框
* 本地数据组织及存储
* 图片预览功能## 使用步骤1. 克隆代码:```bash
$ cd path/to/your/workspace
$ git clone https://github.com/harveyqing/BearDiary.git
```2. 打开`微信Web开放者工具`(注意:须`v0.10.101100`及以上版本)3. 添加项目* AppID:选`无AppID`* 项目名称:任意填写* 项目目录:path/to/your/workspace* 点击 `添加项目`## 开发计划 ##- [ ] 开发server端API接口
- [ ] 完成日记撰写页
- [ ] 添加评论、喜欢、收藏功能
- [ ] 规范`coding style`## 小程序开发相关资源 ##### 开发者工具下载 ###> 最新版本 0.10.101100- [windows 64](https://servicewechat.com/wxa-dev-logic/download_redirect?type=x64&from=mpwiki&t=1476434677599)
- [windows 32](https://servicewechat.com/wxa-dev-logic/download_redirect?type=ia32&from=mpwiki&t=1476434677599)
- [mac](https://servicewechat.com/wxa-dev-logic/download_redirect?type=darwin&from=mpwiki&t=1476434677599)

### 开发者文档 ###- [微信官方文档](https://mp.weixin.qq.com/debug/wxadoc/dev/)

### 最好的资源集 ###- [justjavac/awesome-wechat-weapp](https://github.com/justjavac/awesome-wechat-weapp)

## Anyway, 欢迎PR #### LICENSE ##[MIT](./LICENSE)

3、

1.返回顶部
0、
     
 
1、app.js
// app.js

const config = require('config');
const diaries = require('demo/diaries');App({onLaunch: function () {},// 获取用户信息getUserInfo: function(cb) {var that = this;if (this.globalData.userInfo) {typeof cb == 'function' && cb(this.globalData.userInfo)} else {// 先登录
      wx.login({success: function() {wx.getUserInfo({success: (res) => {that.globalData.userInfo = res.userInfo;typeof cb == 'function' && cb(that.globalData.userInfo)}})}})}},// 获取本地全部日记列表
  getDiaryList(cb) {var that = this;if (this.globalData.diaryList) {typeof cb == 'function' && cb(this.globalData.diaryList);} else {let list = [];this.getLocalDiaries(storage => {// 本地缓存数据for (var k in storage) {list.push(storage[k]);}});// 本地假数据
      list.push(...diaries.diaries);that.globalData.diaryList = list;typeof cb == 'function' && cb(that.globalData.diaryList)}},// 获取本地日记缓存
  getLocalDiaries(cb) {var that = this;if (this.globalData.localDiaries) {typeof cb == 'function' && cb(this.globalData.localDiaries);} else {wx.getStorage({key: config.storage.diaryListKey,success: (res) => {that.globalData.localDiaries = res.data;typeof cb == 'function' && cb(that.globalData.localDiaries);},fail: (error) => {that.globalData.localDiaries = {};typeof cb == 'function' && cb(that.globalData.localDiaries);}});}},// 获取当前设备信息getDeviceInfo: function(callback) {var that = this;if (this.globalData.deviceInfo) {typeof callback == "function" && callback(this.globalData.deviceInfo)} else {wx.getSystemInfo({success: function(res) {that.globalData.deviceInfo = res;typeof callback == "function" && callback(that.globalData.deviceInfo)}})}},globalData: {// 设备信息,主要用于获取屏幕尺寸而做适配deviceInfo: null,// 本地日记缓存列表 + 假数据// TODO 真实数据同步至服务端,本地只做部分缓存diaryList: null,// 本地日记缓存localDiaries: null,// 用户信息userInfo: null,}})

2、app.json
{"pages":["pages/list/list","pages/mine/mine","pages/new/new","pages/entry/entry"],"window":{"backgroundTextStyle": "light","navigationBarBackgroundColor": "#39b5de","navigationBarTitleText": "小熊の日记","navigationBarTextStyle": "white","backgroundColor": "#eceff4"},"tabBar": {"color": "#858585","selectedColor": "#39b5de","backgroundColor": "#ffffff","borderStyle": "black","list":[{"pagePath": "pages/list/list","iconPath": "images/icons/mark.png","selectedIconPath": "images/icons/markHL.png","text": "印记"},{"pagePath": "pages/mine/mine","iconPath": "images/icons/mine.png","selectedIconPath": "images/icons/mineHL.png","text": "我的"}]},"debug": true
}

3、app.wxss
/**app.wxss全局样式
**/page {width: 100%;height: 100%;padding: 0;background-color: #eceff4;font-size: 30rpx;font-family: -apple-system-font, 'Helvetica Neue', Helvetica, 'Microsoft YaHei', sans-serif;}

3、config.js
// 全局配置

module.exports = {/** 腾讯地图 **/map: {baseUrl: 'https://apis.map.qq.com/ws',key: '2TCBZ-IM7K5-XHCIZ-QXLRT-CIT4J-DEFSM',},/** 输入框控件设置 **/input: {charWidth: 14,  // 单个字符的宽度,in rpx
    },/** 本地存储 **/// TODO 数据通过API全部存储于服务端
    storage: {diaryListKey: 'bearDiaryList',}
};

4、project.config.json
{"description": "项目配置文件。","packOptions": {"ignore": []},"setting": {"urlCheck": true,"es6": true,"postcss": true,"minified": true,"newFeature": true},"compileType": "miniprogram","libVersion": "2.2.3","appid": "wx7d22ab7088f2db6a","projectname": "BearDiary","isGameTourist": false,"condition": {"search": {"current": -1,"list": []},"conversation": {"current": -1,"list": []},"game": {"currentL": -1,"list": []},"miniprogram": {"current": -1,"list": []}}
}

5、images
6、
2. pages返回顶部
1、demo
-diaries.js
var diaries = [{meta: {  // 内容元数据cover: "http://m.chanyouji.cn/index-cover/64695-2679221.jpg?imageView2/1/w/620/h/330/format/jpg",avatar: "https://pic4.zhimg.com/e515adf3b_xl.jpg",title: "此刻静好,愿幸福长存",meta: "2016.10.17",create_time: "2016.10.18 11:57:27",nickName: "肥肥的小狗熊",},list: [{type: "TEXT",content: '9月11日,15年的911事件使这天蒙上了特殊的意义。2016年的这一天,怀着激动的心情,开启了高原寻秘之旅,向着那圣洁之地出发。全程自驾近2000公里,雨崩徒步80公里,完成觐见之旅。',poi: {longitude: 117.2,latitude: 37.5,name: "北京市",},description: "",id: 1,commentNum: 0,likeNum: 0,},{type: "IMAGE",content: 'http://p.chanyouji.cn/1473699595/1740E45C-D5AF-497E-A351-06E5BA22B1A3.jpg',poi: {longitude: 117.2,latitude: 37.5,name: "深圳市",},description: "深圳宝安国际机场",id: 2,commentNum: 1,likeNum: 5,},{type: "IMAGE",content: 'http://p.chanyouji.cn/1473699603/7C3B253F-0A31-4754-B042-E04115F2C931.jpg',poi: {longitude: 117.2,latitude: 37.5,name: "丽江三义机场",},description: "丽江三义机场",id: 2,commentNum: 1,likeNum: 5,},{type: "TEXT",content: ' 玉水寨在白沙溪镇,是纳西族中部地区的东巴圣地,是丽江古城的溯源。\n\nTips:门票50元/人,游玩时间2小时。',poi: {longitude: 117.2,latitude: 37.5,name: "玉水寨",},description: "",id: 1,commentNum: 0,likeNum: 0,},{type: "IMAGE",content: 'http://p.chanyouji.cn/1473685830/2A48B40F-1F11-498D-ABD2-B0EDCD09F776.jpg',poi: {longitude: 117.2,latitude: 37.5,name: "玉水寨",},description: "阳光下的玉水寨",id: 2,commentNum: 1,likeNum: 5,},{type: "VIDEO",content: 'http://flv.bn.netease.com/videolib3/1605/22/auDfZ8781/HD/auDfZ8781-mobile.mp4',poi: {longitude: 117.2,latitude: 37.5,name: "深圳宝安国际机场",},description: "",id: 2,commentNum: 10,likeNum: 200,},]},{meta: {  // 内容元数据cover: "http://m.chanyouji.cn/articles/625/ca9e50f74e273041e3a399bf5528f7b5.jpg?imageView2/1/w/620/h/330/format/jpg",avatar: "https://pic4.zhimg.com/e515adf3b_xl.jpg",title: "梦想实现的地方-马达加斯加第二季",meta: "2013.8.10",create_time: "2016.10.18 11:57:27",nickName: "小闹钟",},list: [{type: "TEXT",content: '2012年十一,我和朋友一行五人第一次登上这个被非洲大陆抛弃的岛屿,看到了可爱的狐猴,憨态可掬的变色龙,明信片一样的猴面包树,天真的孩子淳朴的人民,结识了我们生命中一个重要的朋友导游小温(可以加地接小温QQ或微信咨询:109300820),从此,我们爱上了这片土地。马达加斯加是一个海岛,一年分成旱季和雨季,没有特别的低温或者高温季节,几乎全年都适合旅游,只是观赏的重点略有不同而已。 \n导游小温向我们介绍,在这里,每年的7月到9月,可以近距离观看座头鲸,于是,我们从那时开始期待这个夏季的到来。',poi: {longitude: 117.2,latitude: 37.5,name: "塔那那利佛",},description: "",id: 1,commentNum: 0,likeNum: 0,},{type: "TEXT",content: '第一天 8月10日 天气晴\n\n长时间的飞行,多少会有一些枯燥,然而只要你愿意,依然可以看到心中的那片风景。 \n嗨!别郁闷了,和我一起到三万英尺的高空来看云。 \n喜欢飞机起飞的刹那间,加速再加速直到脱离开地球的引力冲向自由的天空。喜欢像鸟一样俯视地面的视角,高高在上,笑看人间。 \n天,蓝,云,白。机窗外的云时而像珍珠点点,时而像棉絮团团。\n夕阳将至,云和机翼被镀上一层华丽的金。 \n金红色的阳光与蓝色的天空最终合成出一片淡淡的紫,绚丽而梦幻。',poi: {longitude: 117.2,latitude: 37.5,name: "塔那那利佛",},description: "",id: 1,commentNum: 0,likeNum: 0,},{type: "IMAGE",content: 'http://p.chanyouji.cn/64695/1377177446705p182j2oa9031j1p0b5vpuvj1voj2.jpg-o',poi: {longitude: 117.2,latitude: 37.5,name: "塔那那利佛",},description: "",id: 2,commentNum: 1,likeNum: 5,},]}
]module.exports = {diaries: diaries,
}

2、services
-geo.js
// 基于腾讯地图API的地理位置功能封装

const config = require('../config.js');
const request = require('request.js');const statusCodeMap = {  // 请求失败原因映射110: '请求来源未被授权',301: '请求参数信息有误',311: 'key格式错误',306: '请求有护持信息请检查字符串',
}module.exports = {// 地图API请求方法
    mapRequest(method, params, callback) {var url = [config.map.baseUrl, method, 'v1/'].join('/');let param = Object.assign({'key': config.map.key}, params);let queryString = Object.keys(param).map(q => [q, param[q]].join('=')).join('&');url += '?' + queryString;request({'method': 'GET', 'url': url}).then(resp => {if (resp.status != 0) {console.log('请求错误:' + (statusCodeMap[resp.status] || resp.message));request}return callback(resp);}).catch(err => {console.log(err);});},// 格式化地理位置
    formatLocation(loc) {return [loc.latitude, loc.longitude].map(f => f.toString()).join(',');},
}

-request.js
// 对微信网络请求的异步封装

module.exports = (options) => {return new Promise((resolve, reject) => {options = Object.assign(options, {success(result) {if (result.statusCode === 200) {resolve(result.data);} else {reject(result);}},fail: reject,});wx.request(options);});
};

3、utills
-input.js
// 输入框相关处理函数

module.exports = {// 计算字符串长度(英文占一个字符,中文汉字占2个字符)
  strlen(str) {var len = 0;for (var i = 0; i < str.length; i++) {var c = str.charCodeAt(i);if ((c >= 0x0001 && c <= 0x007e) || (c >= 0xff60 && c <= 0xff9f)) {len++;} else {len += 2;}}return len;},
}

-utill.js
// 工具函数function formatTime(date) {var year = date.getFullYear()var month = date.getMonth() + 1var day = date.getDate()var hour = date.getHours()var minute = date.getMinutes()var second = date.getSeconds();return [year, month, day].map(formatNumber).join('.') + ' ' + [hour, minute, second].map(formatNumber).join(':')
}function formatNumber(n) {n = n.toString()return n[1] ? n : '0' + n
}// 将一维数组转为二维数组
function listToMatrix(list, elementPerSubArray) {let matrix = [], i, k;for (i = 0, k = -1; i < list.length; i += 1) {if (i % elementPerSubArray === 0) {k += 1;matrix[k] = [];}matrix[k].push(list[i]);}return matrix;
}module.exports = {formatTime: formatTime,listToMatrix: listToMatrix,
}

4、
3.返回顶部
1、entry
a) .js
// entry.js

const toolbar = ['../../images/nav/download.png', '../../images/nav/fav.png','../../images/nav/share.png', '../../images/nav/comment.png',
];
const app = getApp();Page({data: {// 当前日志详情
    diary: undefined,// 右上角工具栏
    toolbar: toolbar,// 图片预览模式previewMode: false,// 当前预览索引previewIndex: 0,// 多媒体内容列表
    mediaList: [],},// 加载日记
  getDiary(params) {console.log("Loading diary data...", params);var id = params["id"], diary;app.getDiaryList(list => {if (typeof id === 'undefined') {diary = list[0];} else {diary = list[id];}});this.setData({diary: diary,});},// 过滤出预览图片列表
  getMediaList() {if (typeof this.data.diary !== 'undefined' &&this.data.diary.list.length) {this.setData({mediaList: this.data.diary.list.filter(content => content.type === 'IMAGE'),})}},// 进入预览模式
  enterPreviewMode(event) {let url = event.target.dataset.src;let urls = this.data.mediaList.map(media => media.content);let previewIndex = urls.indexOf(url);this.setData({previewMode: true, previewIndex});},// 退出预览模式
  leavePreviewMode() {this.setData({previewMode: false, previewIndex: 0});},onLoad: function(params) {this.getDiary(params);this.getMediaList();},onHide: function() {},
})

b) .json
c) .wxml
<!-- dairy.wxml --><!-- 单条内容 -->
<template name="content-item"><block wx:if="{{content.type == 'TEXT'}}"><view style="margin-top:30rpx"><text wx:if="{{content.type == 'TEXT'}}" class="text">{{content.content}}</text></view></block><block wx:if="{{content.type == 'IMAGE'}}"><image class="media" mode="aspectFill" src="{{content.content}}" bindtap="enterPreviewMode" data-src="{{content.content}}"></image><view style="margin-top: 10rpx">{{content.description}}</view></block><block wx:if="{{content.type == 'VIDEO'}}"><video class="media" src="{{content.content}}"></video><view style="margin-top: 10rpx">{{content.description}}</view></block><template is="content-footer" data="{{content}}"></template>
</template><!-- 日记正文footer -->
<template name="content-footer"><view class="footer"><view class="left"><image mode="aspectFit" src="../../images/icons/poi.png"></image><text style="margin-left:10rpx;">{{content.poi.name}}</text></view><view class="right"><image mode="aspectFit" src="../../images/icons/comment.png"></image><view>{{content.commentNum}}</view></view><view class="right"><image mode="aspectFit" src="../../images/icons/like.png"></image><view>{{content.likeNum}}</view></view></view>
</template><view class="container"><view class="header" style="background-image:url({{diary.meta.cover}})"><!--顶部固定工具栏--><view class="toolbar"><image class="item" mode="aspectFit" wx:for="{{toolbar}}" src="{{item}}"></image></view><!--日记meta信息区--><view class="title"><image class="avatar" mode="aspectFit" src="{{diary.meta.avatar}}"> </image><view class="desc"><view class="item">{{diary.meta.title}}</view><view class="item">{{diary.meta.meta}}</view></view></view></view><!--日记正文--><view wx:for="{{diary.list}}" wx:for-item="content" class="content"><template is="content-item" data="{{content}}"></template></view><view id="footer"><view class="container"><view class="item" style="font-size:50rpx;"><view style="display:inline-block">THE</view><view style="display:inline-block;margin-left:10rpx;color:#2EA1CA;">END</view></view><view class="item" style="font-size:24rpx;color:gray">DESIGNED BY 小闹钟</view></view></view>
</view><!-- 预览模式 -->
<swiper class="swiper-container" duration="400" current="{{previewIndex}}" bindtap="leavePreviewMode" style="display:{{previewMode ? 'block' : 'none'}};"><block wx:for="{{mediaList}}" wx:for-item="media"><swiper-item><image src="{{media.content}}" mode="aspectFit"></image></swiper-item></block>
</swiper>

d) .wxss
/** item.wxss **/.container {font-size: 26rpx;
}.header {height: 400rpx;
}.toolbar {height: 60rpx;position: fixed;top: 0;right: 0;display: flex;flex-direction: row;justify-content: space-between;align-items: center;
}.toolbar .item {width: 40rpx;height: 40rpx;margin: 10rpx 20rpx;
}.title {height: 120rpx;position: absolute;top: 280rpx;
}.title .avatar {margin: 20rpx;width: 80rpx;height: 80rpx;border-radius: 40rpx;float: left;
}.title .desc {height: 100rpx;width: 630rpx;margin: 10rpx 0;float: right;color: white;display: flex;flex-direction: column;
}.desc .item {height: 50%;padding: 12rpx 0;
}.content {padding: 10rpx;border-bottom: 1px solid #E5E7ED;
}.content .text {line-height: 42rpx;
}.content .media {width: 730rpx;
}.content .footer {height: 60rpx;margin-top: 10rpx;font-size:22rpx;color: #70899D;
}.content .footer image {width: 20rpx;height: 20rpx;
}.content .footer .left {display: inline-block;height: 40rpx;margin: 10rpx 0;
}.content .footer .right {display: flex;justify-content: space-between;align-items: center;float: right;height: 40rpx;margin-left: 20rpx;background-color: #E5E7ED;font-size: 20rpx;
}.content .footer .right image {margin: 10rpx;
}.content .footer .right text {font-size: 20rpx;padding:10rpx 10rpx 10rpx 0;
}#footer {width: 100%;height: 300rpx;display: flex;justify-content: center;align-items: center;
}#footer .container {height: 100rpx;display: flex;flex-direction: column;justify-content: space-between;align-items: center;
}#footer .container .item {height: 50%;display: flex;justify-content: center;align-items: center;
}.swiper-container {position: fixed;left: 0;top: 0;width: 100%;height: 100%;background-color: #000;
}.swiper-container image {width: 100%;height: 100%;
}

e)
2、list
a) .js
// index.js
// 日记聚合页

const config = require("../../config");var app = getApp();Page({data: {// 日记列表// TODO 从server端拉取diaries: null,// 是否显示loadingshowLoading: false,// loading提示语loadingMessage: '',},/*** 生命周期函数--监听页面加载*/onLoad() {this.getDiaries();},/*** 获取日记列表* 目前为本地缓存数据 + 本地假数据* TODO 从服务端拉取*/getDiaries() {var that = this;app.getDiaryList(list => {that.setData({diaries: list});})},// 查看详情
  showDetail(event) {wx.navigateTo({url: '../entry/entry?id=' + event.currentTarget.id,});}
})

b) .json
c) .wxml
<!--list.wxml--><scroll-view scroll-y="true"><view wx:for="{{diaries}}" wx:for-index="idx" class="item-container" bindtap="showDetail" id="{{idx}}"><image mode="aspectFit" src="{{item.meta.cover}}" class="cover"></image><view class="desc"><view class="left"><view style="font-size:32rpx;margin:10rpx 0;">{{item.meta.title}}</view><view style="font-size:24rpx;color:darkgray">{{item.meta.meta}}</view></view><view class="right"><image mode="aspectFit" src="{{item.meta.avatar}}"></image><text style="font-size:24rpx;margin-top:10rpx;color:darkgray">{{item.meta.nickName}}</text></view></view></view>
</scroll-view>

d) .wxss
/** list.wxss **/.item-container {margin: 10rpx 20rpx;position: relative;
}.cover {width: 100%;height: 400rpx;display: block;
}.desc {margin: 10rpx 0;display: flex;justify-content: space-between;align-items: center;padding-bottom: 20rpx;border-bottom: 1px solid #E5E7ED;
}.desc .left {
}.desc .right {display: flex;flex-direction: column;align-items: center;
}.right image{display: block;width: 60rpx;height: 60rpx;border-radius: 30rpx;
}

e)
3、mine
a) .js
// mine.js// 自定义标签
var iconPath = "../../images/icons/"
var tabs = [{"icon": iconPath + "mark.png","iconActive": iconPath + "markHL.png","title": "日记","extraStyle": "",},{"icon": iconPath + "collect.png","iconActive": iconPath + "collectHL.png","title": "收藏","extraStyle": "",},{"icon": iconPath + "like.png","iconActive": iconPath + "likeHL.png","title": "喜欢","extraStyle": "",},{"icon": iconPath + "more.png","iconActive": iconPath + "moreHL.png","title": "更多","extraStyle": "border:none;",},
]
var userInfo = {avatar: "https://pic4.zhimg.com/e515adf3b_xl.jpg",nickname: "小闹钟",sex: "♂",  // 0, male; 1, femalemeta: '1篇日记',
}Page({// data
    data: {// 展示的tab标签
        tabs: tabs,// 当前选中的标签currentTab: "tab1",// 高亮的标签索引highLightIndex: "0",// 模态对话框样式 modalShowStyle: "",// 待新建的日记标题diaryTitle: "",// TODO 用户信息
        userInfo: userInfo,},// 隐藏模态框
    hideModal() {this.setData({modalShowStyle: ""});},// 清除日记标题
    clearTitle() {this.setData({diaryTitle: ""});},onShow: function() {this.hideModal();this.clearTitle();},// 点击tab项事件touchTab: function(event){var tabIndex = parseInt(event.currentTarget.id);var template = "tab" + (tabIndex + 1).toString();this.setData({currentTab: template,highLightIndex: tabIndex.toString()});},// 点击新建日记按钮touchAdd: function (event) {this.setData({modalShowStyle: "opacity:1;pointer-events:auto;"})},// 新建日记touchAddNew: function(event) {this.hideModal();wx.navigateTo({url: "../new/new?title=" + this.data.diaryTitle,});},// 取消标题输入touchCancel: function(event) {this.hideModal();this.clearTitle();}, // 标题输入事件titleInput: function(event) {this.setData({diaryTitle: event.detail.value,})}
})

b) .json
c) .wxml
<!--mine.wxml--><template name="tab1"><view></view>
</template><template name="tab2"><view></view>
</template><template name="tab3"><view></view>
</template><template name="tab4"><view></view>
</template><view><!--一个全屏模态对话框--><view class="modal" style="{{modalShowStyle}}"><view class="dialog"><view class="modal-item" style="display:flex;justify-content:center;align-items:center;">请输入日记标题</view><view class="modal-item" style="margin:0 auto;width:90%;"><input type="text" bindinput="titleInput" style="background-color:white;border-radius:2px;" value="{{diaryTitle}}" placeholder="请输入日记标题"></input></view><view class="modal-button" style="width:100%"><view style="color:green;border-right:1px solid #E5E7ED;" bindtap="touchAddNew">确定</view><view bindtap="touchCancel">取消</view></view></view></view><view class="header"><view class="profile"><image class="avatar" mode="aspectFit" src="{{userInfo.avatar}}"></image><view class="description"><view class="item"><view style="margin-right:5px">{{userInfo.nickname}}</view><view>{{userInfo.sex}}</view></view><view class="item">{{userInfo.meta}}</view></view><image class="add" mode="aspectFill" src="../../images/icons/add.png" bindtap="touchAdd"></image></view><view class="tablist"><view wx:for="{{tabs}}" wx:for-index="idx" class="tab" bindtap="touchTab" style="{{item.extraStyle}}" id="{{idx}}"><view class="content" style="color:{{highLightIndex == idx ? '#54BFE2' : ''}};"><image class="image" mode="aspectFit" src="{{highLightIndex == idx ? item.iconActive : item.icon}}"></image><view style="margin-top:2px;">{{item.title}}</view></view></view></view></view><template is="{{currentTab}}"></template>
</view>

d) .wxss
/**mine.wxss**/.header {height: 130px;background: white;
}.header .profile {height: 50%;
}.profile .avatar {width: 50px;height: 50px;float: left;margin: 7.5px 10px;border-radius: 25px;
}.profile .description {display: inline-block;margin: 7.5px auto;height: 50px;
}.description .item {height: 50%;display: flex;align-items: center;
}.profile .add {float: right;margin: 15px 10px;height: 35px;width: 35px;
}.header .tablist {height: 50%;display: flex;justify-content: space-between;align-items: center;
}.tablist .tab {display: flex;justify-content: center;align-items: center;height: 50px;width: 25%;margin: 7.5px 0px;border-right: 1px solid #eceff4;
}.tab .content{width: 25px;height: 50px;font-size: 12px;color: #B3B3B3;
}.tab .image {width: 25px;height: 25px;margin-top: 10px;
}.modal {position: fixed;top: 0;left: 0;bottom: 0;right: 0;background: rgba(0, 0, 0, .5);z-index: 99999;opacity: 0;transition: opacity 400ms ease-in;pointer-events: none;display: flex;justify-content: center;align-items: center;
}.modal .dialog {width: 84%;height: 28%;background-color: #eceff4;border-radius: 4px;display: flex;flex-direction: column;justify-content: space-between;
}.dialog .modal-item {height: 33.3%;width: 100%;
}.modal-button {height: 100rpx;margin-bottom: 0;display: flex;flex-direction: row;justify-content: space-between;
}.modal-button view {width: 50%;border-top: 1px solid #E5E7ED;display: flex;justify-content: center;align-items: center;
}

e)
4、new
a) .js
// new.js
// TODO 并不是所有非中文字符宽度都为中文字符宽度一半,需特殊处理
// TODO 由于文本框聚焦存在bug,故编辑模式待实现

const input = require('../../utils/input');
const config = require('../../config');
const geo = require('../../services/geo');
const util = require('../../utils/util');const RESOLUTION = 750;  // 微信规定屏幕宽度为750rpx
const MARGIN = 10;  // 写字面板左右margin
const ROW_CHARS = Math.floor((RESOLUTION - 2 * MARGIN) / config.input.charWidth);
const MAX_CHAR = 1000;  // 最多输1000字符// 内容布局
const layoutColumnSize = 3;// 日记内容类型
const TEXT = 'TEXT';
const IMAGE = 'IMAGE';
const VIDEO = 'VIDEO';const mediaActionSheetItems = ['拍照', '选择照片', '选择视频'];
const mediaActionSheetBinds = ['chooseImage', 'chooseImage', 'chooseVideo'];var app = getApp();Page({data: {// 日记对象
    diary: {meta: {},list: [],},// 日记内容布局列表(2x2矩阵)
    layoutList: [],// 是否显示loadingshowLoading: false,// loading提示语loadingMessage: '',// 页面所处模式showMode: 'common',// 输入框状态对象
    inputStatus: {row: 0,column: 0,lines: [''],mode: 'INPUT',auto: false,  // 是否有自动换行
    },// 当前位置信息poi: null,// 点击`图片`tab的action-sheetmediaActionSheetHidden: true,// 多媒体文件插入action-sheet
    mediaActionSheetItems: mediaActionSheetItems,// 多媒体文件插入项点击事件
    mediaActionSheetBinds: mediaActionSheetBinds,// 是否显示底部tab栏showTab: true,},// 显示底部tab
  showTab() {this.setData({showTab: true});},// 隐藏底部tab
  hideTab() {this.setData({showTab: false});},// 显示loading提示
  showLoading(loadingMessage) {this.setData({showLoading: true, loadingMessage});},// 隐藏loading提示
  hideLoading() {this.setData({showLoading: false, loadingMessage: ''});},// 数据初始化
  init() {this.getPoi();this.setMeta();},// 设置日记数据
  setDiary(diary) {let layout = util.listToMatrix(diary.list, layoutColumnSize);this.setData({diary: diary, layoutList: layout});this.saveDiary(diary);},// 保存日记// TODO sync to server
  saveDiary(diary) {const key = config.storage.diaryListKey;app.getLocalDiaries(diaries => {diaries[diary.meta.title] = diary;wx.setStorage({key: key, data: diaries});})},// 页面初始化onLoad: function(options) {if (options) {let title = options.title;if (title) {this.setData({'diary.meta.title': title,'diary.meta.create_time': util.formatTime(new Date()),'diary.meta.cover': ''});}}this.init();},// 页面渲染完成onReady: function(){wx.setNavigationBarTitle({title: '编辑日记'});},onShow:function(){// 页面显示
  },onHide:function(){// 页面隐藏
  },onUnload:function(){// 页面关闭console.log('页面跳转中...');},// 清除正在输入文本
  clearInput() {this.setData({inputStatus: {row: 0,common: 0,lines: [''],mode: 'INPUT',auto: false,}});},// 结束文本输入
  inputDone() {let text = this.data.inputStatus.lines.join('\n');let diary = this.data.diary;if (text) {diary.list.push(this.makeContent(TEXT, text, ''));this.setDiary(diary);}this.inputCancel();},// 进入文本编辑模式
  inputTouch(event) {this.setData({showMode: 'inputText'});},// 取消文本编辑
  inputCancel() {this.setData({showMode: 'common'});this.clearInput();},// 文本输入
  textInput(event) {console.log(event);let context = event.detail;// 输入模式if (this.data.inputStatus.mode === 'INPUT') {if (context.value.length != context.cursor) {console.log('用户输入中...');} else {let text = context.value;let len = input.strlen(text);let lines = this.data.inputStatus.lines;let row = this.data.inputStatus.row;let [extra, extra_index] = [[['']], 0];let hasNewLine = false;console.log('当前文本长度: ' + len);// 当前输入长度超过规定长度if (len >= ROW_CHARS) {// TODO 此处方案不完善// 一次输入最好不超过两行hasNewLine = true;while (input.strlen(text) > ROW_CHARS) {let last = text[text.length - 1];if (input.strlen(extra[extra_index] + last) > ROW_CHARS) {extra_index += 1;extra[extra_index] = [''];}extra[extra_index].unshift(last);text = text.slice(0, -1);}}lines[lines.length - 1] = text;if (hasNewLine) {extra.reverse().forEach((element, index, array) => {lines.push(element.join(''));row += 1;});}let inputStatus = {lines: lines,row: row,mode: 'INPUT',auto: true,  // // 自动换行的则处于输入模式
      };this.setData({inputStatus});}}},// 文本框获取到焦点
  focusInput(event) {let isInitialInput = this.data.inputStatus.row == 0 &&this.data.inputStatus.lines[0].length == 0;let isAutoInput = this.data.inputStatus.mode == 'INPUT' &&this.data.inputStatus.auto == true;let mode = 'EDIT';if (isInitialInput || isAutoInput) {mode = 'INPUT';}this.setData({'inputStatus.mode': mode});},// 点击多媒体插入按钮
  mediaTouch() {this.setData({showTab: false,mediaActionSheetHidden: false,});},mediaActionSheetChange(event) {this.setData({showTab: true,mediaActionSheetHidden: true,})},// 将内容写入至日记对象
  writeContent(res, type) {let diary = this.data.diary;if (type === IMAGE) {res.tempFilePaths.forEach((element, index, array) => {// TODO 内容上传至服务器diary.list.push(this.makeContent(type, element, ''))});}if (type === VIDEO) {// TODO 内容上传至服务器diary.list.push(this.makeContent(type, res.tempFilePath, ''))}// 设置日记封面if (type === IMAGE && !this.data.diary.meta.cover) {this.setData({'diary.meta.cover': res.tempFilePaths[0]});}this.setDiary(diary);this.hideLoading();this.showTab();},// 从相册选择照片或拍摄照片
  chooseImage() {let that = this;wx.chooseImage({count: 9,  // 最多选9张sizeType: ['origin', 'compressed'],sourceType: ['album', 'camera'],success: (res) => {this.setData({mediaActionSheetHidden: true});this.showLoading('图片处理中...');that.writeContent(res, IMAGE);}})},// 从相册选择视频文件
  chooseVideo() {let that = this;wx.chooseVideo({sourceType: ['album'],  // 仅从相册选择success: (res) => {this.setData({mediaActionSheetHidden: true});this.showLoading('视频处理中...');that.writeContent(res, VIDEO);}})},// 获得当前位置信息
  getPoi() {var that = this;wx.getLocation({type: 'gcj02',success: function(res) {geo.mapRequest('geocoder',{'location': geo.formatLocation(res)},loc => {let poi = {'latitude': res.latitude,'longitude': res.longitude,'name': loc.result.address,};that.setData({poi: poi});})}})},// 构造日记内容对象
  makeContent(type, content, description) {return {type: type,content: content,description: description,poi: this.data.poi,};},// 构造日记meta信息
  setMeta() {var that = this;app.getUserInfo(info => {that.setData({'diary.meta.avatar': info.avatarUrl,'diary.meta.nickName': info.nickName,})})},})

b) .json
c) .wxml
<!--new.wxml--><template name="common"><scroll-view class="container" scroll-y="true"><view class="common-container"><view class="item-group" wx:for="{{layoutList}}" wx:for-item="group"><block wx:for="{{group}}" wx:for-item="item"><block wx:if="{{item.type == 'TEXT'}}"><view class="album-item content-text"><view>{{item.content}}</view></view></block><block wx:elif="{{item.type == 'IMAGE'}}"><image src="{{item.content}}" class="album-item" mode="aspectFill"></image></block><block wx:elif="{{item.type == 'VIDEO'}}"><video class="album-item" src="{{item.content}}"></video></block></block></view></view></scroll-view><view class="tabbar" style="display:{{showTab ? 'flex' : 'none'}};"><view class="item" bindtap="inputTouch"><image class="icon" mode="aspectFit" src="../../images/tabbar/text.png"></image></view><view class="item" bindtap="mediaTouch"><image class="icon" mode="aspectFit" src="../../images/tabbar/image.png"></image></view><view class="item"><image class="icon" mode="aspectFit" src="../../images/tabbar/more.png"></image></view></view><action-sheet hidden="{{mediaActionSheetHidden}}" bindchange="mediaActionSheetChange"><block wx:for-items="{{mediaActionSheetItems}}" wx:for-index="id"><action-sheet-item class="action-item" bindtap="{{mediaActionSheetBinds[id]}}">{{item}}</action-sheet-item></block><action-sheet-cancel class='action-cacel'>取消</action-sheet-cancel></action-sheet>
</template><template name="inputText"><view class="input-container"><view style="height:47rpx" wx:for="{{inputStatus.lines}}" wx:for-index="idx"><input type="text" data-index="{{idx}}" placeholder="" bindinput="textInput" bindchange="textInputChange" value="{{item}}" auto-focus="{{idx == inputStatus.row ? true : false}}" bindfocus="focusInput"/></view></view><view class="tabbar"><view class="item" style="width:50%" bindtap="inputCancel"><image class="icon" mode="aspectFit" src="../../images/tabbar/cancel.png"></image></view><view class="item" style="width:50%" bindtap="inputDone"><image class="icon" mode="aspectFit" src="../../images/tabbar/ok.png"></image></view></view>
</template><view style="width:100%;height:100%"><block wx:if="{{showMode == 'common'}}"><template is="{{showMode}}" data="{{showTab: showTab, mediaActionSheetHidden: mediaActionSheetHidden, mediaActionSheetItems: mediaActionSheetItems, mediaActionSheetBinds: mediaActionSheetBinds, layoutList: layoutList}}"></template></block><block wx:if="{{showMode == 'inputText'}}"><template is="{{showMode}}" data="{{inputStatus}}"></template></block><loading hidden="{{!showLoading}}" bindchange="hideLoading">{{loadingMessage}}</loading>
</view>

d) .wxss
/** new.wxss **/.container {height: 91%;
}.common-container {margin: 0.1rem;
}.item-group {display: flex;align-items: center;
}.album-item {flex-direction: column;margin: 0.1rem;background: white;width: 6.4rem;height: 6.4rem;
}.content-text{justify-content: center;align-items: center;display: flex;
}.content-text view {overflow: hidden;text-overflow: ellipsis;font-size: 10px;line-height: 15px;
}.tabbar {position: fixed;width: 100%;height: 8%;left: 0;right: 0;bottom: 0;background-color: white;display: flex;flex-direction: row;justify-content: space-between;
}.tabbar .item {width: 33.33%;display: flex;justify-content: center;align-items: center;
}.item .icon {width: 50rpx;height: 50rpx;
}.input-container {height: 80%;background-color: #eceff4;background-image: linear-gradient(#E1E6EA .1em, transparent .1em);background-size: 100% 48rpx;padding: 0;box-sizing: border-box;margin: 0 10rpx;
}.input-container input{height: 47rpx;max-height: 47rpx;font-size: 28rpx;margin: 0px;
}.action-item, .action-cacel {font-size: 30rpx;color: #39b5de;
}

e)
5、
a) .js
b) .json
c) .wxml
d) .wxss

e)
6、

4.返回顶部
5.返回顶部
0、
https://github.com/harveyqing/BearDiary
1、
6.返回顶部
作者:ylbtech
出处:http://ylbtech.cnblogs.com/
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。

转载于:https://www.cnblogs.com/storebook/p/9509614.html

小程序-demo:小熊の日记相关推荐

  1. 微信小程序之日记本,纪录人生(微信小程序之小熊の日记)

    功能完备,实用导向,Server端API支持,涵盖众多组件.API使用,适用于学习微信小程序,多行文本模拟实现tab切换模态框和本地数据组织及存储,有图片预览功能,微信小程序方便人们的生活. 下面是微 ...

  2. java小程序贪吃蛇代码_微信小程序Demo之贪食蛇

    原标题:微信小程序Demo之贪食蛇 差不多大半年前,笔者发布了一篇关于OC版贪食蛇开发的文章,时隔多月,微信小程序横空出世,于是闲来无事的我又写了一个小程序版. 01页面布局 关于小程序笔者就不做介绍 ...

  3. 最常用的小程序demo

    wx-gesture-lock  微信小程序的手势密码 WXCustomSwitch 微信小程序自定义 Switch 组件模板 WeixinAppBdNovel 微信小程序demo:百度小说搜索 sh ...

  4. 微信小程序一双日记-项目分享

    github地址 项目入口 ?????????? 小程序已经发布至市场,可以扫码体验 项目介绍 为什么写这个项目 我设计这款产品,灵感来自于大家儿时在学生时代时,写的情侣日记这个点.我认为日记即是生活 ...

  5. 小程序开发教程、小程序资讯、小程序demo、小程序实战等合揖(7月19日更新)

    7月19日微信小程序联盟更新的小程序开发教程.小程序资讯.小程序demo.小程序实战内容合揖如下: 小程序资讯与小程序教程 一张图带你看懂小程序发展蓝皮书 2017-07-19 微信小程序开发问答&l ...

  6. 小程序开发教程、小程序资讯、小程序demo、小程序实战等合揖(7月19日更新)...

    2019独角兽企业重金招聘Python工程师标准>>> 7月19日微信小程序联盟更新的小程序开发教程.小程序资讯.小程序demo.小程序实战内容合揖如下: #小程序资讯与小程序教程 ...

  7. 最全微信小程序demo

    wx-gesture-lock  微信小程序的手势密码 WXCustomSwitch 微信小程序自定义 Switch 组件模板 WeixinAppBdNovel 微信小程序demo:百度小说搜索 sh ...

  8. WX小程序demo示例

    wx-gesture-lock  微信小程序的手势密码 WXCustomSwitch 微信小程序自定义 Switch 组件模板 WeixinAppBdNovel 微信小程序demo:百度小说搜索 sh ...

  9. 微信小程序踩坑日记-微信小程序首次加载样式错乱问题

    微信小程序踩坑日记-微信小程序首次加载样式错乱问题 在实际开发项目中,遇到了个棘手的问题,就是在某些因素下,进入小程序发现有些样式发生偏移.错乱等问题 问题原因:-未知(估计是组件的问题) ↓ 解决办 ...

最新文章

  1. python下拉菜单_python-web自动化:下拉列表操作
  2. 计算机应用属不属于科技股,哪些股票属于科技股
  3. java实现对文件加解密操作
  4. 一步一步搭建客服系统 (7) 多人共享的电子白板、画板
  5. matlab求解helmholtz,MATLAB与科学计算(第2版)
  6. Intel 64/x86_64/IA-32/x86处理器 - SIMD指令集 - SSE扩展(10) - MXCSR状态控制指令
  7. php yii应用运维,Windows运维之Windows下用cmd命令实例讲解yii2.0在php命令行中运行的步骤...
  8. 定位会完全压住标准流盒子里面的内容(HTML、CSS)
  9. python str转json_Python中如何将一个字符串转换为json格式呢?
  10. 部署在IIS服务器的asp.net 网站,禁止访问指定类型文件
  11. SpringMVC核心
  12. excel快速选择数据的4种方法
  13. Hive调优之 union all 效率低的问题解决
  14. 张张催人泪下 图说“工人阶级”的心酸谋生路
  15. 微软mes杀毒更新服务器搭建,我的系统的不能用Microsoft Update更新的啊
  16. 最优传输论文(二十六):Sliced Wasserstein Discrepancy for Unsupervised Domain Adaptation论文原理
  17. h3c 云服务器操作系统,H3C云服务器安装系统的前期准备
  18. Matlab 动态心形线GIF图
  19. 自动切图生成html,Photoshop如何实现UI自动切图?_html/css_WEB-ITnose
  20. 台式计算机硬件组成主机,台式电脑主机的硬件组成部分简介

热门文章

  1. 计算机储存数据怎样操作,计算机如何存储数据
  2. Savieo 万能下载器,下载多达34 站点,包括ins、Facebook
  3. 怎样形成计算机知识体系,打牢基础,形成网络化知识体系
  4. 24、新增商铺 - 小程序端开发 - 微擎小程序模块应用开发
  5. 量子通信基础知识简介(一)
  6. 预见未来: 微软亚洲研究院看下一个二十年
  7. Android应用利用libusb设备通信权限问题
  8. EP10W2A02N05方向阀导压操作插装阀
  9. VLC-你不知道的那些功能-播客
  10. 腾讯阿里是否开始走向衰落,用新互联网大脑模型分析