最近研究了uniCloud,并用uniCloud开发了一个性格测试小程序,已经发布到服务器,完美的发布到抖音,在抖音可以搜索到该小程序。
源码和视频教程都开源给大家了。小孟已经发布到抖音,全部的已经跑通,所以小伙伴可以拿去学习,没有任何的问题。
也出了详细的教程了!
视频的教程放在b站了,希望下坡伙伴,给个三连:
https://www.bilibili.com/video/BV19u411z7Jr?spm_id_from=333.999.0.0
uniCloud是uni-app的云开发库,是 DCloud 联合阿里云、腾讯云,为开发者提供的基于 serverless 模式和 js 编程的云开发平台。
uniCloud基本抹平了不同云厂商的差异,如果你熟悉mongoDB,那么就很容易上手了!
现在用uniCloud可以大大的提高开发的效率,而且可以降低运维方面的成本,因为现在serverless还处于免费阶段。
当然也有很多的缺点,新手上手的话不是很快,很多东西也不支持,例如删除数据,竟然还要去调api。
最近小孟和老王研究了下,感觉还是可以搞的,于是就测试并发布了整个通用的版本,发布到了抖音,这个大家可以搞一下,抖音的流量你懂的,但是我们现在对赚钱不感兴趣。所以有熊伙伴想搞的,可以拿去源码学习,但是不要商用和贩卖!
<template>
<view class="center">
<view class="userInfo" @click.capture="toUserInfo">
<uni-file-picker v-if="userInfo.avatar_file" v-model="userInfo.avatar_file"
fileMediatype="image" :del-icon="false" return-type="object" :image-styles="listStyles" disablePreview
disabled />
<image v-else class="logo-img" src="/static/uni-center/defaultAvatarUrl.png"></image>
<view class="logo-title">
<text class="uer-name">{{userInfo.nickname||userInfo.username||userInfo.mobile||'未登录'}}</text>
</view>
</view>
<uni-list class="center-list" v-for="(sublist , index) in ucenterList" :key="index">
<uni-list-item v-for="(item,i) in sublist" :title="item.title" link :rightText="item.rightText" :key="i"
:clickable="true" :to="item.to" @click="ucenterListClick(item)" :show-extra-icon="true"
:extraIcon="{type:item.icon,color:'#999'}">
<view v-if="item.showBadge" class="item-footer" slot="footer">
<text class="item-footer-text">{{item.rightText}}</text>
<view class="item-footer-badge"></view>
</view>
</uni-list-item>
</uni-list>
</view>
</template>
<script>
import {
mapGetters,
mapMutations
} from 'vuex';
import checkUpdate from '@/uni_modules/uni-upgrade-center-app/utils/check-update';
import callCheckVersion from '@/uni_modules/uni-upgrade-center-app/utils/call-check-version';
import uniShare from 'uni_modules/uni-share/js_sdk/uni-share.js';
const db = uniCloud.database();
export default {
data() {
return {
ucenterList: [
[{
"title": '问题与反馈',
"to": '/uni_modules/uni-feedback/pages/uni-feedback/uni-feedback',
"icon": "help"
}, {
"title": '设置',
"to": '/pages/ucenter/settings/settings',
"icon": "gear"
}],
[{
"title": '关于',
"to": '/pages/ucenter/about/about',
"icon": "info"
}]
],
listStyles: {
"height": "150rpx", // 边框高度
"width": "150rpx", // 边框宽度
"border": { // 如果为 Boolean 值,可以控制边框显示与否
"color": "#eee", // 边框颜色
"width": "1px", // 边框宽度
"style": "solid", // 边框样式
"radius": "100%" // 边框圆角,支持百分比
}
}
}
},
onLoad() {
//#ifdef APP-PLUS
this.ucenterList[this.ucenterList.length - 2].unshift({
title: '检查更新',
rightText: this.appVersion.version + '-' + this.appVersion.versionCode,
event: 'checkVersion',
icon: 'loop',
showBadge: this.appVersion.hasNew
})
//#endif
},
computed: {
...mapGetters({
userInfo: 'user/info',
login: 'user/hasLogin'
})
// #ifdef APP-PLUS
,
appVersion() {
return getApp().appVersion
}
// #endif
,
appConfig() {
return getApp().globalData.config
}
},
methods: {
...mapMutations({
setUserInfo: 'user/login'
}),
toSettings() {
uni.navigateTo({
url: "/pages/ucenter/settings/settings"
})
},
/**
* 个人中心项目列表点击事件
*/
ucenterListClick(item) {
if (!item.to && item.event) {
this[item.event]();
}
},
async checkVersion() {
let res = await callCheckVersion()
console.log(res);
if (res.result.code > 0) {
checkUpdate()
} else {
uni.showToast({
title: res.result.message,
icon: 'none'
});
}
},
toUserInfo() {
uni.navigateTo({
url: '/pages/ucenter/userinfo/userinfo'
})
},
/**
* 去应用市场评分
*/
gotoMarket() {
// #ifdef APP-PLUS
if (uni.getSystemInfoSync().platform == "ios") {
// 这里填写appstore应用id
let appstoreid = this.appConfig.marketId.ios; // 'id1417078253';
plus.runtime.openURL("itms-apps://" + 'itunes.apple.com/cn/app/wechat/' + appstoreid + '?mt=8');
}
if (uni.getSystemInfoSync().platform == "android") {
var Uri = plus.android.importClass("android.net.Uri");
var uri = Uri.parse("market://details?id=" + this.appConfig.marketId.android);
var Intent = plus.android.importClass('android.content.Intent');
var intent = new Intent(Intent.ACTION_VIEW, uri);
var main = plus.android.runtimeMainActivity();
main.startActivity(intent);
}
// #endif
},
async share() {
let {result} = await uniCloud.callFunction({
name: 'uni-id-cf',
data: {
action: 'getUserInviteCode'
}
})
console.log(result);
let myInviteCode = result.myInviteCode || result.userInfo.my_invite_code
console.log(myInviteCode);
let {
appName,
logo,
company,
slogan
} = this.appConfig.about
// #ifdef APP-PLUS
uniShare({
content: { //公共的分享类型(type)、链接(herf)、标题(title)、summary(描述)、imageUrl(缩略图)
type: 0,
href: this.appConfig.h5.url +
`/#/pages/ucenter/invite/invite?code=${myInviteCode}`,
title: appName,
summary: slogan,
imageUrl: logo + '?x-oss-process=image/resize,m_fill,h_100,w_100' //压缩图片解决,在ios端分享图过大导致的图片失效问题
},
menus: [{
"img": "/static/app-plus/sharemenu/wechatfriend.png",
"text": "微信好友",
"share": {
"provider": "weixin",
"scene": "WXSceneSession"
}
},
{
"img": "/static/app-plus/sharemenu/wechatmoments.png",
"text": "",
"share": {
"provider": "weixin",
"scene": "WXSenceTimeline"
}
},
{
"img": "/static/app-plus/sharemenu/weibo.png",
"text": "微博",
"share": {
"provider": "sinaweibo"
}
},
{
"img": "/static/app-plus/sharemenu/qq.png",
"text": "QQ",
"share": {
"provider": "qq"
}
},
{
"img": "/static/app-plus/sharemenu/copyurl.png",
"text": "复制",
"share": "copyurl"
},
{
"img": "/static/app-plus/sharemenu/more.png",
"text": "更多",
"share": "shareSystem"
}
],
cancelText: "取消分享",
}, e => { //callback
console.log(e);
})
// #endif
}
}
}
</script>
<style>
/* #ifndef APP-PLUS-NVUE */
page {
background-color: #f8f8f8;
}
/* #endif*/
.center {
flex: 1;
flex-direction: column;
background-color: #f8f8f8;
}
.userInfo {
width: 750rpx;
padding: 20rpx;
padding-top: 50px;
background-image: url(../../static/uni-center/headers.png);
flex-direction: column;
align-items: center;
}
.logo-img {
width: 150rpx;
height: 150rpx;
border-radius: 150rpx;
}
.logo-title {
flex: 1;
align-items: center;
justify-content: space-between;
flex-direction: row;
}
.uer-name {
height: 100rpx;
line-height: 100rpx;
font-size: 38rpx;
color: #FFFFFF;
}
.center-list {
margin-bottom: 30rpx;
background-color: #f9f9f9;
}
.center-list-cell {
width: 750rpx;
background-color: #007AFF;
height: 40rpx;
}
.grid {
background-color: #FFFFFF;
margin-bottom: 6px;
}
.uni-grid .text {
font-size: 30rpx;
height: 25px;
line-height: 25px;
color: #817f82;
}
.uni-grid .item /deep/ .uni-grid-item__box {
justify-content: center;
align-items: center;
}
/*修改边线粗细示例*/
/* #ifndef APP-NVUE */
.center-list /deep/ .uni-list--border:after {
-webkit-transform: scaleY(0.2);
transform: scaleY(0.2);
margin-left: 80rpx;
}
.center-list /deep/ .uni-list--border-top,
.center-list /deep/ .uni-list--border-bottom {
display: none;
}
/* #endif */
.item-footer {
flex-direction: row;
align-items: center;
}
.item-footer-text {
color: #999;
font-size: 24rpx;
padding-right: 10rpx;
}
.item-footer-badge {
width: 20rpx;
height: 20rpx;
/* #ifndef APP-NVUE */
border-radius: 50%;
/* #endif */
/* #ifdef APP-NVUE */
border-radius: 10rpx;
/* #endif */
background-color: #DD524D;
}
</style>
<script>
import uQRCode from './uqrcode.js'
export default {
props: {
cid: {
type: String,
default(){
return Date.now()+Math.random()+'';
}
},
text: {
type: String,
required: true
},
size: {
type: Number,
default: uni.upx2px(200)
},
margin: {
type: Number,
default: 0
},
backgroundColor: {
type: String,
default: '#ffffff'
},
foregroundColor: {
type: String,
default: '#000000'
},
backgroundImage: {
type: String
},
logo: {
type: String
},
makeOnLoad: {
type: Boolean,
default: false
}
},
data() {
return {
}
},
mounted() {
if (this.makeOnLoad) {
this.make()
}
},
methods: {
async make() {
var options = {
canvasId: this.cid,
componentInstance: this,
text: this.text,
size: this.size,
margin: this.margin,
backgroundColor: this.backgroundImage ? 'rgba(255,255,255,0)' : this.backgroundColor,
foregroundColor: this.foregroundColor
}
var filePath = await this.makeSync(options)
if (this.backgroundImage) {
filePath = await this.drawBackgroundImageSync(filePath)
}
if (this.logo) {
filePath = await this.drawLogoSync(filePath)
}
this.makeComplete(filePath)
},
makeComplete(filePath) {
this.$emit('makeComplete', filePath)
},
drawBackgroundImage(options) {
var ctx = uni.createCanvasContext(this.cid, this)
ctx.drawImage(this.backgroundImage, 0, 0, this.size, this.size)
ctx.drawImage(options.filePath, 0, 0, this.size, this.size)
ctx.draw(false, () => {
uni.canvasToTempFilePath({
canvasId: this.cid,
success: res => {
options.success && options.success(res.tempFilePath)
},
fail: error => {
options.fail && options.fail(error)
}
}, this)
})
},
async drawBackgroundImageSync(filePath) {
return new Promise((resolve, reject) => {
this.drawBackgroundImage({
filePath: filePath,
success: res => {
resolve(res)
},
fail: error => {
reject(error)
}
})
})
},
fillRoundRect(ctx, r, x, y, w, h) {
ctx.save()
ctx.translate(x, y)
ctx.beginPath()
ctx.arc(w - r, h - r, r, 0, Math.PI / 2)
ctx.lineTo(r, h)
ctx.arc(r, h - r, r, Math.PI / 2, Math.PI)
ctx.lineTo(0, r)
ctx.arc(r, r, r, Math.PI, Math.PI * 3 / 2)
ctx.lineTo(w - r, 0)
ctx.arc(w - r, r, r, Math.PI * 3 / 2, Math.PI * 2)
ctx.lineTo(w, h - r)
ctx.closePath()
ctx.setFillStyle('#ffffff')
ctx.fill()
ctx.restore()
},
drawLogo(options) {
var ctx = uni.createCanvasContext(this.cid, this)
ctx.drawImage(options.filePath, 0, 0, this.size, this.size)
var logoSize = this.size / 4
var logoX = this.size / 2 - logoSize / 2
var logoY = logoX
var borderSize = logoSize + 10
var borderX = this.size / 2 - borderSize / 2
var borderY = borderX
var borderRadius = 5
this.fillRoundRect(ctx, borderRadius, borderX, borderY, borderSize, borderSize)
ctx.drawImage(this.logo, logoX, logoY, logoSize, logoSize)
ctx.draw(false, () => {
uni.canvasToTempFilePath({
canvasId: this.cid,
success: res => {
options.success && options.success(res.tempFilePath)
},
fail: error => {
options.fail && options.fail(error)
}
}, this)
})
},
async drawLogoSync(filePath) {
return new Promise((resolve, reject) => {
this.drawLogo({
filePath: filePath,
success: res => {
resolve(res)
},
fail: error => {
reject(error)
}
})
})
},
async makeSync(options) {
return new Promise((resolve, reject) => {
uQRCode.make({
canvasId: options.canvasId,
componentInstance: options.componentInstance,
text: options.text,
size: options.size,
margin: options.margin,
backgroundColor: options.backgroundColor,
foregroundColor: options.foregroundColor,
success: res => {
resolve(res)
},
fail: error => {
reject(error)
}
})
})
}
}
}
</script>
这个系统小孟也开发了很久,有小伙伴说需要学习,狠狠心,给大家开源了,拿去学习吧,下面的图片,输入:unicloud
对于程序开发这块,需要不断的练习,不断的改bug,才能成长,遇到bug别慌,因为以后有改不完的bug!