動態發布小程序
配置ColorUI
下載ColorUI到本地解壓,復制ColorUI-master\demo\colorui
目錄到項目根目錄中。
在app.wxss
中導入全局外部CSS
@import "./colorui/main.wxss";
@import "./colorui/icon.wxss";
自定義導航欄
在app.json中取消系統導航欄
"window":{
"navigationStyle": "custom"
}
在app.js中獲取系統信息
wx.getSystemInfo({
success: (result) => {
this.globalData.StatusBar = result.statusBarHeight;
let custom = wx.getMenuButtonBoundingClientRect();
this.globalData.Custom = custom;
this.globalData.CustomBar = custom.bottom + custom.top - result.statusBarHeight;
},
})
home.wxml首頁導航欄試例
<cu-custom bgColor="bg-gradual-green" isBack="{{false}}">
<view slot="content">動態</view>
</cu-custom>
自定義底部導航欄
在app.json啟用custom導航欄
"tabBar": {
"custom": true,
"list": [{
"pagePath": "pages/home/home",
"text": "首頁"
},{
"pagePath": "pages/addmoment/addmoment",
"text": "分享動態"
}]
}
在項目根目錄新建custom-tab-bar
文件夾
custom-tab-bar
目錄結構
代碼部分
custom-tab-bar/index.wxml
使用自定義底部導航欄tabbar
<view class="box">
<view class="cu-bar tabbar">
<view class="action {{selected === 0 ? 'active' : 'default'}}" data-index="0" bindtap="switchTab">
<view class="cuIcon-home"></view> 首頁
</view>
<view class="action {{selected === 1 ? 'active' : 'default'}}" data-index="1" bindtap="switchTab">
<view class="cuIcon-share"></view> 分享
</view>
</view>
</view>
custom-tab-bar/index.js
Component({
properties: {
},
data: {
selected:0,
tabList:[
{
"pagePath": "pages/home/home",
},
{
"pagePath": "pages/addmoment/addmoment",
}
]
},
methods: {
switchTab(e){
//console.log(this.data)
let key = Number(e.currentTarget.dataset.index);
let tabList = this.data.tabList;
let selected = this.data.selected;
if(selected !== key){
this.setData({
selected:key
});
wx.switchTab({
url: `/${tabList[key].pagePath}`,
})
}
}
}
})
custom-tab-bar/index.json
{
}
custom-tab-bar/index.wxss
樣式
/*自定義Component全局樣式失效,手動引入*/
@import "../colorui/main.wxss";
@import "../colorui/icon.wxss";
.tabbar{
background-color: white;
}
.active{
color: orange;
}
.default{
color:rgb(51, 24, 24);
}
需要在home.js
和addmoment.js
中設置當前選中的Tab
home.js
// pages/home/home.js
Page({
onShow: function () {
this.tabBar();
},
tabBar(){
if(typeof this.getTabBar === 'function' && this.getTabBar()){
this.getTabBar().setData({
//當前位於選中為首頁
selected:0
})
}
},
})
addmoment.js
// pages/addmoment/addmoment.js
Page({
onShow: function () {
this.tabBar();
},
tabBar(){
if(typeof this.getTabBar === 'function' && this.getTabBar()){
this.getTabBar().setData({
//當前位於選中為分享
selected:1
})
}
},
})
雲開發數據集
- comments(評論)
- moments(動態)
權限
pages/auth/auth.wxml
<!--pages/auth/auth.wxml-->
<cu-custom bgColor="bg-gradual-pink">
<view slot="content">授權</view>
</cu-custom>
<view class="cu-bar padding margin-top flex justify-center">
<view class="padding-sm">
<view>
<open-data type="userAvatarUrl"></open-data>
</view>
</view>
</view>
<view class="padding bg-white margin-lr-xs solid-bottom">
<view class="text-black">該應用將獲取以下授權並登錄:</view>
<view class="text-grey">獲取您的公開信息(昵稱,頭像,性別等)</view>
</view>
<view class="flex justify-center bg-white margin-lr-xs">
<button class="cu-btn bg-red padding-sm margin-sm" bindtap="refuseAuth">拒絕</button>
<button class="cu-btn bg-green padding-sm margin-sm" wx:if="{{canIUseGetUserProfile}}" bindtap="getUserProfile">允許</button>
<button wx:else class="cu-btn bg-green padding-sm margin-sm" open-type="getUserInfo" bindgetuserinfo="getUserInfo">允許</button>
</view>
pages/auth/auth.js
// pages/auth/auth.js
Page({
/**
* 頁面的初始數據
*/
data: {
canIUseGetUserProfile: false,
userInfo: {}
},
refuseAuth: function() {
wx.switchTab({
url: '../home/home',
})
},
getUserInfo: function(e) {
if(e.detail.userInfo) {
console.log("可用");
console.log(e.detail.userInfo);
wx.cloud.callFunction({
name: "getOpenId",
}).then(res => {
wx.setStorageSync("openid", res.result.openid);
})
wx.setStorageSync("userInfo", e.detail.userInfo);
wx.showToast({
title: '授權成功...',
icon: 'success',
duration: 1500
})
} else {
console.log("獲取信息失敗")
}
wx.navigateBack({
delta: 1,
})
},
getUserProfile: function(e) {
wx.cloud.callFunction({
name: "getOpenId",
}).then(res => {
wx.setStorageSync("openid", res.result.openid);
})
wx.getUserProfile({
desc: "用於完善資料",
success: res => {
wx.setStorageSync('userInfo', res.userInfo);
wx.showToast({
title: '授權成功...',
icon: 'success',
duration: 1500
})
wx.navigateBack({
delta: 1,
})
}
})
},
/**
* 生命周期函數--監聽頁面加載
*/
onLoad: function (options) {
if(wx.getUserProfile) {
this.setData({
canIUseGetUserProfile: true
})
} else {
console.log("不可用")
}
},
/**
* 生命周期函數--監聽頁面初次渲染完成
*/
onReady: function () {
},
/**
* 生命周期函數--監聽頁面顯示
*/
onShow: function () {
},
/**
* 生命周期函數--監聽頁面隱藏
*/
onHide: function () {
},
/**
* 生命周期函數--監聽頁面卸載
*/
onUnload: function () {
},
/**
* 頁面相關事件處理函數--監聽用戶下拉動作
*/
onPullDownRefresh: function () {
},
/**
* 頁面上拉觸底事件的處理函數
*/
onReachBottom: function () {
},
/**
* 用戶點擊右上角分享
*/
onShareAppMessage: function () {
}
})
首頁
pages/home/home.wxml
<!--pages/home/home.wxml-->
<cu-custom bgColor="bg-gradual-pink" isBack="{{false}}">
<view slot="content">動態</view>
</cu-custom>
<view class="myPage">
<view wx:if="{{momentsList.length}}">
<block wx:for="{{momentsList}}" wx:key="this">
<view class="cu-card case dynamic no-card margin-tb radius">
<view class="cu-item shadow" data-id="{{item._id}}" bindtap="momentClick">
<view class="cu-list menu-avatar">
<view class="cu-item">
<view class="cu-avatar round lg" style="background-image: url({{item.avatarUrl}})">
</view>
<view class="content solid-bottom">
<view class="text-grey">{{item.publisher}}</view>
<view class="text-gray sm">{{item.time}}</view>
</view>
</view>
</view>
<view class="text-content">{{item.title}}</view>
<view class="grid flex-sub padding-lr">
<image style="width: 100%" src="{{item.imgUrl[0]}}" mode="aspectFill"></image>
</view>
<view class="text-gray text-sm text-right padding">
<text class="cuIcon-attentionfill margin-lr-xs"></text>{{item.views}}
<text class="cuIcon-appreciatefill margin-lr-xs"></text>{{item.appreciates}}
<text class="cuIcon-messagefill margin-lr-xs"></text>{{item.comment}}
</view>
</view>
</view>
</block>
</view>
<view class="cu-bar margin bg-gradual-green" wx:else>
<view class="content">沒有動態,等你來分享</view>
</view>
</view>
pages/home/home.wxss
消除自定義底部導航欄的高度對頁面高度造成的覆蓋影響。
/* pages/home/home.wxss */
.myPage {
padding-bottom: calc(120rpx + env(safe-area-inset-bottom) / 2);
}
pages/home/home.js
// pages/home/home.js
const db = wx.cloud.database();
var util = require('../../utils/util.js');
Page({
/**
* 頁面的初始數據
*/
data: {
momentsList: {},
openid: ""
},
/**
* 生命周期函數--監聽頁面加載
*/
onLoad: function (options) {
var userInfo = wx.getStorageSync('userInfo');
this.data.openid = wx.getStorageSync('openid');
if(userInfo == "") {
wx.navigateTo({
url: '../auth/auth',
})
} else {
this.setData({
userInfo: userInfo
})
}
},
/**
* 生命周期函數--監聽頁面初次渲染完成
*/
onReady: function () {
},
/**
* 生命周期函數--監聽頁面顯示
*/
onShow: function () {
this.tabBar();
db.collection('moments').orderBy('istop', 'desc').orderBy('submitdate', 'desc').get().then(res => {
for(var index in res.data) {
res.data[index].time = util.formatTime(res.data[index].submitdate);
let length = res.data[index].time.length;
res.data[index].time = res.data[index].time.replaceAll('/', '-').slice(0, length-9);
res.data[index].views = res.data[index].view.length;
res.data[index].appreciates = res.data[index].appreciate.length;
}
this.setData({
momentsList: res.data
})
}).catch(err => {
console.log(err);
})
},
/**
* 生命周期函數--監聽頁面隱藏
*/
onHide: function () {
},
/**
* 生命周期函數--監聽頁面卸載
*/
onUnload: function () {
},
/**
* 頁面相關事件處理函數--監聽用戶下拉動作
*/
onPullDownRefresh: function () {
},
/**
* 頁面上拉觸底事件的處理函數
*/
onReachBottom: function () {
},
/**
* 用戶點擊右上角分享
*/
onShareAppMessage: function () {
},
momentClick: function(e) {
// console.log(e.currentTarget.dataset.id)
let openid = this.data.openid;
// console.log(openid)
wx.cloud.callFunction({
name: 'moment',
data: {
$url: "view_inc",
id: e.currentTarget.dataset.id,
openid: openid
}
}).then((res)=>{
})
wx.navigateTo({
url: '../momentdetail/momentdetail?id=' + e.currentTarget.dataset.id
})
},
tabBar(){
if(typeof this.getTabBar === 'function' && this.getTabBar()){
this.getTabBar().setData({
selected:0
})
}
},
})
添加動態
pages/addnews/addnews.wxml
<!--pages/addnews/addnews.wxml-->
<cu-custom bgColor="bg-gradual-pink">
<view slot="content">添加動態</view>
</cu-custom>
<form>
<view class="cu-form-group margin-top">
<view class="title">
<text>*標題:</text>
</view>
<input bindinput="updateValue" data-name="title" placeholder="請輸入標題"></input>
</view>
<view class="cu-form-group align-start">
<view class="title">
<text>*內容</text>
</view>
<textarea maxlength="-1" bindinput="updateValue" data-name="content" placeholder="請輸入內容"></textarea>
</view>
<view class="cu-form-group">
<view class="title">
<text>是否置頂</text>
</view>
<switch class="cyan sm" bindchange="switchChange"></switch>
</view>
<view class="cu-bar bg-white margin-top">
<view class="action">
<text>圖片上傳</text>
</view>
<view class="action">
{{imgList.length}}/3
</view>
</view>
<view class="cu-form-group padding">
<view class="grid col-3 grid-square flex-sub">
<view class="bg-img" wx:for="{{imgList}}" wx:key="this" bindtap="ViewImage" data-url="{{imgList[index]}}">
<image src="{{imgList[index]}}" mode="aspectFill"></image>
<view class="cu-tag bg-red" catchtap="DelImg" data-id="{{index}}">
<text class="cuIcon-close"></text>
</view>
</view>
<view class="solids" bindtap="ChooseImage" wx:if="{{imgList.length<3}}">
<text class="cuIcon-cameraadd"></text>
</view>
</view>
</view>
</form>
<view class="cu-btn-group padding flex justify-center">
<button class="basis-sm cu-btn bg-green shadow margin-sm" bindtap="submitform">發布</button>
</view>
pages/addnews/addnews.js
// pages/addnews/addnews.js
var util = require('../../utils/util.js');
const db = wx.cloud.database();
Page({
/**
* 頁面的初始數據
*/
data: {
imgList: [],
momentInfo: {istop: 0},
userInfo: {}
},
/**
* 生命周期函數--監聽頁面加載
*/
onLoad: function (options) {
},
/**
* 生命周期函數--監聽頁面初次渲染完成
*/
onReady: function () {
},
/**
* 生命周期函數--監聽頁面顯示
*/
onShow: function () {
this.tabBar();
var userInfo = wx.getStorageSync('userInfo');
if(userInfo == "") {
wx.navigateTo({
url: '../auth/auth',
})
} else {
this.setData({
userInfo: userInfo
})
}
},
/**
* 生命周期函數--監聽頁面隱藏
*/
onHide: function () {
},
/**
* 生命周期函數--監聽頁面卸載
*/
onUnload: function () {
},
/**
* 頁面相關事件處理函數--監聽用戶下拉動作
*/
onPullDownRefresh: function () {
},
/**
* 頁面上拉觸底事件的處理函數
*/
onReachBottom: function () {
},
/**
* 用戶點擊右上角分享
*/
onShareAppMessage: function () {
},
switchChange: function(e) {
let momentInfo = this.data.momentInfo;
if(e.detail.value == true) {
momentInfo.istop = 1;
} else {
momentInfo.istop = 0;
}
this.setData({
momentInfo: momentInfo
})
},
updateValue: function(e) {
let name = e.currentTarget.dataset.name;
let momentInfo = this.data.momentInfo;
momentInfo[name] = e.detail.value;
this.setData({
momentInfo: momentInfo
})
},
ChooseImage: function() {
wx.chooseImage({
count: 3,
sizeType: ['original', 'compressed'],
sourceType: ['album'],
success: (res) => {
wx.showLoading({
title: '圖片上傳中...',
})
var time = util.formatTime(new Date());
console.log(time);
var FilePaths = [];
const temFilePaths = res.tempFilePaths;
let promiseArr = [];
for(let i = 0; i < temFilePaths.length; i++) {
let promise = new Promise((resolve, reject) => {
var randstring = Math.floor(Math.random() * 1000000).toString() + '.png';
randstring = time + '-' + randstring;
console.log(randstring);
wx.cloud.uploadFile({
cloudPath: 'newImages/' + randstring,
filePath: temFilePaths[i],
success: res => {
console.log(res.fileID);
FilePaths[i] = res.fileID,
resolve(res)
},
fail: err => {
reject(error);
}
})
})
promiseArr.push(promise);
}
Promise.all(promiseArr).then((result) => {
if(this.data.imgList.length != 0) {
this.setData({
imgList: this.data.imgList.concat(FilePaths)
})
} else {
this.setData({
imgList: FilePaths
})
}
wx.hideLoading({
success: (res) => {},
})
})
}
})
},
ViewImage: function(e) {
wx.previewImage({
urls: this.data.imgList,
current: e.currentTarget.dataset.url
})
},
DelImg: function(e) {
console.log(e.currentTarget.dataset.id);
var id = e.currentTarget.dataset.id;
var imgList = this.data.imgList;
wx.cloud.deleteFile({
fileList: [imgList[id]]
}).then(res => {
imgList.splice(id, 1);
this.setData({
imgList: imgList
})
console.log(res.fileList)
}).catch(error => {
})
},
submitform: function(e) {
let momentInfo = this.data.momentInfo;
let userInfo = this.data.userInfo;
if(momentInfo.title && momentInfo.content) {
db.collection('moments').add({
data: {
title: momentInfo.title,
content: momentInfo.content,
publisher: userInfo.nickName,
imgUrl: this.data.imgList,
avatarUrl: userInfo.avatarUrl,
submitdate: db.serverDate(),
istop: momentInfo.istop,
comment: 0,
appreciate: {length: 0, people: []},
view: {length:0, people: []}
}
}).then(wx.reLaunch({
url: '../home/home',
}))
} else {
wx.showToast({
title: '檢查內容',
icon: "none",
duration: 1500
})
}
},
tabBar(){
if(typeof this.getTabBar === 'function' && this.getTabBar()){
this.getTabBar().setData({
selected:1
})
}
}
})
查看、點贊的雲函數
cloudfunctions\moment\index.js
const cloud = require('wx-server-sdk');
cloud.init();
const TcbRouter = require('tcb-router');
const db = cloud.database();
const _ = db.command;
exports.main = async(event, context) => {
const app = new TcbRouter({event});
app.router('view_inc', async(ctx, next) => {
console.log("增加")
try {
db.collection('moments').where({
_id: _.eq(event.id),
view: {
people: _.elemMatch(_.eq(event.openid))
}
}).get().then(res => {
if(res.data.length == 0) {
return db.collection('moments').doc(event.id).update({
data: {
view: {
people: _.push(event.openid),
length: _.inc(1)
}
}
})
}
})
} catch(e) {
console.log(e)
}
await next();
})
app.router('appreciate_inc', async(ctx, next) => {
try {
db.collection('moments').where({
_id: _.eq(event.id),
appreciate: {
people: _.elemMatch(_.eq(event.openid))
}
}).get().then(res => {
if(res.data.length == 0) {
return db.collection('moments').doc(event.id).update({
data: {
appreciate: {
people: _.push(event.openid),
length: _.inc(1)
}
}
})
}
})
} catch(e) {
console.log(e)
}
await next();
})
app.router('comment_inc', async(ctx, next) => {
try {
return db.collection('moments').doc(event.id).update({
data:{
comment: _.inc(1)
}
})
} catch(e) {
console.log(e)
}
await next();
})
return app.serve();
}
修復問題
由於自定義組件不能使用ID,屬性等選擇符,將custom-tab-bar/index.wxss
文件引入的外部樣式表做相應的修改。
源文件
@import "../colorui/main.wxss"; @import "../colorui//icon.wxss"; .tabbar { background-color: white; } .active { color: orange; } .default { color: rgb(51, 24, 24); }
修改后
.tabbar { background-color: white; } .active { color: orange; } .default { color: rgb(51, 24, 24); } .cu-bar { display: flex; position: relative; align-items: center; min-height: 100rpx; justify-content: space-between; } .cu-bar .action { display: flex; align-items: center; height: 100%; justify-content: center; max-width: 100%; } .cu-bar.tabbar .action .cuIcon-home, .cu-bar.tabbar .action .cuIcon-edit { width: 100rpx; position: relative; display: block; height: auto; margin: 0 auto 10rpx; text-align: center; font-size: 40rpx; } .cu-bar.tabbar { padding: 0; height: calc(100rpx + env(safe-area-inset-bottom) / 2); padding-bottom: calc(env(safe-area-inset-bottom) / 2); } .cu-bar.tabbar .action { font-size: 22rpx; position: relative; flex: 1; text-align: center; padding: 0; display: block; height: auto; line-height: 1; margin: 0; overflow: initial; } .cuIcon-home:before { content: "\e6b8"; } .cuIcon-edit:before { content: "\e649"; }
全部改為使用class選擇器。