最近研究了uniCloud,并用uniCloud开发了一个性格测试小程序,已经发布到服务器,完美的发布到抖音,在抖音可以搜索到该小程序。
源码和视频教程都开源给大家了。小孟已经发布到抖音,全部的已经跑通,所以小伙伴可以拿去学习,没有任何的问题。
也出了详细的教程了!
视频的教程放在b站了,希望下坡伙伴,给个三连:
https://www.bilibili.com/video/BV19u411z7Jr?spm_id_from=333.999.0.0
一,什么是uniCloud:
uniCloud是uni-app的云开发库,是 DCloud 联合阿里云、腾讯云,为开发者提供的基于 serverless 模式和 js 编程的云开发平台。
uniCloud基本抹平了不同云厂商的差异,如果你熟悉mongoDB,那么就很容易上手了!
现在用uniCloud可以大大的提高开发的效率,而且可以降低运维方面的成本,因为现在serverless还处于免费阶段。
当然也有很多的缺点,新手上手的话不是很快,很多东西也不支持,例如删除数据,竟然还要去调api。
最近小孟和老王研究了下,感觉还是可以搞的,于是就测试并发布了整个通用的版本,发布到了抖音,这个大家可以搞一下,抖音的流量你懂的,但是我们现在对赚钱不感兴趣。所以有熊伙伴想搞的,可以拿去源码学习,但是不要商用和贩卖!
二,系统界面截图:
三,核心代码演示:
- <template>
- <view class=&#34;center&#34;>
- <view class=&#34;userInfo&#34; @click.capture=&#34;toUserInfo&#34;>
- <uni-file-picker v-if=&#34;userInfo.avatar_file&#34; v-model=&#34;userInfo.avatar_file&#34;
- fileMediatype=&#34;image&#34; :del-icon=&#34;false&#34; return-type=&#34;object&#34; :image-styles=&#34;listStyles&#34; disablePreview
- disabled />
- <image v-else class=&#34;logo-img&#34; src=&#34;/static/uni-center/defaultAvatarUrl.png&#34;></image>
- <view class=&#34;logo-title&#34;>
- <text class=&#34;uer-name&#34;>{{userInfo.nickname||userInfo.username||userInfo.mobile||&#39;未登录&#39;}}</text>
- </view>
- </view>
- <uni-list class=&#34;center-list&#34; v-for=&#34;(sublist , index) in ucenterList&#34; :key=&#34;index&#34;>
- <uni-list-item v-for=&#34;(item,i) in sublist&#34; :title=&#34;item.title&#34; link :rightText=&#34;item.rightText&#34; :key=&#34;i&#34;
- :clickable=&#34;true&#34; :to=&#34;item.to&#34; @click=&#34;ucenterListClick(item)&#34; :show-extra-icon=&#34;true&#34;
- :extraIcon=&#34;{type:item.icon,color:&#39;#999&#39;}&#34;>
- <view v-if=&#34;item.showBadge&#34; class=&#34;item-footer&#34; slot=&#34;footer&#34;>
- <text class=&#34;item-footer-text&#34;>{{item.rightText}}</text>
- <view class=&#34;item-footer-badge&#34;></view>
- </view>
- </uni-list-item>
- </uni-list>
- </view>
- </template>
- <script>
- import {
- mapGetters,
- mapMutations
- } from &#39;vuex&#39;;
- import checkUpdate from &#39;@/uni_modules/uni-upgrade-center-app/utils/check-update&#39;;
- import callCheckVersion from &#39;@/uni_modules/uni-upgrade-center-app/utils/call-check-version&#39;;
- import uniShare from &#39;uni_modules/uni-share/js_sdk/uni-share.js&#39;;
- const db = uniCloud.database();
- export default {
- data() {
- return {
- ucenterList: [
- [{
- &#34;title&#34;: &#39;问题与反馈&#39;,
- &#34;to&#34;: &#39;/uni_modules/uni-feedback/pages/uni-feedback/uni-feedback&#39;,
- &#34;icon&#34;: &#34;help&#34;
- }, {
- &#34;title&#34;: &#39;设置&#39;,
- &#34;to&#34;: &#39;/pages/ucenter/settings/settings&#39;,
- &#34;icon&#34;: &#34;gear&#34;
- }],
- [{
- &#34;title&#34;: &#39;关于&#39;,
- &#34;to&#34;: &#39;/pages/ucenter/about/about&#39;,
- &#34;icon&#34;: &#34;info&#34;
- }]
- ],
- listStyles: {
- &#34;height&#34;: &#34;150rpx&#34;, // 边框高度
- &#34;width&#34;: &#34;150rpx&#34;, // 边框宽度
- &#34;border&#34;: { // 如果为 Boolean 值,可以控制边框显示与否
- &#34;color&#34;: &#34;#eee&#34;, // 边框颜色
- &#34;width&#34;: &#34;1px&#34;, // 边框宽度
- &#34;style&#34;: &#34;solid&#34;, // 边框样式
- &#34;radius&#34;: &#34;100%&#34; // 边框圆角,支持百分比
- }
- }
- }
- },
- onLoad() {
- //#ifdef APP-PLUS
- this.ucenterList[this.ucenterList.length - 2].unshift({
- title: &#39;检查更新&#39;,
- rightText: this.appVersion.version + &#39;-&#39; + this.appVersion.versionCode,
- event: &#39;checkVersion&#39;,
- icon: &#39;loop&#39;,
- showBadge: this.appVersion.hasNew
- })
- //#endif
- },
- computed: {
- ...mapGetters({
- userInfo: &#39;user/info&#39;,
- login: &#39;user/hasLogin&#39;
- })
- // #ifdef APP-PLUS
- ,
- appVersion() {
- return getApp().appVersion
- }
- // #endif
- ,
- appConfig() {
- return getApp().globalData.config
- }
- },
- methods: {
- ...mapMutations({
- setUserInfo: &#39;user/login&#39;
- }),
- toSettings() {
- uni.navigateTo({
- url: &#34;/pages/ucenter/settings/settings&#34;
- })
- },
- /**
- * 个人中心项目列表点击事件
- */
- 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: &#39;none&#39;
- });
- }
- },
- toUserInfo() {
- uni.navigateTo({
- url: &#39;/pages/ucenter/userinfo/userinfo&#39;
- })
- },
- /**
- * 去应用市场评分
- */
- gotoMarket() {
- // #ifdef APP-PLUS
- if (uni.getSystemInfoSync().platform == &#34;ios&#34;) {
- // 这里填写appstore应用id
- let appstoreid = this.appConfig.marketId.ios; // &#39;id1417078253&#39;;
- plus.runtime.openURL(&#34;itms-apps://&#34; + &#39;itunes.apple.com/cn/app/wechat/&#39; + appstoreid + &#39;?mt=8&#39;);
- }
- if (uni.getSystemInfoSync().platform == &#34;android&#34;) {
- var Uri = plus.android.importClass(&#34;android.net.Uri&#34;);
- var uri = Uri.parse(&#34;market://details?id=&#34; + this.appConfig.marketId.android);
- var Intent = plus.android.importClass(&#39;android.content.Intent&#39;);
- 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: &#39;uni-id-cf&#39;,
- data: {
- action: &#39;getUserInviteCode&#39;
- }
- })
- 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 + &#39;?x-oss-process=image/resize,m_fill,h_100,w_100&#39; //压缩图片解决,在ios端分享图过大导致的图片失效问题
- },
- menus: [{
- &#34;img&#34;: &#34;/static/app-plus/sharemenu/wechatfriend.png&#34;,
- &#34;text&#34;: &#34;微信好友&#34;,
- &#34;share&#34;: {
- &#34;provider&#34;: &#34;weixin&#34;,
- &#34;scene&#34;: &#34;WXSceneSession&#34;
- }
- },
- {
- &#34;img&#34;: &#34;/static/app-plus/sharemenu/wechatmoments.png&#34;,
- &#34;text&#34;: &#34;&#34;,
- &#34;share&#34;: {
- &#34;provider&#34;: &#34;weixin&#34;,
- &#34;scene&#34;: &#34;WXSenceTimeline&#34;
- }
- },
- {
- &#34;img&#34;: &#34;/static/app-plus/sharemenu/weibo.png&#34;,
- &#34;text&#34;: &#34;微博&#34;,
- &#34;share&#34;: {
- &#34;provider&#34;: &#34;sinaweibo&#34;
- }
- },
- {
- &#34;img&#34;: &#34;/static/app-plus/sharemenu/qq.png&#34;,
- &#34;text&#34;: &#34;QQ&#34;,
- &#34;share&#34;: {
- &#34;provider&#34;: &#34;qq&#34;
- }
- },
- {
- &#34;img&#34;: &#34;/static/app-plus/sharemenu/copyurl.png&#34;,
- &#34;text&#34;: &#34;复制&#34;,
- &#34;share&#34;: &#34;copyurl&#34;
- },
- {
- &#34;img&#34;: &#34;/static/app-plus/sharemenu/more.png&#34;,
- &#34;text&#34;: &#34;更多&#34;,
- &#34;share&#34;: &#34;shareSystem&#34;
- }
- ],
- cancelText: &#34;取消分享&#34;,
- }, 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 &#39;./uqrcode.js&#39;
- export default {
- props: {
- cid: {
- type: String,
- default(){
- return Date.now()+Math.random()+&#39;&#39;;
- }
- },
- text: {
- type: String,
- required: true
- },
- size: {
- type: Number,
- default: uni.upx2px(200)
- },
- margin: {
- type: Number,
- default: 0
- },
- backgroundColor: {
- type: String,
- default: &#39;#ffffff&#39;
- },
- foregroundColor: {
- type: String,
- default: &#39;#000000&#39;
- },
- 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 ? &#39;rgba(255,255,255,0)&#39; : 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(&#39;makeComplete&#39;, 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(&#39;#ffffff&#39;)
- 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>
复制代码 四,代码获取:
这个系统小孟也开发了很久,有小伙伴说需要学习,狠狠心,给大家开源了,拿去学习吧,:
我把小程序发布到抖音啦!【开源了】对于程序开发这块,需要不断的练习,不断的改bug,才能成长,遇到bug别慌,因为以后有改不完的bug! |