uni-app:使用HBuilderX引入uni-cloud并初步使用

Unicloud的初始化

  1. 点击关联云服务空间

  2. 点击新建

  3. 先要实名认证

  4. 到 uni-Cloud 里面:新建服务空间

  5. 最后关联

  6. 云服务空间初始化

  7. 点击下一步

  8. 全选。其实就是把云函数和数据库上传的服务器上面

  9. 云函数:也可以手动一个一个上传

  10. 数据库:上传之后,还需要初始化。

  11. 引入uni-id 用户管理系统

    记得使用正则表达式,除掉注释

  12. 生成创建默认匿名用户名的钩子函数

    // 钩子函数示例 hooks/index.js  https://blog.csdn.net/qq_18798149/article/details/149302312
    function beforeRegister({
      userRecord,
      clientInfo
    } = {}) {  
        if(!userRecord.nickname) {
            /*
            Math.random() 生成随机数,例如:0.734628923
            .toString(36):把数字转为 36进制字符串, 可能变成:0.k3j4ls9
            .substring(3,9) 截取字符串的一部分。例如:k3j4ls
            最终得到:匿名k3j4ls
            */
          userRecord.nickname = "匿名"+Math.random().toString(36).substring(3,9)
        }    
        return userRecord
    }
    
    module.exports = {
      beforeRegister
    }
    
  13. 运行项目。之后先注册管理员账户

  14. 然他通过创建的管理员账户登录

  15. 客户端绑定相同的服务空间

UniCloud引入Element-Plus

  1. 安装

    npm install element-plus --save
    
  2. 在main.js里面导入和使用

    // #ifdef VUE3
    import { createSSRApp } from 'vue'
    import { createI18n } from 'vue-i18n'
    import ElementPlus from 'element-plus' // 导入element-plus
    import 'element-plus/dist/index.css' // 导入css样式
    export function createApp() {
      const app = createSSRApp(App)
      const i18n = createI18n({
          locale: lang,
          messages
      })
      app.use(i18n)
      app.use(plugin)
      app.use(store)
      app.use(ElementPlus) // 使用 element-plus
      return {
        app
      }
    }
    // #endif
    
  3. 设置语言模式为中文,因为Element Plus 组件默认使用英文

    // #ifdef VUE3
    import { createSSRApp } from 'vue'
    import { createI18n } from 'vue-i18n'
    import ElementPlus from 'element-plus' // 导入element-plus
    import 'element-plus/dist/index.css' // 导入css样式
    import zhCn from 'element-plus/es/locale/lang/zh-cn' // 引入中文
    export function createApp() {
      const app = createSSRApp(App)
      const i18n = createI18n({
          locale: lang,
          messages
      })
      app.use(i18n)
      app.use(plugin)
      app.use(store)
      // 使用 element-plus
      app.use(ElementPlus, {
        locale: zhCn, // 使用中文
      })
      return {
        app
      }
    }
    // #endif
    

开启多端运营数据统计

找到manifext.json,找到uni统计配置,开启2.0版本。前端上报周期默认是10秒,如果觉得太短,可以改成60秒。可以点击启动所有平台。也可以按需选取。

UniCloud admin 后台管理添加页面

  1. 创建新闻列表页面:/pages/activity/news/list.vue

  2. Pages.json文件里面要确保有路径

    {
      "path": "pages/activity/news/list",
      "style": {
        "navigationBarTitleText": "新闻列表"
      }
    }
    
  3. 在 admin 后台管理里面添加这个页面

  4. 添加子菜单的时候需要添加路径

创建数据库表(Schema)

如何创建

  1. 创建Schema

  2. 选择模版

  3. 讲Schema上传至服务器,创建新的表格

  4. https://unicloud.dcloud.net.cn/查看数据库表

Schema 内容解读

{
	"bsonType": "object", // 声明这个Schema描述的是一个文档对象,这个值通常是固定的 "object",因为MongoDB的文档本身就是BSON对象
	"required": [ // 必填字段
		"user_id",
		"title",
		"content"
	],
	"permission": { // 数据库权限控制
		"read": "doc.article_status == 1",  // 只有发布的文章可以被读取,article_status=1 表示已发布
		"create": false, // 客户端不能直接创建
		"update": "doc.user_id == auth.uid", // 只能修改自己的文章
		"delete": "doc.user_id == auth.uid" // 只能删除自己的文章
	},
	"properties": { // 表字段结构
		"_id": { // MongoDB / uniCloud 自动生成, 不用手动写。
			"description": "存储文档 ID(用户 ID),系统自动生成"
		},
		"user_id": {
			"bsonType": "string", // 字段类型
			"description": "文章作者ID, 参考`uni-id-users` 表", // 字段的 说明文字。不会影响数据库逻辑。
			"foreignKey": "uni-id-users._id", // 表示 外键关系(关联表)。集合名.字段名。user_id 对应 uni-id-users 表的 _id
			"defaultValue": { // 指定 字段的默认值。
				"$env": "uid" // 当前登录用户ID
			}
		},		
		"title": {
			"bsonType": "string",
			"title": "标题",
			"description": "标题",
			"label": "标题",
			"trim": "both"
		},
		"content": {
			"bsonType": "string",
			"title": "文章内容",
			"description": "文章内容",
			"label": "文章内容",
			"trim": "right"
		},
		"excerpt": {
			"bsonType": "string",
			"title": "文章摘录",
			"description": "文章摘录",
			"label": "摘要",
			"trim": "both"
		},
		"article_status": {
			"bsonType": "int",
			"title": "文章状态",
			"description": "文章状态:0 草稿箱 1 已发布",
			"defaultValue": 1,
			"enum": [
				{
					"value": 0,
					"text": "草稿箱"
				},
				{
					"value": 1,
					"text": "已发布"
				}
			]
		},
		"view_count": {
			"bsonType": "int",
			"title": "阅读数量",
			"description": "阅读数量",
			"defaultValue":50
		},		
		"is_sticky": {
			"bsonType": "bool",
			"title": "是否置顶",
			"description": "是否置顶",
			"defaultValue":false
		},
		"avatar": {
			"bsonType": "string",
			"title": "封面大图",
			"description": "缩略图地址",
			"label": "封面大图",
			"trim": "both",
			"defaultValue":""
		},
		"publish_date": {
			"bsonType": "timestamp",
			"title": "发表时间",
			"description": "发表时间",
			"defaultValue": {
				"$env": "now"
			}
		},
		"publish_ip": {
			"bsonType": "string",
			"title": "发布文章时IP地址",
			"description": "发表时 IP 地址",
			"forceDefaultValue": {
				"$env": "clientIP"
			}
		},
		"last_modify_date": {
			"bsonType": "timestamp",
			"title": "最后修改时间",
			"description": "最后修改时间",
			"defaultValue": {
				"$env": "now"
			}
		},
		"last_modify_ip": {
			"bsonType": "string",
			"description": "最后修改时 IP 地址",
			"forceDefaultValue": {
				"$env": "clientIP" // 客户端ip
			}
		}
	},
	"version": "0.0.1" // schema版本
}

permission

uniCloud Schema 里,permission 用来定义 客户端访问数据库的权限规则。 它控制客户端能否对集合执行 CRUD(增删改查) 操作。

"permission": {
  "read": "...",
  "create": "...",
  "update": "...",
  "delete": "..."
}

权限值可以是:

  • true(允许)
  • false(禁止)
  • 表达式(按条件控制)

对应四种操作:

权限 对应数据库操作 含义
read 查询数据 是否允许读取
create 新增数据 是否允许创建
update 修改数据 是否允许更新
delete 删除数据 是否允许删除

这些规则 只限制客户端(小程序 / H5 / App)。

云函数和**管理后台(admin)**默认不受限制。

read(读取权限)

控制 是否允许查询数据

例如:"read": "doc.article_status == 1"

意思是:只有 article_status = 1 的文章可以被读取。

假设数据库:

{
 "title": "文章1",
 "article_status": 1
}

客户端查询:db.collection("article").get()

可以返回。但如果:

{
 "title": "草稿",
 "article_status": 0
}

客户端查询 不会返回这条数据

常见 read 规则

只允许读取自己的数据:"read": "doc.user_id == auth.uid"

只允许登录用户读取:"read": "auth != null"

完全开放读取:"read": true

create(创建权限)

控制 客户端是否能新增数据

例如:"create": true

客户端可以直接创建:

db.collection("article").add({
  title:"hello",
  content:"world"
})

如果是:"create": false

客户端创建会失败:permission denied

必须通过 云函数 创建。

常见 create 规则

只允许登录用户创建:"create": "auth != null"

只允许管理员创建:"create": "auth.role == 'admin'"

update(修改权限)

控制 客户端是否可以修改数据

例如:"update": "doc.user_id == auth.uid"

意思是:只能修改自己创建的数据。

假设数据库:

{
 "user_id": "1001",
 "title": "文章"
}

如果当前用户:auth.uid = 1001

就可以执行:

db.collection("article").doc(id).update({
  title:"新标题"
})

但如果用户:auth.uid = 2002

就会失败。

常见 update 规则

只允许作者修改:"update": "doc.user_id == auth.uid"

只允许管理员修改:"update": "auth.role == 'admin'"

禁止修改:"update": false

delete(删除权限)

控制 客户端是否可以删除数据

例如:"delete": "doc.user_id == auth.uid"

  • 意思:只能删除自己的数据。

如果文章作者是:user_id = 1001

  • 只有 auth.uid = 1001 的用户才能删除。
常见 delete 规则

只允许作者删除:"delete": "doc.user_id == auth.uid"

只允许管理员删除:"delete": "auth.role == 'admin'"

禁止删除:"delete": false

权限表达式中的常见变量

变量 含义
doc 当前数据库记录
auth 当前登录用户信息
auth.uid 当前用户ID
auth.role 用户角色
$env 系统环境变量

例如:"update": "doc.user_id == auth.uid"

含义:当前用户 ID 必须等于 文档里的 user_id。

Uni-Cloud的访问来源

客户端(App / 小程序 / H5)

运行在 用户设备上的前端代码

const db = uniCloud.database()

db.collection("article").get()
特点 说明
运行位置 用户设备
可信度 不可信
权限 permission 限制
身份 用户 token(auth.uid)
云函数

运行在 uniCloud 云服务器上的后端代码

exports.main = async (event, context) => {
  const db = uniCloud.database()

  return db.collection("article").add({
    title: event.title
  })
}
特点 说明
运行位置 云服务器
可信度 可信
权限 不受 permission 限制
身份 服务器身份
Admin 后台

uniCloud 提供的 管理后台系统,用于管理员管理数据库。

通常是:uni-admin、管理系统、运维后台

特点 说明
运行位置 服务器 / 管理系统
可信度 可信
权限 不受 permission 限制
身份 管理员
两种访问模式

模式 1:客户端直接访问数据库:这种方式会校验permission

客户端
   ↓
数据库

模式 2:客户端/Admin通过云函数访问数据库

客户端/Admin
   	↓
	云函数
   	↓
	数据库

身份不一样

直接访问数据库和通过云函数访问云数据库的本质区别:身份(身份上下文)不一样。

访问数据库的代码都是:

const db = uniCloud.database()
db.collection("article").get()

但是,运行的环境不一样

客户端运行时,代码码运行在:浏览器、小程序、App

请求流程:

客户端代码
   ↓
uniCloud 客户端 SDK
   ↓
uniCloud 网关
   ↓
数据库

请求里会自动带上:用户 token 和 client 标识

数据库识别为:source = client

于是执行:permission 校验

云函数运行时,代码运行在:uniCloud 服务器 ,环境是云函数 runtime

请求流程:

云函数代码
   ↓
uniCloud Server SDK
   ↓
数据库

请求里带的是:server 签名和云函数上下文

数据库识别为:source = server

于是:permission 不执行

bsonType

"bsonType": "" 指定 字段的数据类型

因为 uniCloud 使用的是 MongoDB 数据库,MongoDB 存储的是 BSON(Binary JSON),所以这里用 bsonType

常见类型

类型 说明 示例
string 字符串 “hello”
int 整数 100
double 浮点数 3.14
bool 布尔 true / false
object 对象 {name:”Tom”}
array 数组 [1,2,3]
timestamp 时间戳 时间
date 日期 Date

$env

$env 表示 环境变量。uniCloud 会自动提供一些系统值。常见 $env

变量 含义
uid 当前登录用户ID
now 当前时间
clientIP 客户端IP
appid 应用ID

label 和title 属性

作用:labeltitle 是用于前端界面显示的字段标签,相当于字段的“显示名称”。

使用场景

"title": {
    "bsonType": "string",
    "title": "标题",        // 主要用于表单显示
    "label": "标题",        // 主要用于表单显示
    "description": "标题"    // 详细说明
}

当您使用 uniCloud 的 schema2code 功能(自动生成前端页面)时,label 会被用于:

  • 表单输入框的标签

    <!-- 自动生成的表单可能类似 -->
    <form>
      <label>标题</label>  <!-- 这里显示的就是 label 的值 -->
      <input type="text" v-model="formData.title" />
    </form>
    
  • 表格列的标题

    <!-- 列表页面中 -->
    <table>
      <thead>
        <tr>
          <th>标题</th>  <!-- 这里也使用 label 的值 -->
          <th>作者</th>
          <th>发布时间</th>
        </tr>
      </thead>
    </table>
    
  • 搜索条件的名称

    <!-- 搜索区域 -->
    <div class="search">
      <span>标题:</span>  <!-- 搜索字段的显示名称 -->
      <input type="text" placeholder="请输入标题" />
    </div>
    
属性名 核心作用 使用场景
title 字段的显示名称,用于自动生成的表单标签和内部文档 。 告诉阅读 Schema 的人这个字段代表什么;在自动生成代码时,作为输入框前面的提示文字。
label title 功能几乎相同,也是用于前端的显示标签 在 schema2code 中,其优先级高于 title,但目标一致。
description 字段的详细说明,用于开发者文档或作为输入框的占位提示 在自动生成的表单中,如果输入框没有专门配置,这里的描述通常会作为输入框内部的灰色提示文字。

trim 属性

作用:trim 用于自动处理字符串两端的空白字符(空格、制表符、换行符等)。这是一个数据清洗功能,在数据保存到数据库前自动执行。

可选值

  • "both":去除字符串两端的空白字符
  • "left":只去除字符串左侧(开头)的空白字符
  • "right":只去除字符串右侧(结尾)的空白字符
  • 不设置或不包含此属性:不进行任何trim操作

enum 的基本作用

enum 是 Schema 中一个非常实用的属性,它用于定义字段的“枚举类型”,即限定该字段只能取一组预定义的值。

数据验证

限制 article_status 字段只能取两个值:0(草稿箱)或 1(已发布),其他任何值都会被拒绝。

// ✅ 允许的值
{ article_status: 0 }  // 草稿
{ article_status: 1 }  // 已发布

// ❌ 不允许的值
{ article_status: 2 }  // 错误,不在枚举范围内
{ article_status: "1" } // 错误,类型必须是 int
{ article_status: true } // 错误,类型错误

值-文本映射

"enum": [
    {
        "value": 0,      // 实际存储在数据库中的值
        "text": "草稿箱"  // 对应的显示文本
    },
    {
        "value": 1,      // 实际存储在数据库中的值
        "text": "已发布"   // 对应的显示文本
    }
]

当使用 uniCloud 的 schema2code 功能自动生成前端页面时,enum 属性会被智能地转换成合适的 UI 组件:

<!-- 根据 enum 自动生成的下拉选择框 -->
<template>
  <view class="form-item">
    <text class="label">文章状态</text>
    <picker @change="onStatusChange" :value="statusIndex" :range="statusOptions" range-key="text">
      <view class="picker">
        {{ statusOptions[statusIndex].text || '请选择' }}
      </view>
    </picker>
  </view>
</template>

<script>
export default {
  data() {
    return {
      statusOptions: [
        { value: 0, text: '草稿箱' },
        { value: 1, text: '已发布' }
      ]
    }
  }
}
</script>

添加云对象

  1. 点击创建

  2. 点击云对象

  3. 编写云对象

    let dbJQL = uniCloud.databaseForJQL() // databaseForJQL() 是 UniCloud 提供的 JQL(JavaScript Query Language)数据库引用
    let {result}  = require("utils");
    module.exports = {
        /*
        作用:在每个云函数方法执行前自动运行
        功能:获取客户端信息(如用户IP、设备信息等)并重新初始化数据库连接
        这样可以确保数据库操作能正确识别客户端上下文(如用户身份)
        */
        _before: function() { // 通用预处理器
            const clientInfo = this.getClientInfo();
            dbJQL = uniCloud.databaseForJQL({
                clientInfo
            })
        },
        async add(params = {}) {
            try {
                // 1. 生成随机浏览量 (50-100之间的随机数)
                const randomInt = Math.floor(Math.random() * 51) + 50;
                params.view_count = randomInt;
                // 2. 执行数据库添加操作
                let {
                    errCode,
                    errMsg,
                    id
                    // 这里的 await 会等待数据库操作完成
                } = await dbJQL.collection("zai-news-articles").add(params)
                // 只有等待上面的操作完成后,才会执行这里的代码
                // 3. 检查返回结果
                if (errCode !== 0) return result({
                    errCode: 400,
                    errMsg: "error",
                    custom: errMsg
                });
                // 4. 成功返回
                return result({
                    errCode: 0,
                    errMsg: "success",
                    data: {
                        id
                    }
                });
            } catch (err) {
                return result({
                    errCode: 500,
                    errMsg: "bug",
                    custom: err
                })
            }
        },
    }
    
  4. 点击运行本地云对象,生成测试

  5. 会有一个 admin-news.param.js的文件

  6. 在admin的后台,找到uni-id的Token。如果不输入这个Token,无法校验通过数据库的permission。

  7. admin-news.param.js的文件里面,模拟在admin后台发出请求

    const clientInfo = {  
      clientIP: '127.0.0.1',
      uniIdToken: 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1aWQiOiI2OWIwNGQyNmVlOTdlZjJlMzE3YmM3ZWYiLCJyb2xlIjpbImFkbWluIl0sInBlcm1pc3Npb24iOltdLCJ1bmlJZFZlcnNpb24iOiIxLjAuMTgiLCJpYXQiOjE3NzMzOTAyNTksImV4cCI6MTc3MzM5NzQ1OX0.6lAOesZa3WTJXQfsJAK5xwVRDhFiJnBl_Ig6PYO4SVI'
    }
    
    add({
        title:"test123",
        content:"test123",
        
    })
    
  8. 点击运行本地云对象,这个时候就可以执行了。

创建公共模块

  1. 创建公共模块

  2. index.js文件里面写公共方法或者公共对象

  3. 要使用公共模块的时候,需要进行关联

  4. 使用require引入模块

    let {result}  = require("utils"); // 引入公共模块对象
    

Client 客户端关联后台服务空间

  1. 关联后台服务空间

  2. 这个时候Client的服务空间就是admin的服务空间

跨域问题

启动的时候会有这么一条提示:

当前项目使用了uniCloud,为避免云函数调用跨域问题,建议在HBuilderX内置浏览器里调试。如使用外部浏览器需处理跨域,请将访问页面对应的IP或域名配置在要访问的云函数所在的服务空间的跨域配置内,详见:https://uniapp.dcloud.net.cn/uniCloud/publish.html#useinh5​

但是,我实际操作是,如果在浏览器登录了uniCloud的账号,是完全不需要配置跨域的。

×

喜欢就点赞,疼爱就打赏