微信小程序开发入门教程(四)---自己动手做个小程序
前面已将基础知识准备的差不多了,下面实际做一个小程序。
一、目标
用于上传照片和文字。
2个主要页面:我me,设置set
二、开始制作
1、打开微信开发者工具(我用的1.02.1907160 Windows 64版本),点+号,新建项目diary,选择目录E:\wxDEV\diary,填入从微信开发平台申请到的AppID,开发模式默认为小程序,后端服务选择云开发,点新建,生成了云开发QuitStart示例模板。下面在此模板基础上制作。
2、建立me set页面,并给小程序增加tabBar。即修改E:\wxDEV\minishop\miniprogram\app.json并保存。代码如下:
{
"pages": [
"pages/index/index",
"pages/me/me",
"pages/people/people",
"pages/set/set"
],
"window": {
"backgroundColor": "#F6F6F6",
"backgroundTextStyle": "light",
"navigationBarBackgroundColor": "#F6F6F6",
"navigationBarTitleText": "日记",
"navigationBarTextStyle": "black"
},
"tabBar": {
"backgroundColor": "#eeeeee",
"position": "bottom",
"list": [
{
"pagePath": "pages/me/me",
"text": "我",
"iconPath": "images/img.jpg",
"selectedIconPath": "images/img.jpg"
},
{
"pagePath": "pages/set/set",
"text": "设置",
"iconPath": "images/img.jpg",
"selectedIconPath": "images/img.jpg"
}
]
},
"sitemapLocation": "sitemap.json"
}
同时,要在images目录中放置一张img.jpg图片(我自己画了一张)
3、我打算将现有的index页作为将来的splash页。所以先修改E:\wxDEV\diary\miniprogram\pages\index\index.js,以实现2秒后跳转me页,代码:
//index.js
Page({
data: {},
onLoad: function() {
setTimeout(function() {
wx.reLaunch({
url: '../me/me',
})
}, )
}
})
4、修改me页(为方便调试,可更改app.json中pages值的顺序,将me调整到前面)。原本想在me页上用movable-view增加可拖动的按钮样式,如下:
<!--可拖动按钮-->
<movable-area style="height:{{mHeight}}px;width:100%;position:fixed;z-index:999;pointer-events:none;">
<movable-view direction="all" style="height: 30px; line-height:30px;width: 30px; margin-left:100%; border:2px solid lightblue;border-radius:50%;">
<cover-view bindtap="writeDiary">
<cover-image src='../../images/img.jpg'></cover-image>
</cover-view>
</movable-view>
</movable-area>
结果在安卓真机上出现兼容性问题,拖动时cover-view瞬间移动,而cover-image不跟随移动,无法正常工作。(谁知道解决办法给我讲一下?)只好弃用。
云开发的云函数的独特优势在于与微信登录鉴权的无缝整合,参考:https://developers.weixin.qq.com/miniprogram/dev/wxcloud/guide/functions/userinfo.html
所以,对不同用户上传内容可以用openid区分。
5.半成品的me.wxml ,代码如下:
<!--pages/me/me.wxml-->
<view style="display:flex;flex-direction: row-reverse;margin-right:20px;font-size:150%;"><text bindtap="writeDiary">{{inputCursor}}</text></view> <view style="width:100%;">
<!-- 上传图片 -->
<view class="uploader">
<view class="uploader-text" bindtap="selPic">
<text>拍照或选择图片(可选)</text>
</view>
<view class="uploader-container" wx:if="{{imgUrl}}">
<image class="uploader-image" src="{{imgUrl}}" mode="aspectFit" bindtap="previewImg"></image>
</view>
</view>
<!-- 表单 -->
<form class="formpub" bindsubmit="formSubmit" bindreset="formReset">
<!-- 保存图片临时路径 -->
<view class="section">
<input name="img" value="{{imgUrl}}" hidden="true" />
</view> <view class="content">
<view class="currentWordNumber">{{currentWordNumber|}}/{{max}}</view>
<!-- 别忘了给textarea加上name属性 -->
<textarea name="diaryContent" bindblur="getText" bindinput="getValueLength" show-confirm-bar='true' value="{{editText}}" bindconfirm="getText" maxlength="{{max}}" minlength="{{min}}" placeholder="内容..." auto-focus>
<text class="minWord">{{minWord}}</text>
</textarea>
</view>
<view class="tips">在上面填写内容</view> <view class="btn-area">
<button form-type="submit" style="width: 80%; margin-top: 20rpx;background-color: beige;color: black;border:2px solid lightblue;">写完了</button>
</view>
</form>
</view> <block wx:for="{{diarys}}" wx:key="{{index}}">
<view style="display:flex;width:100%;min-height:50px;background:rgb(248, 248, 248);margin:8px;">
<view style="border:20px;">
<image wx:if='{{item["img"]}}' src='{{item["img"]}}'mode="widthFix" style="width:100px;"></image>
</view>
<view style="width:100%;border-bottom:solid 1px lightgrey;padding-left:10px;"> {{item["content"]}} </view>
</view>
</block>
<view>
<image src='../../images/img.jpg' mode="widthFix" style="width:50px"></image>
</view>
me.js
// pages/me/me.js
Page({ /**
* 页面的初始数据
*/
data: {
//以下变量也可以不写在这里,可直接在代码中声明和使用,但推荐写在这里
mHeight: ,
hiddenInput: true,
inputCursor: '+',
max: , //限制最大输入字符数
min: , //限制最小输入字符数
minWord: '', //提示语句
imgUrl: '', //要上传的图片的url
editText: '', //textarea中编辑的内容
diarys: {},
curPage:
}, /**
* 生命周期函数--监听页面加载
*/
onLoad: function(options) { }, //写日记
writeDiary: function() {
let tempCursor = ''
if (this.data.inputCursor == '+') {
tempCursor = '-'
} else {
tempCursor = '+'
}
this.setData({
hiddenInput: !this.data.hiddenInput,
inputCursor: tempCursor
})
//滚动视口,返回顶部
wx.pageScrollTo({
scrollTop: ,
duration:
})
},
/****限制字数与计算 */
getValueLength: function(e) {
let value = e.detail.value
let len = parseInt(value.length)
//最少字数限制
if (len <= this.data.min)
this.setData({
minWord: "至少填写10个字哦~"
})
else if (len > this.data.min)
this.setData({
minWord: " "
})
//最多字数限制
if (len > this.data.max) return;
this.setData({
currentWordNumber: len //当前字数
})
},
formSubmit: function(e) {
console.log('form发生了submit事件,携带数据为:', e.detail.value)
let upDiaryContent = e.detail.value["diaryContent"]
let upimgUrl = e.detail.value["img"]
let len = parseInt(upDiaryContent.length)
//最少字数限制
if (len <= this.data.min) {
this.setData({
minWord: "至少填写10个字哦~"
})
return
}
wx.showLoading({
title: '请等待',
})
//判断有无图片
if (typeof upimgUrl == "undefined" || upimgUrl == null || upimgUrl == "") {
//没有图片,直接上传文字
const db = wx.cloud.database()
db.collection('diarys').add({
data: {
content: upDiaryContent
},
success: res => {
//无图,文字上传成功了
this.reset()
console.log('[数据库] [新增记录] 成功,记录 _id: ', res._id)
},
fail: err => {
wx.showToast({
icon: 'none',
title: '新增记录失败'
})
console.error('[数据库] [新增记录] 失败:', err)
} })
} else { //有图片,则先上传图片
const timestamp = new Date().getTime();
const relCloudPath = 'diarys/' + timestamp + upimgUrl.match(/\.[^.]+?$/)[]
console.log()
console.log(upimgUrl)
console.log(relCloudPath)
wx.cloud.uploadFile({
cloudPath: relCloudPath,
filePath: upimgUrl,
success: res => {
console.log('[上传文件] 成功:', res)
let imgFileID = res.fileID
//再上传文字
const db = wx.cloud.database()
db.collection('diarys').add({
data: {
img: imgFileID,
content: upDiaryContent
},
success: res => {
//文字也上传成功了
this.reset()
console.log('[数据库] [新增记录] 成功,记录 _id: ', res._id)
},
fail: err => {
//文字上传失败
wx.showToast({
icon: 'none',
title: '新增记录失败'
})
console.error('[数据库] [新增记录] 失败:', err)
}
})
},
fail: e => {
console.error('[上传文件] 失败:', e)
wx.showToast({
icon: 'none',
title: '上传失败',
})
}
})
}
//图片和文字全部上传了。
wx.hideLoading()
},
// 选择图片
selPic: function() {
var that = this
wx.chooseImage({
count: ,
sizeType: ['compressed'],
sourceType: ['album', 'camera'],
success: function(res) { wx.showLoading({
title: '请等待',
}) const imgfilePath = res.tempFilePaths[]
that.setData({
imgUrl: imgfilePath
}) },
fail: e => {
this.setData({
imgUrl: ''
})
//console.error(e)
},
complete: () => {
wx.hideLoading()
}
})
},
//重置
reset: function() {
let tempCursor = ''
if (this.data.inputCursor == '+') {
tempCursor = '-'
} else {
tempCursor = '+'
}
this.setData({
'imgUrl': '',
'editText': '',
'hiddenInput': !this.data.hiddenInput,
minWord: '',
inputCursor: tempCursor
})
},
// 查询当前用户的数据库集合,暂时没用
onQuery: function(p) {
const db = wx.cloud.database()
db.collection('diarys').skip(p)
.get()
.then(res => {
console.log(res.data)
console.log(res.data[].img)
})
.catch(console.error)
}, /**
* 生命周期函数--监听页面初次渲染完成
*/
onReady: function() {
wx.getSystemInfo({
success: res => {
let h = res.windowHeight
//取20条数据
const db = wx.cloud.database()
db.collection('diarys')
.get()
.then(res => {
this.setData({
mHeight: h,
diarys: res.data
})
console.log(res.data)
console.log(res.data[].img)
})
.catch(console.error)
},
}) }, /**
* 生命周期函数--监听页面显示
*/
onShow: function() { }, /**
* 生命周期函数--监听页面隐藏
*/
onHide: function() { }, /**
* 生命周期函数--监听页面卸载
*/
onUnload: function() { }, /**
* 页面相关事件处理函数--监听用户下拉动作
*/
onPullDownRefresh: function() { }, /**
* 页面上拉触底事件的处理函数
*/
onReachBottom: function() { }, /**
* 用户点击右上角分享
*/
onShareAppMessage: function() { }
})
me.wxss
/* pages/me/me.wxss */
.currentWordNumber {
height: 35px;
line-height: 35px;
font-size: 14px;
float: right;
margin-right: 15px;
color: rgba(, , , );
margin-bottom: 10px;
}
.minWord {
color: rgb(, , );
font-size: 14px;
position: absolute;
top: 30px;
}
.tips {
width: %;
margin-left: %;
height: 45px;
color: rgba(, , , );
font-size: 14px;
margin-top: 15px;
text-align: left;
font-family: PingFangSC-regular;
}
textarea {
min-height: 500rpx;
max-height: 500rpx;
padding: 10rpx 10rpx;
font-size: %;
width: %;
margin-left: %;
margin-top: 15px;
}
.content {
border-top: 1px solid rgb(, , );
width: %;
margin: auto;
background-color: #ffff;
}
参考:授权 https://www.jianshu.com/p/480ff10bfb54
textarea https://blog.csdn.net/ChibiMarukoChan/article/details/88659746
...
微信小程序开发入门教程(四)---自己动手做个小程序的更多相关文章
- C#微信公众号开发系列教程四(接收普通消息)
微信公众号开发系列教程一(调试环境部署) 微信公众号开发系列教程一(调试环境部署续:vs远程调试) C#微信公众号开发系列教程二(新手接入指南) C#微信公众号开发系列教程三(消息体签名及加解密) C ...
- 微信小程序开发入门教程
做任何程序开发要首先找到其官方文档,微信小程序目前还在邀请内测阶段,目前官方放出了部分开发文档,经过笔者一天的查看和尝试,感觉文档并不全面,但是通过这些文档已经能够看出其大概面貌了.闲话不多说,我们先 ...
- C#微信公众号开发入门教程
首先打开开发文档: 微信公众号开发者文档:http://mp.weixin.qq.com/wiki/home/index.html 一.创建测试账号 可以先申请一个开发者测试账号
- 微信小程序开发入门教程(二)---分析官方云开发例子中的一些功能
接上一篇文章:https://www.cnblogs.com/pu369/p/11326538.html 1.官方云开发的例子中,点击获取 openid,对应代码在E:\wxDEV\helloyun\ ...
- 微信小程序开发入门教程(一)---hello world
由于无法备案网站,前期做了个微信小程序(开发版)就搁置了,几乎忘了开发过程.现在重新梳理,做个记录. 一.最基本的小程序前端例子hello 1.下载安装 微信开发者工具 官网: https://d ...
- 微信小程序开发入门教程(三)---小程序云开发支付功能
支付(shoukuan)功能真的很重要!由于我还没有商户号,以下代码未实际验证 1.服务端 进入云开发,新建云函数pay(应该也可以在开发者工具编写后上传) 编写后端代码index.js这里用到第三方 ...
- C#微信公众号开发系列教程六(被动回复与上传下载多媒体文件)
微信公众号开发系列教程一(调试环境部署) 微信公众号开发系列教程一(调试环境部署续:vs远程调试) C#微信公众号开发系列教程二(新手接入指南) C#微信公众号开发系列教程三(消息体签名及加解密) C ...
- C#微信公众号开发系列教程五(接收事件推送与消息排重)
微信公众号开发系列教程一(调试环境部署) 微信公众号开发系列教程一(调试环境部署续:vs远程调试) C#微信公众号开发系列教程二(新手接入指南) C#微信公众号开发系列教程三(消息体签名及加解密) C ...
- 微信小程序开发系列教程三:微信小程序的调试方法
微信小程序开发系列教程 微信小程序开发系列一:微信小程序的申请和开发环境的搭建 微信小程序开发系列二:微信小程序的视图设计 这个教程的前两篇文章,介绍了如何用下图所示的微信开发者工具自动生成一个Hel ...
随机推荐
- Mybatis Plus带多条件的多表联合、分页、排序查询
目录 一.现有表 student学生表: facultylist学院表: 二.同时满足以下需求: 1.多表联合查询出学院名字 2.可以带多条件查询 3.指定页码,页数据大小进行物理分页查询 三.解决步 ...
- Kubernetes---容器探针
⒈含义 探针是由各个节点的kubelet对容器执行的定期诊断.要执行诊断,kubelet 调用由容器实现的Handler[处理程序].有三种类型的处理程序: >ExecAction:在容器内执行 ...
- 利用Python进行数据分析_Numpy_基础_1
ndarray:多维数组 ndarray 每个数组元素必须是相同类型,每个数组都有shape和dtype对象. shape 表示数组大小 dtype 表示数组数据类型 array 如何创建一个数组? ...
- Java 字符串比较
1.字符串比较 compareTo() 方法用于两种方式的比较: 字符串与对象进行比较. 按字典顺序比较两个字符串. 返回值 返回值是整型,它是先比较对应字符的大小(ASCII码顺序),如果第一个字符 ...
- WinSockAPI多线程服务器
运行效果: 程序: // TcpServer.cpp : 定义控制台应用程序的入口点. // #include "stdafx.h" #include <iostream&g ...
- 3. Java开发环境的搭建:安装JDK,配置环境变量
1.安装JDK开发环境 下载网站:http://www.oracle.com/ 开始安装JDK: 修改安装目录如下: 确定之后,单击“下一步”. 注:当提示安装JRE时,可以选择不要安装. 2.配置环 ...
- [转载]Java序列化与反序列化
[转载]Java序列化与反序列化 来源: https://www.cnblogs.com/anitinaj/p/9253921.html 序列化和反序列化作为Java里一个较为基础的知识点,那你能说一 ...
- vue-cli3 本地数据模拟后台接口
vue-cli3 本地数据模拟后台接口 原理: 将本地的json数据在前端模拟为后台接口,然后调用接口,完成前端操作.在后台接通后可以直接在api配置文件中修改路径,完成前后台对接. 配置: 1.文件 ...
- 使用Fiddler工具在夜神模拟器或手机上抓包
下载安装Fiddler 地址:https://www.telerik.com/download/fiddler-everywhere Fiddler端设置 Tools>Options>Co ...
- 命令行工具--LLDP
目录 命令行工具--LLDP 一.场景引入 二.什么是LLDP? 三.在CentOS上安装LLDP 四.命令详解 五.脚本 命令行工具--LLDP 一.场景引入 有的时候,我们需要知道服务器上联交换机 ...