uniCloud——study
一、如何创建项目
新建——>项目——>uniapp——>版本选中vue2——>启动uniCloud选中阿里云(免费)
进入项目选中uniCloud右键——>关联云服务空间或项目——>关联云服务空间——>新建——>选中阿里云——>服务空间(自命名)——>创建——>就会跳转到阿里云服务器空间能看到自己创建的服务器
回到开发工具中——>选中项目进行关联
cloudfunctions:云函数
database:数据库
注意
如果想看阿里云的云服务空间可以选中uniCloud右键选中打开uniCloud Web控制台....
(1)测试阿里云云服务系统
选中uniCloud下的cloudfunctions(服务端)的文件夹右键——>新建云函数/云对象——>{myCkoudFun,云函数,默认模板}——>就会得到一个myCloudFun文件夹,文件夹下包含两个文件
index.js:所有的请求都是从这里来的
package.json:安装需要的依赖
// 测试 myCloudFun下的index.js
export.main = async(event,context) =>{
return "uniapp学习uniCloud"
}
调用服务器接口
//在pages文件夹下的index下的index.vue文件调用
onLoad(){
uniCloud.callFunction({
name:"myCloudFun"
}).then(res=>{
console.log(res);
})
}
// 控制台输出为{result:"uniapp学习uniCloud"}
(2)客户端给服务端传递参数
// pages文件夹下的index下的index.vue文件
onLoad(){
uniCloud.callFunction({
name:"myCloudFun",
data:{
name:"王五",
age:20
}
}).then(res=>{
console.log(res)
})
}
// uniCloud下的cloudfunctions下的myCloudFun下的index.js
export.main = async(event,context) =>{
let {name,age} = event
return event;
}
//控制台输出为{result:{name:"王五",age:20}}
二、创建云数据库/数据表
(1)如何创建数据库/数据表
点击打开uniCloud Web控制台....,进入到云数据库,点击进入到云数据库进入到数据表,点击+号创建数据表users,点击添加记录
{
"name":"张三",
"gender":"男",
"tel": 1886666662,
"mail": "555555@qq.com"
}
(2)在云函数中请求数据库
在cloudfunctions(云函数文件夹下)新建个云函数cloudDemo1,在其index.js文件夹下连接数据库
const db = uniCloud.database() // 连接数据库
export.main = async (event,context) => {
let res = await db.collection("users").get();
return res;// 选中数据库下的users表,获取get请求,拿到数据库中的数据,返回出去
}
(3)在客户端请求服务器发送过来的数据
onLoad(){
uniCloud.callFunction({
name:"cloudDemo1",
data:{}
}).then(res=>{
console.log(res)
})
}
// 输出的结果为
(4)连接数据库发送count请求
const db = uniCloud.database() // 连接数据库
export.main = async (event,context) => {
let res = await db.collection("users").count();
return res;// 选中数据库下的users表,获取count请求,拿到数据库中的数据,返回出去
}
onLoad(){
uniCloud.callFunction({
name:"cloudDemo1",
data:{}
}).then(res=>{
console.log(res)
})
}
// 输出的结果为affectedDocs:3,total:3,显示的是数据的数量
(5)连接数据库发送add请求
const db = uniCloud.database() // 连接数据库
export.main = async (event,context) => {
let res = await db.collection("users").add({
name:"小红",
gender:"女"
});
return res;// 选中数据库下的users表,添加数据add请求,增加一条数据,返回出去
}
onLoad(){
uniCloud.callFunction({
name:"cloudDemo1",
data:{}
}).then(res=>{
console.log(res)
})
}
在客户端调用的话控制台多一条数据
(6)批量插入add请求
const db = uniCloud.database() // 连接数据库
export.main = async (event,context) => {
let res = await db.collection("users").add([
{name:"小红"},
{name:"麦迪"}
]);
return res;// 选中数据库下的users表,添加数据add请求,增加一条数据,返回出去
}
(7)客户端在表单中添加数据传给服务器案例
<form @submit="onSubmit">
<input type="text" name="name">
<input type="text" name="tel">
<button form-type="submit">提交</button>
</form>
....
methods:{
onSubmit(e){
let obj = e.detail.value;
uniCloud.callFunction({
name:"cloudDemo1",
data:obj
}).then(res => {
console.log(res)
})
}
}
// 服务端接收传过来的数据
const db = uniCloud.database() // 连接数据库
export.main = async (event,context) => {
let {name,tel}=event;
let res = await db.collection("users").add([
name,
tel
]);
return res;
}
// 在users数据表中,可以查看到客户端输入提交的数据
(8)用doc对集合中指定id的记录查询引用
// 客户端
onLoad(){
this.getData()
},
methods:{
getData(){
uniCloud.callFunction({
//cloudDemoGet新建的云函数
name:"cloudDemoGet"
}).then(res =>{
console.log(res)
})
}
}
// 输出的是只包含这条id的数据,一般使用场景就是详情页
// 服务端
const db = uniCloud.database() // 连接数据库
export.main = async (event,context) => {
let res = await db.collection("users").doc("63370774d76aaf00015995f3").get();
return res;
}
// 63370774d76aaf00015995f3 是id的唯一标识
(9)limit对数量进行限制
const db = uniCloud.database() // 连接数据库
export.main = async (event,context) => {
let res = await db.collection("users").limit(5).get();
return res;
}
// 客户端
onLoad(){
this.getData()
},
methods:{
getData(){
uniCloud.callFunction({
//cloudDemoGet新建的云函数
name:"cloudDemoGet"
}).then(res =>{
console.log(res)
})
}
}
// 本来14条数据,limit(5)只显示5条数据,一般用做分页
(10)skip跳过指定数量的文档
const db = uniCloud.database() // 连接数据库
export.main = async (event,context) => {
let res = await db.collection("users").limit(5).skip(0).get();
return res;
}
// 客户端
onLoad(){
this.getData()
},
methods:{
getData(){
uniCloud.callFunction({
//cloudDemoGet新建的云函数
name:"cloudDemoGet"
}).then(res =>{
console.log(res)
})
}
}
// 显示第一页的五条数据,skip(5)显示第二页的五条数据
(11)orderBy顺序(倒序)排列
const db = uniCloud.database() // 连接数据库
export.main = async (event,context) => {
let res = await db.collection("users").orderBy("_id","desc").get();
return res;
}
//orderBy("_id","desc")id按倒序排列,asc是顺序排列,阿里云顺序是默认的
(12)field过滤掉不需要的字段
const db = uniCloud.database() // 连接数据库
export.main = async (event,context) => {
let res = await db.collection("users").field({'age':true}).get();
return res;
}
// 只返回age字段、_id字段,_id是唯一标识符,必须返回
(13)where精确查询
const db = uniCloud.database() // 连接数据库
export.main = async (event,context) => {
let res = await db.collection("users").where({id:"63370774d76aaf00015995f3"}).get();
return res;
}
// 控制台输出的是id为:63370774d76aaf00015995f3的一条数据信息
(14)command查询
// eq查询 意思为== neq意思为!= gt意思为> gte意思为>= lt意思为< lte意思为<=
const db = uniCloud.database() // 连接数据库
const dbCmd = db.command;
export.main = async (event,context) => {
let res = await db.collection("users").where({age:dbCmd.eq(30)}).get(); // 查询年龄等于30的数据
return res;
}
//in意思为在数组里面 nin意思为不在数组里 and表示需同时满足指定的条件 or表示需满足指定条件里面的任意一个
const db = uniCloud.database() // 连接数据库
const dbCmd = db,command;
export.main = async (event,context) => {
let res = await db.collection("users").where({age:dbCmd.in[24,41]}).get(); // 查询年龄为24,41岁的数据
return res;
}
查询年龄大于二十岁小于四十岁的数据
const db = uniCloud.database() // 连接数据库
const dbCmd = db.command;
export.main = async (event,context) => {
let res = await db.collection("users").where({age:dbCmd.gt(20).and(dbCmd.lt(40))}).get(); // 查询年龄为24,41岁的数据
return res;
}
const db = uniCloud.database() // 连接数据库
const dbCmd = db.command;
export.main = async (event,context) => {
let res = await db.collection("users").where({age:dbCmd.and(dbCmd.gt(20),dbCmd.lt(40))}).get(); // 查询年龄为24,41岁的数据
return res;
}
(15)正则表达式查询(db.RegExp)
const db = uniCloud.database() // 连接数据库
const dbCmd = db.command;
export.main = async (event,context) => {
let {keyword} = event
let res = await db.collection("users").where({name:new RegExp(keyword,'ig')}).get(); // 查询年龄为24,41岁的数据
return res;
}
(16)update修改
// 改变单条数据
const db = uniCloud.database() // 连接数据库
exports.main = async (event,content) => {
let res = await db.collection("users").doc("63370774d76aaf00015995f3").update({
name:"张三三",
age:66
return{
msg:"修改成功",
res
}
})
}
// 改变多条数据 改变所有年龄为30的电话号码为8888888
const db = uniCloud.database()
exports.main = async(event,content) => {
let res = await db.collection("users").where({age:30}).updata({
tel:8888888
})
}
unshift、push、pop、shift
const db = uniCloud.database() // 连接数据库
const dbCmd = db.command;
exports.main = async (event,content) => {
let res = await db.collection("users").where(_id:"63370774d76aaf00015995f3").update({
tabs:{
jobs:"歌手"
}
// like:dbCmd.unshift(["篮球","演戏"]) 向数组头部添加元素
// like:dbCMd.push(["打游戏"]) 向数组尾部追加元素
// like:dbCmd.pop() 删除数组尾部元素
// like:dbCmd.shift() // 删除数组头部元素
like:dbCmd.push({ // 从第一个数据后面追加["篮球","aaa","bbb","演戏"]
each:['aaa','bbb'],
position:1
})
})
return res
}
set、 inc、 mul
const db = uniCloud.database() // 连接数据库
const dbCmd = db.command;
exports.main = async (event,content) => {
let res = await db.collection("users").where(_id:"63370774d76aaf00015995f3").update({
tabs:{
jobs:"歌手"
}
// like:dbCmd.unshift(["篮球","演戏"]) 向数组头部添加元素
// like:dbCMd.push(["打游戏"]) 向数组尾部追加元素
// like:dbCmd.pop() 删除数组尾部元素
// like:dbCmd.shift() // 删除数组头部元素
// love:dbCmd.inc(2) // 每次刷新或者点击自增2、 inc(-2)自减2
// love:dbCmd.mul(10) // 自乘(10) mul(0.1) 自除
})
return res
}
update和set的区别
updata:局部更新记录(触发请求)只更新传入的字段。如果被更新的记录不存在,会直接返回更新失败
set:覆写记录;会删除操作的记录中的所有字段,创建传入的字段。如果操作的记录不存在,会自动创建新的记录
const db = uniCloud.database() // 连接数据库
const dbCmd = db.command;
exports.main = async (event,content) => {
let res = await db.collection("users").doc("63370774d76aaf00015995f3").set({
// like:dbCmd.unshift(["篮球","演戏"]) 向数组头部添加元素
// like:dbCMd.push(["打游戏"]) 向数组尾部追加元素
// like:dbCmd.pop() 删除数组尾部元素
// like:dbCmd.shift() // 删除数组头部元素
// love:dbCmd.inc(2) // 每次刷新或者点击自增2、 inc(-2)自减2
// love:dbCmd.mul(10) // 自乘(10) mul(0.1) 自除
name:"张三" //当这样设置了之后,这个id的数据只会显示id和name:"张三",其余的数据都会被覆盖删除
})
return res
}
(17)remove删除记录
客户端
<button type="warning" @click="onRemove">删除</button>
.....
onLoad(){
onRemove(){
uniCloud.callFunction({
name:"CloudDemoRemove"
}).then(res =>{
console.log(res);
})
}
}
服务端
const db = uniCloud.database()
exports.main = async (event,context) => {
return await db.collection("users").doc("63370774d76aaf00015995f3").remove() // 删除id为:63370774d76aaf00015995f3的整条数据
}
全部删除
const db = uniCloud.database()
const dbCmd = db.command;
exports.main = async (event,context) => {
return await db.collection("users").where({
_id:dbCmd.neq(-1) // 查询id不等于-1的数进行删除,也就是把数据全部删除
}).remove()
}
(18)云函数的操作
如果换环境或者换电脑了,需要在cloudfunctions里右键选择上传所有云函数,不然换个新环境,云函数就没有了。到了新的环境,需要右键点击下载所有的云函数
三、文章uniCloud案例
(1)新建项目
新建项目——>vue2——>启用uniCloud——>创建——>关联阿里云服务器——>项目创建成功
(2)首页布局
<template>
<view class="home">
<view class="content">
<view class="item" v-for="item in 5">
<view class="text">
<view class="title">默认标题</view>
<view class="info">
<text>小明</text>
<text>2022-10-11</text>
<text>删除</text>
</view>
</view>
<view class="pic">
<image src="../../static/image/nopic.jpg" mode="aspectFill"></image>
</view>
</view>
</view>
<view class="goAddArticle">+</view>
</view>
</template>
<script>
export default {
data() {
return {
title: 'Hello'
}
},
onLoad() {
},
methods: {
}
}
</script>
<style lang="scss" scoped>
.home {
.content {
padding: 30rpx;
.item {
display: flex;
justify-content: space-between;
padding: 20rpx 0;
border-bottom: 1rpx solid #eee;
.text {
flex: 1;
display: flex;
flex-direction: column;
justify-content: space-between;
padding-right: 20rpx;
.title {
font-size: 44rpx;
color: #333;
text-align: justify;
text-overflow: -o-ellipsis-lastline;
overflow: hidden; //溢出内容隐藏
text-overflow: ellipsis; // 文本溢出部分用省略号表示
display: -webkit-box; // 特别显示模式
-webkit-line-clamp: 2; // 行数
line-clamp: 2;
-webkit-box-orient: vertical;
}
.info {
font-size: 28rpx;
color: #888;
padding-right: 20rpx;
}
}
.pic {
width: 260rpx;
height: 180rpx;
image {
width: 100%;
height: 100%;
}
}
}
}
.goAddArticle {
width: 80rpx;
height: 80rpx;
background: #3852f8;
color: #fff;
display: flex;
justify-content: center;
align-items: center;
border-radius: 50%;
font-size: 50rpx;
position: fixed;
right: 60rpx;
bottom: 100rpx;
box-shadow: 0 0 20rpx rgba(56, 82, 248, 0.7);
}
}
</style>
(3)给+号设置点击事件跳转到新增新闻页面
<view class="goAddArticle" @click="goAddArticle">+</view>
methods: {
goAddArticle() { //点击跳转到新增页面
uni.navigateTo({
url: "/pages/AddArticle/AddArticle"
})
}
}
(4)添加文章组件样式
<template>
<view class="add">
<form>
<view class="item">
<input type="text" name="title" placeholder="请输入标题" />
</view>
<view class="item">
<input type="text" name="author" placeholder="请输入作者" />
</view>
<view class="item">
<textarea name="content" placeholder="请输入详细内容"></textarea>
</view>
<view class="item">
<button>提交</button>
</view>
</form>
</view>
</template>
<script>
export default {
data() {
return {
};
}
}
</script>
<style lang="scss" scoped>
.add {
padding: 30rpx;
.item {
padding-bottom: 20rpx;
input,
textarea {
border: 1rpx solid #eee;
height: 80rpx;
padding: 0 20rpx;
}
textarea {
height: 200rpx;
width: 100%;
box-sizing: border-box;
}
}
}
</style>
(5)云数据库新建数据、拿到数据、渲染数据
1、云数据库新建数据库、数据表
2、新建云函数/云对象,编写对应的数据库连接
// 在新建的云函数/云对象getArticleAll下的index.js文件
'use strict';
const db = uniCloud.database()
exports.main = async (event, context) => {
//event为客户端上传的参数
let res = await db.collection("article").get();
//返回数据给客户端
return res
};
3、在客户端编写向服务器发送请求并调用
// 在pages下的index.vue文件编写请求服务器的接口
articleList: []
....
onLoad() {
this.getArticleAll()
},
....
// 获取文章数据
getArticleAll() {
uniCloud.callFunction({
name: "getArticleAll"
}).then(res => {
console.log(res);
this.articleList = res.result.data
})
}
4、对获取的数据在页面上进行渲染
<view class="item" v-for="(item,index) in articleList" :key="item.id">
<view class="text">
<view class="title">{{item.title}}</view>
<view class="info">
<text>{{item.author}}</text>
<text>{{item.postime}}</text>
<text>删除</text>
</view>
</view>
(6)给添加文章组件添加表单事件,并且把值传给云服务器
1、给表单添加提交事件,并且设置提交和重置按钮
// AddArticle.vue
<form @submit="onSubmit">
<view class="item">
<input type="text" name="title" placeholder="请输入标题" />
</view>
<view class="item">
<input type="text" name="author" placeholder="请输入作者" />
</view>
<view class="item">
<textarea name="content" placeholder="请输入详细内容"></textarea>
</view>
<view class="item">
<button form-type="reset" class="reset">重置</button>
<button form-type="submit" type="primary">提交</button>
</view>
</form>
......
onSubmit(e) {
let detail = e.detail.value;
uniCloud.callFunction({
name: "AddArticleRow",
data: {
detail: detail
}
}).then(res => {
console.log(res);
})
}
2、新建云函数,把表单的值传到数据库
// cloudfunctions下新建个AddArticleRow文件夹下的index.js文件
'use strict';
const db = uniCloud.database()
exports.main = async (event, context) => {
//event为客户端上传的参数
let {
detail
} = event;
return await db.collection('article').add({
posttime: Date.now(), // 当前添加的时间
...detail // 把表单里面的值传给服务器
});
//返回数据给客户端
};
(7)对添加表单组件进行优化
1、添加表单验证
//(1) 新建对象存储数据
data() {
return {
//表单验证
formValue: {
title: "",
author: "",
content: ""
}
};
},
// (2) 给输入框添加双向数据绑定
<view class="item">
<input v-model="formValue.title" type="text" name="title" placeholder="请输入标题" />
</view>
<view class="item">
<input v-model="formValue.author" type="text" name="author" placeholder="请输入作者" />
</view>
<view class="item">
<textarea v-model="formValue.content" name="content" placeholder="请输入详细内容"></textarea>
</view>
//(3) 给提交按钮添加禁用事件
<view class="item">
<button form-type="reset" class="reset">重置</button>
<button form-type="submit" type="primary" :disabled="inDisable(formValue)">提交</button>
</view>
//(4)给禁用表单添加循环事件,循环formValue里面的值,判断是否为空,不为空则把disable的值改为true,默认为false
//表单验证,判断是否有一项没输
inDisable(obj) {
for (let key in obj) {
if (!obj[key]) { //若都不为空,则把disable的值改为true
return true;
}
}
},
//(5) 添加发布成功的消息,并且清空表单里面的数据,跳转到首页
onSubmit(e) {
let detail = e.detail.value;
uniCloud.callFunction({
name: "AddArticleRow",
data: {
detail: detail
}
}).then(res => {
uni.showToast({
title: "发布成功"
})
// 清空输入的值
formValue: {
title: "";
author: ""
content: ""
};
setTimeout(() => {
uni.reLaunch({
url: "/pages/index/index"
})
}, 1000)
console.log(res);
})
}
(8)onReachBottom触底事件,加载更多
1、设置每页多少条数据,并接收传过来的总数据,为翻页加载更多做准备
//cloudfunctions下的getArticleAll文件夹下的index.js
'use strict';
const db = uniCloud.database()
exports.main = async (event, context) => {
//event为客户端上传的参数 按添加时间排序,逆序
// 接收传递过来的翻页条数,默认为0
let {
skip = 0
} = event;
let res = await db.collection("article").limit(6).skip(skip).orderBy("posttime", "desc").get();
//返回数据给客户端
return res
};
2、在首页组件pages下的index.vue文件中把skip的值传过去,并且进行数据的拼接,再进行渲染
// 获取文章数据
getArticleAll() {
uniCloud.callFunction({
name: "getArticleAll",
data: {
skip: this.articleList.length
}
}).then(res => {
console.log(res);
let oldList = this.articleList;
let newList = [...oldList, ...res.result.data]
this.articleList = newList
})
}
(9)扩展组件的下载和使用
1、在uniapp的扩展组件(uni-ui)下找到需要的组件进行下载并绑定到项目,然后查看扩展组件里面的实例来进行必要的编写
<view class="home">
<view class="content">
<view class="item" v-for="(item,index) in articleList" :key="item.id">
<view class="text">
<view class="title">{{item.title}}</view>
<view class="info">
<text>{{item.author}}</text>
<!-- 格式化时间戳 -->
<text><uni-dateformat :date="item.posttime" :threshold="[60000, 3600000]"
format="yyyy-MM-dd"></uni-dateformat></text>
</view>
</view>
<view class="pic">
<image src="../../static/image/nopic.jpg" mode="aspectFill"></image>
</view>
</view>
</view>
<!-- +号icon符号 -->
<view class="goAddArticle" @click="goAddArticle"><uni-icons type="plusempty" size="20" color="#fff"></uni-icons>
</view>
</view>
(10)详情页样式编写
<template>
<view class="detail">
<view class="title">这是标题</view>
<view class="info">
<text>王五</text>
<text>2023-07-17 14:46:00</text>
</view>
<view class="content">这是详细内容</view>
<view class="btnGroup">
<button size="mini">修改</button>
<button size="mini" type="warn">删除</button>
</view>
</view>
</template>
<script>
export default {
data() {
return {
};
}
}
</script>
<style lang="scss" scoped>
.detail {
padding: 30rpx;
.title {
font-size: 50rpx;
color: #000;
text-align: justify;
line-height: 1.4em;
}
.info {
font-size: 30rpx;
color: #666;
padding: 30rpx 0 60rpx;
text {
padding-right: 30rpx;
}
}
.content {
font-size: 36rpx;
line-height: 1.4em;
}
.btnGroup {
padding: 50rpx 0;
button {
margin-right: 30rpx;
}
}
}
</style>
(11)点击新闻携带参数跳转到详情页
1、给新闻的头部盒子添加点击事件
<view @click.native="goDetail(item)" class="item" v-for="(item,index) in articleList" :key="item.id">
<view class="text">
<view class="title">{{item.title}}</view>
<view class="info">
<text>{{item.author}}</text>
<!-- 格式化时间戳 -->
<text><uni-dateformat :date="item.posttime" :threshold="[60000, 3600000]"
format="yyyy-MM-dd"></uni-dateformat></text>
</view>
</view>
<view class="pic">
<image src="../../static/image/nopic.jpg" mode="aspectFill"></image>
</view>
</view>
2、设置携带这条新闻的__id跳转到详情页
//跳转到详情页
goDetail(item) {
// console.log(item);
uni.navigateTo({
url: `/pages/detail/detail?id=${item._id}`
})
},
(12)详情页云函数接口的编写和数据的渲染
思路:拿到传过来的id值,后台根据id值来进行数据的查找,并且把数据反馈给前台
1、在onLoad下拿到传过来的id值,并且新建个变量来存储id,为把id传给服务器查找到特定的数据做准备
let id;
...
// 拿到传过来的_id
onLoad(e) {
id = e.id
console.log(id);
this.getDetail();
},
2、在cloudfunctions下新建个getArticleDetail云函数,并且根据id查找对应的数据反馈给前台
'use strict';
const db = uniCloud.database();
exports.main = async (event, context) => {
let {
id
} = event;
return await db.collection("article").doc(id).get();
};
3、前台接收后台传过来的数据,并进行数据渲染
getDetail() {
uniCloud.callFunction({
name: "getArticleDetail",
data: {
id: id
}
}).then(res => {
console.log(res);
this.detail = res.result.data[0];
})
}
<view class="detail">
<view class="title">{{detail.title}}</view>
<view class="info">
<text>{{detail.author}}</text>
<text>
<uni-dateformat :date="detail.posttime" :threshold="[60000, 3600000]"
format="yyyy年MM月dd日 hh:mm:ss"></uni-dateformat>
</text>
</view>
<view class="content">
{{detail.content}}
</view>
<view class="btnGroup">
<button size="mini">修改</button>
<button size="mini" type="warn">删除</button>
</view>
</view>
(13)详情页加载效果优化
1、因为详情页加载跳转是直接跳转,在页面没有渲染完成按钮就已经出来了,所以添加一个加载效果,在扩展组件找到uni-load-more来下载安装
//新建个变量 默认为false
loading: false
//利用个view标签把整段信息包含,并设置判断loading条件
<view v-if="loading">
<view class="title">{{detail.title}}</view>
<view class="info">
<view class="info-item">{{detail.author}}</view>
<view class="info-item">
<uni-dateformat :date="detail.posttime" :threshold="[60000, 3600000]"
format="yyyy年MM月dd日 hh:mm:ss"></uni-dateformat>
</view>
</view>
<view class="content">
{{detail.content}}
</view>
<view class="btnGroup">
<button size="mini">修改</button>
<button size="mini" type="warn">删除</button>
</view>
</view>
<view v-else>
<uni-load-more status="loading"></uni-load-more>
</view>
//当页面加载完毕,把loading的值改为true,并且动态设置页面标题为新闻标题
getDetail() {
uniCloud.callFunction({
name: "getArticleDetail",
data: {
id: id
}
}).then(res => {
this.detail = res.result.data[0];
this.loading = true
uni.setNavigationBarTitle({
title: this.detail.title
})
})
}
(14)删除新闻
思路:①新建云函数,根据id来对这条数据进行删除;
②编写删除的函数,在点击确认的时候,触发这个函数,进行删除
③删除成功的提示信息,删除成功之后跳转到首页
// 新建removeArticle云函数
'use strict';
const db = uniCloud.database();
exports.main = async (event, context) => {
let {
id
} = event;
return await db.collection('article').doc(id).remove();
};
// 编辑删除接口的函数
// 删除接口函数
removeFun() {
uniCloud.callFunction({
name: "removeArticle",
data: {
id: id
}
}).then(res => {
uni.showToast({
title: "删除成功",
})
setTimeout(() => {
uni.reLaunch({
url: "/pages/index/index"
})
}, 800)
})
},
// 给删除按钮添加点击事件,并且设置提示框,点击确认进行删除,点击取消不进行任何操作
// 删除数据
onRemove() {
uni.showModal({
content: "是否确认删除",
success: res => {
//点击确认进行删除 取消不进行任何操作
if (res.confirm) {
this.removeFun()
}
}
})
},
(15)对修改页面进行数据渲染(回显)
1、给详情页的修改按钮添加点击事件,跳转到修改页面并携带这条参数的id
<view class="btnGroup">
<button size="mini" @click="goEdit()">修改</button>
<button size="mini" type="warn" @click="onRemove">删除</button>
</view>
....
//点击修改
goEdit() {
uni.navigateTo({
url: `/pages/EditArticle/EditArticle?id=${id}`
})
},
2、在onLoad()函数里面接收传过来的id
let id;
onLoad(e){
id = e.id
}
3、根据id请求详情页后台服务器数据
//表单验证
formValue: {
title: "",
author: "",
content: ""
}
....
getDetail(){
//获取详情
getDetail() {
uniCloud.callFunction({
name: "getArticleDetail",
data: {
id: id
}
}).then((res) => {
this.formValue = res.result.data[0]
})
},
}
4、最终代码
<template>
<view class="edit">
<form @submit="onSubmit">
<view class="item">
<input v-model="formValue.title" type="text" name="title" placeholder="请输入标题" />
</view>
<view class="item">
<input v-model="formValue.author" type="text" name="author" placeholder="请输入作者" />
</view>
<view class="item">
<textarea v-model="formValue.content" name="content" placeholder="请输入详细内容"></textarea>
</view>
<view class="item">
<button form-type="reset" class="reset">重置</button>
<button form-type="submit" type="primary" :disabled="inDisable(formValue)">提交</button>
</view>
</form>
</view>
</template>
<script>
let id;
export default {
data() {
return {
//表单验证
formValue: {
title: "",
author: "",
content: ""
}
};
},
onLoad(e) {
id = e.id;
this.getDetail();
},
methods: {
//获取详情
getDetail() {
uniCloud.callFunction({
name: "getArticleDetail",
data: {
id: id
}
}).then((res) => {
this.formValue = res.result.data[0]
console.log(this.formValue);
console.log(res);
})
},
//表单验证,判断是否有一项没输
inDisable(obj) {
for (let key in obj) {
if (!obj[key]) { //若都不为空,则把disable的值改为true
return true;
}
}
},
onSubmit(e) {
let detail = e.detail.value;
uniCloud.callFunction({
name: "AddArticleRow",
data: {
detail: detail
}
}).then(res => {
uni.showToast({
title: "发布成功"
})
// 清空输入的值
formValue: {
title: "";
author: ""
content: ""
};
setTimeout(() => {
uni.reLaunch({
url: "/pages/index/index"
})
}, 1000)
console.log(res);
})
}
}
}
</script>
<style lang="scss" scoped>
.edit {
padding: 30rpx;
.item {
padding-bottom: 20rpx;
input,
textarea {
border: 1rpx solid #eee;
height: 80rpx;
padding: 0 20rpx;
}
textarea {
height: 200rpx;
width: 100%;
box-sizing: border-box;
}
button {
margin-bottom: 20rpx;
}
}
}
</style>
(16)对修改页面完成数据回显的修改
1、给表单的点击提交事件把表单的数据传到服务器
onSubmit(e) {
uniCloud.callFunction({
name: "eidtArticleRow",
data: {
detail: this.formValue // 因为this。formValue已经拿到全部的数据了,所以用这个最好
}
}).then(res => {
uni.showToast({
title: "修改成功"
})
// 清空输入的值
formValue: {
title: "";
author: ""
content: ""
};
setTimeout(() => {
uni.reLaunch({
url: "/pages/index/index"
})
}, 1000)
console.log(res);
})
}
2、新建云函数接收前台传过来的值,原理:把原来的值进行覆盖
'use strict';
const db = uniCloud.database()
exports.main = async (event, context) => {
//event为客户端上传的参数
let {
detail
} = event;
return await db.collection("article").doc(detail._id).update({
title: detail.title,
author: detail.author,
content: detail.content
})
return event
};
3、最终代码
<template>
<view class="edit">
<form @submit="onSubmit">
<view class="item">
<input v-model="formValue.title" type="text" name="title" placeholder="请输入标题" />
</view>
<view class="item">
<input v-model="formValue.author" type="text" name="author" placeholder="请输入作者" />
</view>
<view class="item">
<textarea v-model="formValue.content" name="content" placeholder="请输入详细内容"></textarea>
</view>
<view class="item">
<button form-type="reset" class="reset">重置</button>
<button form-type="submit" type="primary" :disabled="inDisable(formValue)">提交</button>
</view>
</form>
</view>
</template>
<script>
let id;
export default {
data() {
return {
//表单验证
formValue: {
title: "",
author: "",
content: ""
}
};
},
onLoad(e) {
id = e.id;
},
onShow() {
this.getDetail();
},
methods: {
//获取详情
getDetail() {
uniCloud.callFunction({
name: "getArticleDetail",
data: {
id: id
}
}).then((res) => {
this.formValue = res.result.data[0]
})
},
//表单验证,判断是否有一项没输
inDisable(obj) {
for (let key in obj) {
if (!obj[key]) { //若都不为空,则把disable的值改为true
return true;
}
}
},
onSubmit(e) {
uniCloud.callFunction({
name: "eidtArticleRow",
data: {
detail: this.formValue
}
}).then(res => {
uni.showToast({
title: "修改成功"
})
setTimeout(() => {
uni.navigateBack()
}, 800)
})
}
}
}
</script>
<style lang="scss" scoped>
.edit {
padding: 30rpx;
.item {
padding-bottom: 20rpx;
input,
textarea {
border: 1rpx solid #eee;
height: 80rpx;
padding: 0 20rpx;
}
textarea {
height: 200rpx;
width: 100%;
box-sizing: border-box;
}
button {
margin-bottom: 20rpx;
}
}
}
</style>
(17)首页开启下拉刷新
思路:
①在需要下拉刷新的页面开启下拉刷新
②找到对应的API,找到下拉刷新事件和停止下拉刷新事件onPullDownRefresh(下拉刷新)、uni.stopPullDownRefresh(停止当前页面下拉刷新)
③在需要下拉刷新的页面定义下拉刷新的方法——再次调用一次获取新闻列表的数据请求,在此之前把存储的数据清空
1、在API下找到下拉刷新文档介绍,得到onPullDownRefresh(下拉刷新)、uni.stopPullDownRefresh(停止当前页面下拉刷新)
// 在pages.json下的首页下的style开启允许下拉刷新
{
"path": "pages/index/index",
"style": {
"navigationBarTitleText": "资讯新闻",
"enablePullDownRefresh": true
}
},
2、在想要下拉刷新的页面定义下拉刷新函数onPullDownRefresh(下拉刷新)
//下拉刷新
onPullDownRefresh() {
//下拉刷新需要对数据进行初始化,防止数据重复拼接
this.articleList = []
this.getArticleAll()
},
3、在数据传输完之后结束下拉刷新
// 获取文章数据
getArticleAll() {
uniCloud.callFunction({
name: "getArticleAll",
data: {
skip: this.articleList.length
}
}).then(res => {
if (res.result.data.length == 0) {
this.loading = 2
}
// console.log(res);
let oldList = this.articleList;
let newList = [...oldList, ...res.result.data]
this.articleList = newList
uni.stopPullDownRefresh() //停止当前页面下拉刷新。
})
}
四、云存储文件上传
uniCloud关联的阿里云服务器有个云存储可以实现文件上传
(1)找到上传组件
在uniapp下——>组件——>扩展组件——>uni-file-picker文件选择上传安装插件
(2)自定义上传
<template>
<view class="file">
<view class="uploadGroup">
<view class="box">
<image src="../../static/logo.png" mode="aspectFill"></image>
<view class="close">x</view>
</view>
<view class="box add">+</view>
</view>
</view>
</template>
<script>
export default {
data(){
return {
}
},
methods:{
}
}
</script>
<style lang="scss" scoped>
.unloadGroup{
padding:30rpx;
display:flex;
flex-wrap:wrap;
.box{
width:200rpx;
height:200rpx;
background:#eee;
margin-right:15rpx;
margin-bottom:15rpx;
position:relative;
image{
width:100%;
height:100%;
}
.close{
position:absolute;
right:0;
top:0;
width:50rpx;
height:50rpx;
background:rgba(0,0,0,0.7);
color:#fff;
border-radius:0 0 0 80rpx;
display:flex;
justify-content:center;
align-items:center;
}
}
.add{
font-size:80rpx;
display:flex;
align-items:center;
justify-content:center;
color:#888;
}
}
</style>
(3)实现图片上传
1、在uniapp下——>组件——>扩展组件——>uni-file-picker文件选择上传安装插件
2、在添加新闻页面(AddArticle.vue)添加上传图片的组件样式和方法
<view class="item">
<uni-file-picker v-model="imageValue" fileMediatype="image" mode="grid" @success="uploadSuccess" />
</view>
imageValue: [],
// 上传成功
uploadSuccess(e) {
console.log('上传成功')
},
3、打印上传图片的参数来查看,然后进行赋值
picUrls: [],
// 上传成功
uploadSuccess(e) {
this.picUrls = e.tempFilePaths
},
4、对表单的点击提交事件进行传值,把存储的图片进行上传
onSubmit(e) {
let detail = e.detail.value;
uniCloud.callFunction({
name: "AddArticleRow",
data: {
detail: detail,
picUrls: this.picUrls
}
}).then(res => {
uni.showToast({
title: "发布成功"
})
setTimeout(() => {
uni.reLaunch({
url: "/pages/index/index"
})
}, 1000)
})
}
5、在添加新闻的云函数中进行接收传过来的值
'use strict';
const db = uniCloud.database()
exports.main = async (event, context) => {
//event为客户端上传的参数
let {
detail,
picUrls
} = event;
return await db.collection('article').add({
picUrls,
posttime: Date.now(), // 当前添加的时间
...detail // 把表单里面的值传给服务器
});
//返回数据给客户端
};
(4)点击修改数据回显和修改
1、在修改的组件里添加上传图片样式和方法
<view class="item">
<uni-file-picker v-model="imageValue" fileMediatype="image" mode="grid" @success="uploadSuccess" />
</view>
imageValue: [],
picUrls: [],
// 上传成功
uploadSuccess(e) {
this.picUrls = e.tempFilePaths
},
2、因为点击详情页携带的数据中包括图片,但是图片必须进行处理才能在页面上显示
注意:文件上传注意事项:(1)必须是数组或者对象形式;(2)value的三个属性必填name extname url 否则影响组件显示
//获取详情
getDetail() {
uniCloud.callFunction({
name: "getArticleDetail",
data: {
id: id,
}
}).then((res) => {
console.log(res);
this.formValue = res.result.data[0]
// 文件上传注意事项:(1)必须是数组或者对象形式;(2)value的三个属性必填name extname url 否则影响组件显示
// this.imageValue = res.result.data[0].picUrls
if (!this.formValue.picUrls) return
let urls = this.formValue.picUrls.map(item => {
return {
url: item
}
})
this.imageValue = urls
})
},
3、对前台传递的图片数据,云函数接收之后,需要进行处理传到服务器上
'use strict';
const db = uniCloud.database()
exports.main = async (event, context) => {
//event为客户端上传的参数
let {
detail,
picUrls
} = event;
return await db.collection("article").doc(detail._id).update({
title: detail.title,
author: detail.author,
content: detail.content,
picUrls: picUrls
})
return event
};
(5)对图片在首页上进行渲染
因为已经获取到了数据,所以直接渲染加判断是否存在就行了
<view class="pic">
<image v-if="item.picUrls && item.picUrls.length" :src="item.picUrls[0]" mode="aspectFill"></image>
<image v-else mode="aspectFill" src="../../static/image/nopic.jpg"></image>
</view>
(6)在详情页上对图片进行渲染
定义详情页样式,判断是否有图片,如果有图片进行渲染,因为是点击此携带id,根据id查询到数据进行返回
<view class="picurls" v-if="detail.picUrls && detail.picUrls.length">
<image v-for="item in detail.picUrls" :src="item" mode="widthFix"></image>
</view>
(7)修复点击修改图片覆盖问题
上传图片的话,图片都上传到imageValue里面去了,不管新的图片还是旧的图片,会把原来的图片覆盖掉,需要在修改页面(EditArticle.vue)进行对图片进行数组循环拿到它,并重新传给后端云函数服务器
onSubmit(e) {
// 上传图片的话,图片都上传到imageValue里面去了,不管新的图片还是旧的图片
let _picUrls = this.imageValue.map(item => {
return item.url
})
uniCloud.callFunction({
name: "eidtArticleRow",
data: {
detail: this.formValue,
picUrls: _picUrls
}
}).then(res => {
uni.showToast({
title: "修改成功"
})
setTimeout(() => {
uni.navigateBack()
}, 800)
})
}
(8)表单的输入框对按钮是否禁用的各软件禁用问题兼容
案例
Object.keys(obj)
参数:要返回其枚举自身属性的对象
返回值:一个表示给定对象的所有可枚举属性的字符串数组
在实际开发中,我们有时需要知道对象的所有属性;
ES5 引入了Object.keys方法,成员是参数对象自身的(不含继承的)所有可遍历( enumerable )属性的键名。
textObject(){
let person = {name:"张三",age:25,address:"深圳",getName:function(){}}
// Object.keys(person) 输出的是 ["name","age","address","getName"]
Object.keys(person).map((key)=>{
// console.log(key); //输出的是 name age address getName
person[key] // 获取到属性对应的值,做一些处理
console.log(person[key]); // 输出的是张三 25 深圳 f getName() {}
})
},
实际解决问题
解决添加和修改的按钮禁用问题
<view class="item">
<button form-type="reset" class="reset">重置</button>
<button form-type="submit" type="primary" :disabled="inDisable(formValue)">提交</button>
</view>
//表单验证,判断是否有一项没输
inDisable(obj) {
// for (let key in obj) {
// if (!obj[key]) { //若都不为空,则把disable的值改为true
// return true;
// }
// }
// Object.keys(obj)枚举formValue里面的所有对象,some查询是否满足obj[key] == ''为空的条件
// 若为空,则返回true,当都不为空时,返回的是false给bool,最后把false的值给到disable(是否禁用),false不禁用
let bool = Object.keys(obj).some((key,value) =>{
return obj[key] == ''
})
return bool
},
五、对项目进行打包
(1)uniCloud打包H5配置
1、对项目建的本地云函数进行上传
2、在manifest.json里面进行配置 ——WEB配置
①页面标题配置——你想要的标题
②路由模式——选择hash
③运行的基础路径—— ./
3、选择发行
网站-PC WEB或手机H5(仅适用于uni-app)——>跳转到一个弹框——>网站标题(你想要的标题)——>网站域名(你自己想要的域名)——>点击发行——>控制台会显示发布H5,需要在uniCloud web控制台操作,绑定安全域名,否则会因为跨域问题而无法访问。教程参考:https://uniapp.dcloud.net.cn/uniCloud/publish.html#useinh5——>点击网址——>点击什么是uniCloud——>uniCloud的web控制台地址:https://unicloud.dcloud.net.cn——>点击进去uniCloud web控制台进行登录——>点击跨域配置——>新增域名(输入你想要的域名:www.zixun98.com)——>项目打包完毕在unpackage/dist/build/h5下就可以看到打包好的文件——>打开vscode把打包好的h5文件夹放到vscode中——>打开文件之后启动open with Live Server(没有插件的话安装Live Server插件)——>启动之后就可以在index.html里面查看打包好的项目了
(2)利用服务器的前端网页托管来进行打包
选择阿里云服务器的前端网页托管——>上传打包好的h5文件夹(可以自己定义)——>参数配置——>把默认域名进行复制(需进行跨域配置)——>跨域配置(新增域名)——>把复制的默认域名添加进去就可以访问了
如果域名太长的话,可以找到二维码生成工具(草料二维码),把域名复制上去就得到二维码访问
如果想修改域名的话得去阿里云购买域名
(3)微信小程序打包项目
在manifest.json中的微信小程序配置——>微信小程序AppID(请在微信开发者工具中申请获取)——>获取AppID(在小程序中找到管理-开发管理-开发设置-AppID(小程序ID))进行复制——>粘贴到微信小程序配置里的-微信小程序AppID中——>显示(dev下的mp-weixin)打包成功——>数据出不来需要进行合法域名的配置——>需要配置两个合法域名的配置(request、uploadFile)——>每个报错的合法域名前面都会提示需要配置哪个——>把提示的合法域名复制——>详情——>项目配置——>在小程序中管理-开发管理-开发设置下找到服务器域名修改进行配置——>把提示的合法域名复制到(request合法域名、uploadFile合法域名中)——>在微信小程序中点击上传——>输入版本号——>点击上传
(4)App打包
manifest.json中——>App图标配置——>选择想要的图标(再点击自动生成所有图标并替换)——>发行——>原生App-云打包