总结所学
uni.getSystemInfoSync //同步获取设备信息
// #ifndef APP-PLUS||H5 //h5不会编译下面这段话
let menuButton = uni.getMenuButtonBoundingClientRect();//获取微信胶囊信息
插件icons
scoll-view组件
引用数据库 const db = uniCloud.database()
使用get,拿到数据。返回给客户端
await db.collection('user').doc(user_id).get()
客户端调用云函数
uniCloud.callFunction{name,data:dataObj}
封装数据请求
需求:this.$api.云函数名({参数}).then
封装顺序 云函数=》$http=>call_function.js=>call_list=>mian $api
field
能筛选请求结果。flase:不要 true:只要
const res= await db.collection('article').field({
content:false
}).get()
聚合 比更加强大
db.collection('article').aggregate().martch({}).project({}).end()
//martch:只选取有该字段的数据块 clasify:前端开发
//project 与field一样
// 加载更多功能
.skip(pagesize*(page-1)) //跳过多少数据,在客户端page每次都+1
.limit(pagesize) //限制多少数据
懒加载数据,给数据加缓存。
插件:loadmore
5,因为vue特新,往listCindexatchData里面加的是[],引用类型,并不会触发响应式。
这时需要用$set
:通知页面,数组或对象发生了变化,要求刷新页面
this.$set
(‘要改变的数组或对象’,key或index,要修改的内容)
this.$forceUpdata()//强制更新
const cmd = db.command command为数据库操作符
let dbCom=null
if (art_likes_ids.includes(article_id)) {
dbCom= cmd.pull(article_id)
}
else {
dbCom= cmd.addToSet(article_id)
}
await db.collection('user').doc(_id).update({
article_likes_ids:dbCom //为article_likes_ids添加和删除数据
})
通过**upload**
更改指定数据
定义聚合的操作符
const $ = db.commamnd.aggregete
添加字段
.addFields({
is_like:$.in(['$_id',art_likes_ids])//添加字段,诺_id在art_likes_ids中存在返回ture
})
加提示
uni.showLoading()
uni.hideLoading()
uni.showToast({
title:
icon:
})
input框发送请求,需添加个延时
搜索功能,匹配题目与val’相关的数据
.match({
title:new RegExp(val) //正则
})
-
- uni.navgateTo :打开新页面自己不关闭 - navback:返回之前的页面,如果之前没有进入过主页,那么也返回不回去 - uni.switchTab:可以
把历史存放到本地
histroy:uni.getStorageSync('histroy')||[] //存在是获取,不存在给个[]
set
remove
添加字段
addFelds({
current :$.in(['$_id',$.ifNull([userInfo.label_ids,[]])])
//ifNull:当第一项为空,则给个空数组
//$_id:当前项的_id,相当于遍历
//_id是否存于在用户的labelids,存在返回true,不存在为false
})
aspectFill
:保持纵横比缩放图片,只保证图片的短边能完全显示出来
内容预加载navgatato
要把数据转化成String,通过url传递。
"...?params="+JSON.stringfy()//传参注意长度
:固定定位要加背景颜色的
bug:给icons添加阻止冒泡会报stopPropagation
未定义的错:解决:将事件给父元 素
富文本插件 u-parser
弹出插件popup
await db.collection('article').doc(artcle_id).update({
comments:dbCmd.unshift(commentObj)//把数据放进comments里第一个
})
.unwind('$comments') //拆分
.replace('$comments') // 将comments作为根节点
bug:当设置flex-diraction:column
, 元素依然时block元素,为了让容器包裹字体,要给字体在报裹一层,把外面那层设置成flex
使用递归组件
在data外面,需要添加一个name值,与组件名一样
name="comment"
基础知识
条件编译
#ifdef H5 || MP-WEXIN
#endif
css方面
page: 等同body
使用单位: px, rpx(响应式 屏幕宽 = 750rpx) , rem ,vh,vw
建议flex布局
生命周期
应用生命周期
onLauch , onshow , onhide
页面生命周期
onload: 监听页面加载
onready : 页面加载完成
onshow: 页面页面显示
onhide : 隐藏
onUnload : 页面卸载
组件生命周期
beforecreated : 实例初始化后调用
created:实例创建完成
beforemounted : 挂载开始之前被调用
mounted: 挂载到实例上被调用
beforeUpdata: 数据更新时调用 , 虚拟dom打补丁之前
updata:由改变data造成 虚拟dom打补丁重新渲染 . 这之后被调用
beforedetory:实例销毁之前被调用
destory : 销毁调用, 调用后, vue实例指示的所有东西都会解绑, 事件监听器都会被移除, 所有的子实例也会被消除
项目
首页功能
easyCom:可以不用引入组件就能使用,要目录名与组件名相同
小bug:一开始没有给view加宽,默认宽是100%。当加上position:flex时,会缩小到内容的宽度
动态的style(数据绑定),要加{}
导航栏:小程序调试
1,给个高度占位,对顶部状态栏
2,不同设备的状态栏高度不一样,用
`uni.getSystemInfoSync //同步获取设备信息`
3,动态获取导航栏高度,获取微信胶囊的位置。
bottm:胶囊的底部到屏幕顶端的距离。top:胶囊顶部到屏幕顶端的距离。
那么=》
状态栏高度= (bottom - 状态栏高度)+(top-状态栏高度)
bug:内联式style里,margin-right要加双引号,才不报错。{}里的规范
// #ifndef APP-PLUS||H5 //h5不会编译下面这段话
let menuButton = uni.getMenuButtonBoundingClientRect();
console.log(menuButton);
this.navHeight = menuButton.bottom - this.statusBarHeight + (menuButton.top - this.statusBarHeight);
this.marginSearch = menuButton.width;
// #endif
4,h5无端没胶囊API,会报错。=》条件编译
字体图标
安装使用hbuild里的插件icons
tab栏
使用scoll-view组件。
bug:scoll-view里,别直接写item,外面套一层。 item上写flex没有用,不知道为什么
初始化tab栏中的数据
1,创建云函数
2,引用数据库 const db = uniCloud.database()
3,使用get,拿到数据。返回给客户端
await db.collection('user').doc(user_id).get()
4,客户端调用云函数
uniCloud.callFunction{参数}
5,接受到的数据,传给子组件
封装数据请求
- 再common里创建这个封装函数,里面返回个promise对象,把原始请求函数丢进去。
- export 导出这个函数再main.js中引入,绑定再实例上,即可在组件中使用为方便维护,把export defalt的内容单独弄在另一个js文件中,原来的全部用export 单个导出。
- 从代码量并没有得到改变,pormise重复使用,再把返回的promise封装成$http函数
- 每增加一个云函数请求,都要在list里面添加导入导出很麻烦。=》批量导出 require.context(目录相对路径,是否查询子目录,查询文件后缀) 。.keys可取到
bug:export导出已经声明的变量时,要加{};而export defaut不用加,然而 export 依然出错,还是export default吧
export {module}//然而 export 依然出错,还是export default吧
// export default module
选项卡切换
每个添加点击事件,把index传给函数,添加activeIndex,activeIndex=index
添加:
<view :class="index===active_index ? 'activeStyle' : '' " @click="showActive(index)" v-for="(item,index) in labelData"
class="scroll-view-item_H">{{item.name}}</view>
卡片视图实现
下方添加scroll,实现样式,封装组件,添加插槽,加上card 完全看不懂 在不懂页面布局时,可以给每个元素加个大点的边框
添加card,里面加img,标题,内容
大bug:全写英文竟然直接撑开盒子,不换行
多行文本溢出显示代码
.box {
width: 100px;
display: -webkit-box;
-webkit-line-clamp: 2;
-webkit-box-orient: vertical;
overflow: hidden;
}
多图模式
1,复制一份单独,把标题放图片上面
2.,新建个类,写多模模式的样式,层叠掉单独模式的
3,创建大图模式
4,v-if,不同模式下显示不同的结构。模式由父组件传进来
bug:图片外需加个div,不然会出现样式冲突
实现内容切换,swiper
选项卡与内容联动
1,利用$emit,实现父子传值
2,swiper的current属性和chengr事件
获取数据渲染
field能筛选请求结果。flase:不要 true:只要
const res= await db.collection(‘article’).field({
content:false
}).get()
数据分类
1,切换tab,触发change事件,将当前tab的name,传递给云函数,进行筛选聚合
.aggregate().martch({}).project({}).end()
//martch:只选取有该字段的数据块 clasify:前端开发
//project 与field一样
bug:调用云函数传参数,要用{}包裹
懒加载数据,给数据加缓存。
(以前是把数据赋值给单个的数组拿去渲染,每次赋值新值都是覆盖以前的旧值,导致页面滑动到下个页面会直接显示上个页面的值,过一会才刷新)(加缓存的目的是把一个数组变成多个数组,每个页面对应一个数组)
1,data里声明个listCatchData:{}
2,去掉list赋值,改成listCatchData。通过curent进行缓存,在geiList传进来
3.tab值可能来不及拿到,因为在create里调用,而在父组件请求数据。加个监听
4,改下结构中的 :list=‘listCindexatchData[index]’
5,因为vue特新,往listCindexatchData里面加的是[],引用类型,并不会触发响应式。
这时需要用$set
:通知页面,数组或对象发生了变化,要求刷新页面
this.$set
(‘要改变的数组或对象’,key或index,要修改的内容)
处理遗留问题
添加全部
1.给tab添加个“全部”,
2,把‘全部传递到云函数,对数据进行过滤’
每次滑动都会请求数据。以经加载过的数据就不要请求了
在change
中加个if
下拉加载更多
1,下载插件:loadmore
结构赋值的一种写法,给默认值
const {
a,
b=2 //如果’…‘中没有b,则默认为2
} = …
2,给云函数添加,page,pagesize。
.skip(pagesize*(page-1)) //跳过多少数据,在客户端page每次都+1
.limit(pagesize) //限制多少数据
3.给scroll,添加底部事件
4,定义page,pagesize,触发底部事件page++,调用云函数
5,客户端接收数据时,赋值覆盖掉了老数据。应该push到老数据后面。 listcatchdata一开始没有值,所以在后加个 || [] ,或者空数组
let oldres = this.listCatchData[current] || []
oldres.push(…res)
6,这时候渲染的数据还是有问题,原因在page,当切换tab时需要将page重置,但这样依然会有问题。会好时想上面一样加个缓存loading,把多个数组存在{}对象里面。首次获取数据,需要初始化loading。
bug: {}:并不是falsely
’‘、0 、undefined是falsely
7,处理loading,当返回数据为0时,再次向上面的思路,通过 s e t 重 新 赋 值 , 为 每 个 页 面 设 置 ’ n o m o r e ‘ 。 / / t h i s . l o a d [ c u r r e n t ] . l o a d i n g = ′ n o m o r e ′ 直 接 这 中 赋 值 也 可 以 , 但 不 能 加 r e t r u n , 需 要 借 助 下 set重新赋值,为每个页面设置’nomore‘。 // this.load[current].loading='nomore' 直接这中赋值也可以,但不能加retrun,需要借助下 set重新赋值,为每个页面设置’nomore‘。//this.load[current].loading=′nomore′直接这中赋值也可以,但不能加retrun,需要借助下set
8,此处nomore还是加载不出来,遇到这情况,再set下,加上
this.$forceUpdata()//强制更新
9,有个bug,没有set page ,导致请求,page空的,又会重0开始请求到数据
10,当load==’nomore‘,应该不要再去请求数据了。需要把activeindex重新赋值下,因为一直没有同步。
11,一个问题,当文章小于5时,不会触发下拉刷新,也就不会改变loading。需要给loadding组件加个if,大于5或=0时才显示
bug:当重新进入相同页bug面,会再次获取数据。解决:再赋值时,加个if判断,诺该页面不是undefined,则return
不能用上面的,return。而是把请求数据放if里。思路要变通
// 当重新进入相同页面,会再次获取数据。解决:再赋值前,加个if判断,诺该页面不是undefined或list长度为0,则请求数据
if (!this.listCatchData[this.swcurrent]||this.listCatchData[this.swcurrent].length===0) {
this.getArtcle(this.swcurrent)
}
收藏功能
1,在评论右侧添加个icons
2,需要单独作成组件,不然每次点击都会去刷新整个页面,耗费性能
3,添加click事件,并阻止冒泡
4,添加个更新收藏的云函数,上传userid和atcleID
可以右键,点击配置参数,可以测试
5,通过upload更改指定数据,command为数据库操作符
cmd.addToSet(id) //把文章id添加到数组中
pull(id) //删除
6,需要拿到用户数据收藏文章的数组,通过include判断,是否包含id,没有则addToSet,有则pull。可用null作为中间件来传值
// 更新
let dbCom=null
if (useInfo.data[0].article_likes_ids.includes(article_likes_ids)) {
dbCom= cmd.pull(article_likes_ids)
}
else {
dbCom: cmd.addToSet(article_likes_ids)
}
await db.collection(‘user’).doc(_id).update({
article_likes_ids:dbCom
})
bug:不能把if写{}里面,因为里面只能写参数
7,请求云函数
8,红心切换
bug:里面得加单引号,type要动态绑定 :type=“is_heart ? ‘heart-filled’ : ‘heart’”
9,刷新了红心也就没了,这时要在云函数的返回数据追加一个is_red的字段。通过聚合里的 .addFelds
10,定义聚合的操作符
const $ = db.commamnd.aggregete
11,获取用户数据,拿到收藏数组,需要添加参数id,运行配置中配置下参数,使用addFeleds,测试,
.addFields({
is_like:$.in(['$_id',art_likes_ids])//添加字段,诺_id在art_likes_ids中存在返回ture
})
12,所以的接口都要传userid,在$http里,顶一个{},里面加上id,把原来data解构在里面
13,客户端请求到islike赋值给本地
14,加提示:
uni.showLoading()
uni.hideLoading()
uni.showToast({
title:
icon:
})
2搜索页功能
搜索页导航栏修改
1,在pages新建页面,点击搜索跳转到该页面,去掉原始导航,把navbar写上去
2,需要区分下navbar在两个界面的不同样式,传一个bool值,用v-if,在不同页面展示不同的navbar
3,写下面的搜索内容样式
在page加flex ,是要把内容撑开,跟加100%是一个意思
4,添加没有搜索历史,v-if,当数据为空显示
5,导入vuex,引入vue和vuex
6,点击添加历史记录,就加个一条
7, 添加搜索结果,只有input不为空时才显示,添加list组件
bug:scoll出现显示异常,在.home_list上加和overflow:hidden得到解决
8,onload和输入时和请求数据,此时是page页面
9,每次输入都会发送请求,需添加个延时
// 添加延时
if(!this.flag){ //开始为定义,flag为undefined
this.flag=true //下面的定时器没结束前,就进不来if
setTimeout(()=>{
this.getArtcle(val)
this.flag=false
},1000)
}
10,建立搜索云函数,只需加个match,new个正则
11,点击内容,保存搜索记录。点搜索记录,能搜索。这里用到组件间的双向数据绑定
在调用的子组件上,不可写@click,会被以为是自定义函数
12,添加没有搜索到相关数据
13,loading
搜索历史数据持久化
1,返回首页
-
-
-
- uni.navgateTo :打开新页面自己不关闭
- navback:返回之前的页面,如果之前没有进入过主页,那么也返回不回去
- uni.switchTab:可以
-
-
2,清空历史
3,把历史放到本地缓存
bug:getStorage默认为异步,要改成同步,不然会报错
histroy:uni.getStorageSync('histroy')||[] //存在是获取,不存在给个[]
set
remove
3.标签管理页面布局
1,创建页面
2,获取标签数据
1使用聚合。添加用户表.。主要是看label表的个id,是否存于在用户的labelids。因为一开始没有labelids,所以全为false
2给label添加字段
addFelds({
current :$.in(['$_id',$.ifNull([userInfo.label_ids,[]])])
//ifNull:当第一项为空,则给个空数组
//$_id:当前项的_id,相当于遍历
//_id是否存于在用户的labelids,存在返回true,不存在为false
})
3,返回指定的label项,前端传一个type,如果为all返回所以label,否则返回current为true的
.match({
current:true
})
3.编辑标签页
1.编辑和完成要切换,所以要加个中间变量isedit
2.获取数据渲染
3.切换编辑完成
4.标签上移下移
4.上传标签页数据
1.核心思路,主要时根据labeid由没有再ids里面,所以只要拿到“我的标签”里的所有id就行
2。创建云函数,接收一个labelid数组,利用updaat跟新数据的数据
3,用户点击完成时,触发调用云函数
4,加个loading
5,自定义事件来同步
uni.$emit()
4.详情页
1,界面实现
只有给了图片宽高的时候才由这种mode,给图片宽高100%也是给了宽高,跟父元素一样罢 了aspectFill:保持纵横比缩放图片,只保证图片的短边能完全显示出来
2,内容预加载
1,因为在首页已经拿到了一部分数据,为了性能,直接把则部分数据给详情页用
2,要把数据转化成String,通过url传递。
"...?params="+JSON.stringfy()//传参注意长度
3,直接在onload()能接受到数据,再用JSON.parse转回格式
3,详情数据初始化
1,添加云函数,需要添加字段addFields,是否关注,是否收藏,是否点赞
bug:固定定位要加背景颜色的
bug:给icons添加阻止冒泡会报stopPropagation
未定义的错:解决:将事件给父元 素
:{'[$_id',kkk]}
match({
_id:artcleId //只匹配该id的文章数据
})
.project({
不要评论
})
2,添加个富文本插件 u-parser
3,添加个弹出插件popup
5.评论
1,创建提交评论的云函数,里面包含很多字段,用updata来提交,不能再云函数里面直接获取时间,拿到作者信息通过user表,提交到article中;需要添加随机id和时间搓
await db.collection('article').doc(artcle_id).update({
comments:dbCmd.unshift(commentObj)//把数据放进comments里第一个
})
2,客户端提交数据,写好样式
3请求评论。因为请求到的数据里多了个comments字段,需要切割,再把comments做成根节点,相当于把comments变成data
bug:总忘记加await,直接return res
可以, 但加了{}
就返回的空数据了
.unwind('$comments') //拆分
.replace('$comments') // 将comments作为根节点
4渲染数据
5回复
1,添加回复按钮和回复区域,回复区域就根评论是一样的,这边就自己调用自己的组件,用v-for判断回复数,不然会陷入死循环
bug:当设置flex-diraction:column , 元素依然时block元素,为了让容器包裹字体,要给字体在报裹一层,把外面那层设置成flex
2,定义事件,拿到评论id,传给云函数,2个参数:文章id 评论id
3,云函数分两种逻辑:1,评论id===“,就是评论,把回复内容设为[]以防万一 2,没有则是回复
4,获取该文章的所有评论,,
5.获取评论索引 。根据id, 拿到索引是为了下面更新 索引对应的评论
findIndex(item=> item.commentid = commentid)
6.获取作者信息,得到作者名,是为让客户端知道回复给谁
find(item=> item.commentid = commentid)
name=info....
7,为了知道回复的是哪条评论,然后在要上传的obj中加个to=作者名
,
8,更新回复信息: 其实就是根据索引,跟新了改变了的回复数组,在upload整个评论
obj={ //跟新数组对象的一种方式
[index]:{
replys:dbCmd.unshift(obj) //把添加了to的obj传给replys数组
}
}
uplaod(obj) //更新该评论
相当于 跟新数组 obj = {
arr:[{name;1},{name:2}]
}
updata({
arr:{
0:{
name:3
}
}
})
bug:当实在找不出bug,给全问都上个注释看看,记得单词写正确单词,少写了个字母会死人
9,使用递归组件,在data外面,需要添加一个name值,与组件名一样
name="comment"
10,点击发布,刷新页面,重新请求下评论ps
11,回复”回复“,
1,因为评论和回复都是同一个组件,所以要区分是点击了谁的回复按钮。所以,给回复组件加个:reply=true
,在评论组件props
里填个 reply{default:false }
,这样父组件detail那边就不要写个:reply=false
了,因为默认为false
2,给回复按钮的click事件,跟换参数,把reply加进({compopents,is_reply:reply})
,这样就知道点击的是哪个回复按钮了
3,判断主回复和子回复:评论里有一个coments_id,回复则因该有两个id,1是评论id coments_id; 2是 回复id reply_id
if(comment.is_reply){
//改个名字,改成reply_id
comment.comments.reply_id = comment.comments.comment_id
//上级的评论id
comment.comments.comment_id=this.item.comment_id
}
4,回到更新评论函数,如果reply为true,要添加一个reply_id和is_reply的字段,测试一下,点主回复一个id,子回复2个id
5,处理云函数,里面多加两个参数reply_id和is_reply,通过is_reply判断主回复和子回复,子回复拿到子回复的作者信息,主回复拿到主回复的作者信息
//回复给谁 拿到索引是为了下面更新 索引对应的评论
const index = comments.findIndex((item) => item.comment_id === comment_id)
// 子
if(is_reply){
// 拿到此条回复的作者名
const commemt =comments[index].replys.find((item) => item.comment_id === reply_id)
}else{
// 主
// 拿到此条评论的作者名
const commemt = comments.find((item) => item.comment_id === comment_id)
}
const commemner_name = commemt.commenter.name
// 添加字段 被回复的名字
commentObj.to = commemner_name
6加个回复样式,当reply为true,v-if和v-else
7上传成功后要清空form,不然发布也会变成回复