uniCloud——study

发布时间 2023-07-26 14:03:08作者: hongk

目录

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)
    })
}
// 输出的结果为

image-20230714103126954

(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、云数据库新建数据库、数据表

image-20230714201250643


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-云打包

image-20230726120747409