一、基本介绍
use strict
在JS中,'use strict'
特殊的字符串字面量,通知JS引擎以“严格模式”执行代码。避免一些常见的错误和不安全的实践。建议在云函数的代码中使用'use strict'
来启用严格模式。
二、云函数
基础使用
const db = uniCloud.database()
exports.main = async (event, context) => {
...
}
uniCloud.callFunction({
name : "云对象文件夹名",
data,
}).then(res=>{
...
})
添加云函数
const db = uniCloud.database()
exports.main = async (event, context) => {
db.collection('user').add({
joinTime: new Date(),
...event
})
}
uniCloud.callFunction({
name : "cloudFun1",
data:{num: 2}
}).then(res=>{
...
})
删除云函数
注意:删除、set等操作,一定要写好条件,在做相关功能阶段可以备份好数据库
const db = uniCloud.database()
exports.main = async (event, context) => {
let {id} = event
return await db.collection("article").doc(id).remove()
}
修改云函数
注:某种情况下也可使用【添加云函数】进行覆盖,来达到修改的目的
db.collection( "xxx" ).doc(xxx).update({
...data
})
获取列表数据云函数
- 限制数据条数(条数、页数、拼接、加载、刷新)
- 开始,根据后端固定的条数,刷新后,后端获取数据为,忽略前端已有数据条数之后的固定条数
前端:
listArr:[]
uniCloud.callFunction({
name: "xxx",
data:{ skip:this.listArr.length }
}).then( res=> {
let oldList = this.listArr;
let newList=[ ...oldList, ...res.result.data];
this.listArr= newList
})
后端:
let { skip=0 } = e
db.collection( "xxx" ).limit(10).skip(skip).get();
三、云对象
相对云函数更加简洁
使用场景
云函数是一种在云端运行的 JS函数,可以执行一些特定的业务逻辑
云对象是一种数据存储服务,类似于数据库中的一张表,可以存储结构化的数据
- 云函数主要用于执行一些特定的业务逻辑,比如处理用户请求、调用第三方 API、生成临时文件等。由于其运行在云端,可以避免在客户端进行敏感操作或数据存储,保证了数据的安全性和隐私性
- 云对象主要用于存储和查询结构化的数据,类似于数据库中的一张表。你可以使用云对象来存储用户信息、订单数据、商品信息等,并通过定义的字段进行查询、更新和删除等操作
进行数据处理和存储,云对象合适;执行一些特定的业务逻辑,云函数合适
基础使用
- 定义
const db = uniCloud.database();
module.exports = {
// 通用预处理器,默认即可
_before : function (){ ... },
// 自定义方法
async get(){
return await db.collection("数据表名").limit(num).get();
},
add: async()=>{
return await db.collection("数据表名").add(params).get();
}
}
- 使用
// vue顶部引入
const cloudObjFun = uniCloud.importObject("云对象文件夹名")
// 使用
cloudObjFun.get(2).then(res=>{ ... })
cloudObjFun.add({userId:'01'}).then(res=>{ ... })
浏览量自增封装
由于前端数据库组件不能使用【inc】方法,所以采用云对象的方式来做
const db = uniCloud.database();
const dbCmd = db.command;
module.exports = {
// 通用预处理器
_before: function (){},
/**
*自定义增减
*@param {Object] table 数据表
*@param {object} attr 属性
*@param {object} id
*@param {object] num 自增减数
*/
async operation(table, attr, id, num){
let obj = {}
obj[attr] = dbCmd.inc(num);
return await db.collection(table).doc(id).update(obj)
}
}
四、DB Schema
介绍:在客户端前端代码直接操作数据库
使用:在uniCloud-database下新建【xxx.schema.json】文件,或者从云端下载同步到本地。之后修改代码以获取对应的权限,在本地编辑测试完之后,同步到云端
{
"bsonType" : "object",
// 必填项
"required": ["title"],
// 权限
"permission": {
// 开启【读】权限
"read" : true,
"create": false,
"update": false,
"delete": false
},
// 表结构
"properties": {
"_id": { "description":“ID,系统自动生成" },
// 自定义属性名
"title": {
"bsonType" : "stying",
"title" : "标题",
"drscription" : "描述",
"errorMessage" : "错误提示"
},
"createTime" : {...},
...
}
}
const db = uniCloud.database()
export default{
onload(){
db.collection("数据表名").get.then(res=>{ ... })
}
}
表关联关系
uniCloud–database下【自定义表】的用户id关联【uni-id-user】表的用户id
xxx.schame.json
{
...
"propertise":{
"userid" :{
"bsonType" : "string",
"title":“用户id",
"foreignKey" : "uni-id-users._id" ,
"defaultValue" :{
"$env" : "uid"
}
},
}
}
权限限制
未登录的用户不能创建信息
auth.uid为官方提供的【当前登录用户的id】
{
...
"permission" : {
"read" : true,
"create" : "auth.uid != null", // 判断用户是否登录
"update": "doc.userid == auth.uid", // 判断所修改数据的用户id是否是当前用户的id
"delete" : false
},
}
五、JQL语法
-
sql:有学习成本
select * from table1 where field1="value1"
-
nosql:连表查询比sql还要复杂
const db = uniCloud.database() let res = await db.collection('table').where({ field1 : value1 }).get(0)
-
jql:更加贴近js写法、学习成本低、代码简短
连表查询
前提:建立枢纽、开启权限(看DB Schame案例)
let artTemp=db.collection ( "cloudDemo").field("title, content , userid").getTemp()
let userTemp=db.collection("uni-id-users").field("_id,username,nickname" ).getTemp()
db.collection(artTemp, userTemp).get().then(res=>{
console.log(res);
})
前端组件方式
连表查询:collection=“主表,副表”
过滤写法1【语法简介】:field=“posttime,userid{avatar}”,主表posttime,userid,副表avatar
过滤写法2【官方推荐】:field=“posttime,userid.avatar”
排序:orderby=“posttime desc, userid desc”,根据时间排序,时间一样则根据id排序
<unicloud-db
v-slot:default= "{data, loading, error, options}"
collection="cloudDemo, uni-id-users"
field="posttime,userid{avatar}"
orderby="posttime desc, userid desc"
>
<view v-if="error ">{error.message}}</view>
<view v-else-if="loading"><uni-load-more status="loading"></uni-load-more></view>
<view v-else>
<uni-list>
<uni-list-item
v-for="item in data"
:thumb="item.avatar"
></uni-list-item>
</ uni-list>
</view>
</ unicloud-db>
####五 、云数据库
六、云存储
阿里云:
七、打包
- 本地云函数上传
- 进入manifest.json修改对应的配置
-
H5打包
-
manifest.json
- 标题(自填)
- 路由模式【hash(默认)、history(需要另外配置)】
- 运行的基础路径【./】
-
发行:网站PC
- 网站标题(自填)
- 域名(默认空)
- 打包完成:unpackage/dist/build/h5
-
获取域名:https://unicloud.dcloud.net.cn
- 前端页面托管
- 文件管理–上传到当前目录–上传文件夹(含根目录)
- 参数配置–默认域名
- 跨域配置–添加域名
-
跨域:https://unicloud.dcloud.net.cn
- 跨域配置–添加域名
-
域名丑
- 配置自己的域名
- 阿里云等购买主机域名(chenjigang.com)
- https://unicloud.dcloud.net.cn
- 前端网页托管–参数配置–配置网站域名
- 域名:自定义二级域名.购买的域名【https://xxx.chenjigang.com】
- CNAME:复制到阿里云
- 阿里云:
- 域名控制台–域名列表–解析–解析设置–添加记录
- 主机记录:自定义二级域名
- 记录值:填写unicloud的CNAME
- 域名控制台–域名列表–解析–解析设置–添加记录
- 配置跨域
- 域名转二维码
- 百度短连接
- 配置自己的域名
-
vscode本地运行
-
安装【Live Serve】插件
-
运行index.html
-
-
-
微信小程序打包
- manifest.json
- 小程序管理后台:https://mp.weixin.qq.com/wxamp/devprofile/get_profile
- 开发–开发管理–开发设置–获取AppID填写到 manifest.json
- 点击发行:微信小程序
- 填写项目名称和AppID
- 点击发行
- 打包完成:unpackage/dist/dev/mp-weixin
- 微信开发者工具
- 本地设置
- 关闭不校验合法语名
- 根据报错提示,复制不合法域名以及类型(request、socket等)
- 小程序管理后台:https://mp.weixin.qq.com/wxamp/devprofile/get_profile
- 开发–开发管理–服务器域名–合法域名–多个域名用【;】分隔
- 本地设置
- manifest.json
-
app
- manifest.json
- 上传图标
- 自动生成图标并替换
- 点击发行:App云打包(较简单)
- 使用云端证书
- 点击打包
- 打包完成:unpackage/release/apk
- manifest.json
-
…
八、常用方法
触底加载
触底方法:【scroll-view】标签的触底、页面触底等
技巧:通过过滤前端已有的数组长度
uniCloud.cal1Function({
name : "getData",
data:{
skip: this.listArr.length
}
}).then(res=>{
this.listArr = [...this.listArr, ...res.result.data]
})
limit:请求条数,skip:过滤条数,orderBy:排序
const db=uniCloud.database();
exports.main = async (event, context) =>{
let { skip=0 } = event;
return await db.collection ("article")
.limit(8)
.skip(skip)
.orderBy("posttime", "desc")
.get();
};
下来刷新
列表清空、重新获取
事件委托
原生的 JavaScript 来实现事件委托。允许你将事件监听器添加到父元素,而不是分别添加到每个子元素。当事件在子元素上触发时,事件会冒泡到父元素,通过检查事件的 target
属性来确定是哪个子元素触发了事件
<template>
<div @click="handleClick">
<button data-action="action1">Action 1</button>
<button data-action="action2">Action 2</button>
</div>
</template>
<script>
export default {
methods: {
handleClick(e) {
const target = e.target;
if (target.tagName === 'BUTTON') {
const action = target.dataset.action;
this[action]();
}
},
action1() { console.log(1) },
action2() { console.log(2) }
},
};
</script>
高德获取定位封装:获取省市位置信息
官网:https://lbs.amap.com/api/webservice/summar
export function getprovince(){
return new Promise((resolve,reject)=>{
uni.request({
url: "https://restapi.amap.com/v3/ip?key=xxx",
success: res=>{ resolve(res.data.province) },
fail: err=>{ reject(err) }
})
})
}
九、问题解决
Invalid uni-id config file
官网:https://doc.dcloud.net.cn/uniCloud/uni-id/summary.html#config
缺少uni-id-pages的配置文件【config.json】,在uniCloud中手动创建相关路径和文件
uni-id的云端配置文件在:uniCloud/cloudfunctions/ common/uni-config-center/uni-id/config.json
{
"passwordSecret": [
{
"type": "hmac-sha256",
"version": 1
}
],
"passwordStrength": "medium",
"tokenSecret": "",
"requestAuthSecret": "",
"tokenExpiresIn": 7200,
"tokenExpiresThreshold": 3600,
"maxTokenLength": 10,
"passwordErrorLimit": 6,
"passwordErrorRetryTime": 3600,
"autoSetInviteCode": false,
"forceInviteCode": false,
"idCardCertifyLimit": 1,
"realNameCertifyLimit": 5,
"sensitiveInfoEncryptSecret": "",
"frvNeedAlivePhoto": false,
"userRegisterDefaultRole": [],
"app": {
"tokenExpiresIn": 2592000,
"tokenExpiresThreshold": 864000,
"oauth": {
"weixin": {
"appid": "",
"appsecret": ""
},
"qq": {
"appid": "",
"appsecret": ""
},
"apple": {
"bundleId": ""
}
}
},
"web": {
"tokenExpiresIn": 7200,
"tokenExpiresThreshold": 3600,
"oauth": {
"weixin-h5": {
"appid": "",
"appsecret": ""
},
"weixin-web": {
"appid": "",
"appsecret": ""
}
}
},
"mp-weixin": {
"tokenExpiresIn": 259200,
"tokenExpiresThreshold": 86400,
"oauth": {
"weixin": {
"appid": "",
"appsecret": ""
}
}
},
"mp-qq": {
"tokenExpiresIn": 259200,
"tokenExpiresThreshold": 86400,
"oauth": {
"qq": {
"appid": "",
"appsecret": ""
}
}
},
"mp-alipay": {
"tokenExpiresIn": 259200,
"tokenExpiresThreshold": 86400,
"oauth": {
"alipay": {
"appid": "",
"privateKey": "",
"keyType": "PKCS8"
}
}
},
"service": {
"sms": {
"name": "",
"codeExpiresIn": 180,
"smsKey": "",
"smsSecret": "",
"scene": {
"bind-mobile-by-sms": {
"templateId": "",
"codeExpiresIn": 240
}
}
},
"univerify": {
"appid": "",
"apiKey": "",
"apiSecret": ""
}
}
}
十、其他信息
-
项目上线,使用本地云函数调试即可。使用远程的话,其他用户可能会出现问题,待测试完,再上传到远端
-
通过【for…in】遍历对象的属性,【obj[key]】访问对象属性的值,来判断按钮的禁用状态
-
日期格式化:采用uni扩展组件【uni-dateformat】
-
做数据处理的时候,避免乐观形式,要做好各种数据状态的处理
-
封装常用提示、跳转等
-
阿里图标库一个项目尽量使用同一人分享的,这样大小会相对统一一些
-
选择性的做二次校验(比较敏感的属性)
-
UView有富文本解析器组件
-
阿里iconfont的Font class使用,需要将相对引用改为绝对引用
-
uniapp使用uView
-
插件市场下载
-
main.js中引入
import uView from '@/uni_modules/uview-ui' Vue.use(uView)
-
App.vue中引入
@import "@/uni_modules/uni-scss/index.scss";
-
uni.sass中引入
@import '@/uni_modules/uview-ui/theme.scss';
-
-
父子传值-自定义事件-简写【.syan】
// 父组件 <child :data.syan="data"></child>
// 子组件 <view @click="change">{{data}}</view> props:{ data:{ default:'', type:String } } methods:{ change(){ this.$emit('update:data',"uni-app") } }
-
父组件点击子组件事件【.native】
引入的子组件,原生绑定的事件不能使用,需要添加【.native】
//父组件 <componentA @click.native="change"></componentA>
-
页面跳转查看详情
-
方式一:传id【item.id】
item不含所有内容
-
方式二:传JSON字符串【JSON.string(item)】
item含有跳转页面所有内容,并且内容不能太多【内容过多可能会传递失败】
-
方式三:缓存
退出时记得清缓存
-
-
Vue2在模板中使用导入的方法
类似于组件注册
{{giveName(item)}} import {giveName} from'xxx' methods:{ giveName }
-
CSS根据头像设置专属背景
filter: blur(20px) // 模糊 transform: scale(2) // 放大 opacity: 0.5 // 透明
-
JS新语法【?.】和【??】,【??】和【||】
const obj = { a: 1 } 访问【obj.b】会返回undefined,访问【obj.b.c】会报错 使用【obj.b?.c】会判断【b】是否存在,存在则访问c 使用【obj.b ?? 'default'】会判断【b】是否为【null】【undefined】,是的话使用一个值替代【obj.b】 相比较【obj.b && obj.b.c】简洁很多
【??】:当变量的值为 null 或 undefined ,为变量提供一个默认值 【||】:当变量的值为“falsy”(例如 0, '', NaN, false),为变量提供一个默认值。 const value = 0 || 'default'; 这里 value 会是 'default',即使 0 是一个有效的数值。
-
在uniapp中存在CSS变量,提供了系统状态栏高度
官网:http://uniapp.dcloud.net.cn/tutorial/syntax-css.html
-
–status-bar-height :系统状态栏高度
-
–window-top:内容区域距离顶部的距离
-
–window-bottom:内容区域距离底部的距离(tabbar)
padding-top: var( --status-bar-height) min-height: calc(100vh - var( --window-top)) padding-top: var(--window-bottom)
-
-
vue阻止【事件冒泡stop】+【事件捕获prevent】
<button @click.stop.prevent>
-
white-space: nowrap(不换行)
.text-overflow { white-space: nowrap; /* 防止文本换行 */ overflow: hidden; /* 隐藏溢出部分 */ text-overflow: ellipsis; /* 当文本溢出时,显示省略号 */ width: 200px; /* 设置一个固定宽度 */ } .container { display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden; }
-
前后端要规定好时间日期等格式
- 获取日期:xxxx-xx-xx
// 它生成的日期字符串是基于 UTC 时间的,可能与本地时间不同 new Date().toISOString().slice(0, 10) // 通用 let today = new Date(); let year = today.getFullYear(); let month = (today.getMonth() + 1).toString().padStart(2, "0"); let day = today.getDate().toString().padStart(2, "0"); let formattedDate = `${year}-${month}-${day}`;
- 获取当前时间戳:1702430065563
// ECMAScript 5 引入的新方法,不兼容旧版本的浏览器(例如 IE8 及更早版本)。 const timestamp = new Date().getTime(); // Date 对象的标准方法,支持在所有符合 ECMAScript 标准的 JavaScript 环境中使用 const timestamp = Date.now();
- 日期格式【nnnn-yy-rr】转时间戳
let dateStr = "2023-08-01"; let parts = dateStr.split("-"); let date = new Date(parts[0], parts[1] - 1, parts[2]); let timestamp = date.getTime();
-
app端不支持【for… in】语法,some只要一个满足则返回true,every全部满足则返回true
//判断按钮是否禁用 inDisabled(obj){ /* for(let key in obj){ if( !obj[key] ){ return true; } } */ let bool = Object.keys(obj).some((key, value)=>{ return obj[key] == '' }) return bool; }
-
数据顺序
后端:通过数据库方法:db.collection( "xxx" ).orderBy("time","desc").get(); 前端:1、改变原数组:array.reverse(); 2、不改变原数组: array.slice().reverse();
-
图片上传
-
uni-file-picker组件,开启手动上传【auto-upload】,避免云存储无效占;回显:
imgValueList = [ { "name":"file.txt", "extname":"txt", "url":"https://xxxx...", // ... }, ... ] <uni-file-picker :value="imgValueList" ></uni-file-picker>
-
手写上传组件
// 用到的api uni.chooseImage() // 上传临时路径 uni.previewImage() // 预览 uniCloud.uploadFile() // 上传云存储
// 点击上传 goUpload(){ let newsArr = this.temFiles.map( async item =>{ return await this.uploadFun(item) }) Promise.all(newsArr).then( res =>{ let arr = res.map( item =>{ return item.fileID }) this.picArr = arr; }) }, uploadFun(item){ return uniCloud.uploadFile({ filePath:item.path, cloudPath:item.name }) }
-
-
uni-app和Vue的生命周期可以按照以下方式分类和排序:
一、uni-app的生命周期
- 应用生命周期:
- onLaunch:应用启动时触发,用于执行应用启动时的初始化操作。
- onShow:应用显示时触发,用于执行应用显示时的操作。
- onHide:应用隐藏时触发,用于执行应用隐藏时的操作。
- onError:应用发生错误时触发,用于处理应用错误。
- 页面生命周期:
- onLoad:页面加载时触发,用于执行页面加载时的初始化操作。
- onShow:页面显示时触发,用于执行页面显示时的操作。
- onHide:页面隐藏时触发,用于执行页面隐藏时的操作。
- onReady:页面初次渲染完成时触发,用于执行页面初次渲染完成时的操作。
二、Vue的生命周期
- 创建阶段:
- beforeCreate:实例化前,未创建 data 和 methods 之前。
- created:实例化后,已创建 data 和 methods。
- 挂载阶段:
- beforeMount:模板编译成虚拟 DOM 之前。
- mounted:模板编译成虚拟 DOM 之后,已挂载到真实 DOM 上。
- 更新阶段:
- beforeUpdate:数据更新前。
- updated:数据更新后。
- 销毁阶段:
- beforeDestroy:实例销毁之前。
- destroyed:实例销毁之后。
综合uni-app和Vue的生命周期,按照先后顺序,可以排列如下:
-
onLaunch:应用启动时触发,执行应用启动时的初始化操作。
-
beforeCreate:实例化前,未创建 data 和 methods 之前。
-
created:实例化后,已创建 data 和 methods。
-
beforeMount:模板编译成虚拟 DOM 之前。
-
mounted:模板编译成虚拟 DOM 之后,已挂载到真实 DOM 上。
-
onLoad:页面加载时触发,执行页面加载时的初始化操作。
-
beforeUpdate:数据更新前。
-
updated:数据更新后。
-
onShow:页面显示时触发,执行页面显示时的操作。
-
onHide:页面隐藏时触发,执行页面隐藏时的操作。
-
onReady:页面初次渲染完成时触发,执行页面初次渲染完成时的操作。
-
beforeDestroy:实例销毁之前。
-
destroyed:实例销毁之后。
- 应用生命周期: