https://uniapp.dcloud.io/
HbuiderX
vue-cli
的方式运行项目vue create -p dcloudio/uni-preset-vue test-uniapp
问题:为什么data不建议用对象格式?
注意:
注意事项:
easyCom
,若组件的命名方式是:components/组件名/组件名.vue
,就不需要引用和注册,直接使用即可uni.scss
中,即设置某个变量代替:$mk-base-color:#f07373
注意事项:
"pages": [ //pages数组中第一项表示应用启动页,参考:https://uniapp.dcloud.io/collocation/pages
{
"path": "pages/tabbar/index/index",
"style": {
//导航栏的样式 custom取消默认的导航栏
"navigationStyle":"custom",
//字体颜色为白色
"navigationBarTextStyle":"white",
"navigationBarTitleText": "uni-app"
}
}
scroll-view
可滚动视图区域,用于区域滚动
滚动视图
//获取数据库的引用
const db = uniCloud.database()
requireApi
实现文件批量导出// 批量导出文件
const requireApi = require.context(
//api 目录的相对路径
'.',
//是否查询子目录
false,
//查询文件的一个后缀
/.js$/
)
let module = {}
requireApi.keys().forEach((key,index)=>{
// 去掉index.js
if(key === './index.js') return
Object.assign(module,requireApi(key))
})
export default module
swiper-item
实现页面左右上下滚动,注意高度撑开change
事件监听swiper
,关注返回内容中detail
属性emit
完成组件中的传值swiper
中属性current
可选择当前跳转的哪个页面const db = uniCloud.database()
exports.main = async (event, context) => {
//event为客户端上传的参数
// 获取数据
const list = await db.collection('article')
.field({
//过滤掉content内容 true:表示只返回该字段 FALSE:不返回
content:false
})
.get()
//返回数据给客户端
return {
code:200,
msg:'数据请求成功',
data:list.data
}
};
exports.main = async (event, context) => {
//event为客户端上传的参数
const list = await db.collection('article')
//获取数据库集合的聚合操作实例
.aggregate()
//根据条件过滤文档,并且把符合条件的文档传递给下一个流水线阶段。
.match({ //匹配类别为前端开发的文章
classify:'前端开发'
})
//把指定的字段传递给下一个流水线,指定的字段可以是某个已经存在的字段,也可以是计算出来的新字段。
.project({
//类似field 不需要接收content false 或0
content:false
})
//标志聚合操作定义完成,发起实际聚合操作
.end()
//当数据不存在或者长度是0的情况下, 才去请求数据
if(!this.listCatchData[current] || this.listCatchData[current].length === 0){
this.getList(current)
}
loadmore
插件//loading:正在加载
//noMore:没有更多数据
//状态需要进行判断
<uni-load-more iconType="snow" status="loading"></uni-load-more>
pageSize
//指定一个正整数,跳过对应数量的文档,输出剩下的文档
.skip(pageSize * (page - 1))
//指定查询结果集数量上限
.limit(pageSize)
@scrolltolower=“”
:滑动到底部/右边会触发//heart-filled:爱心填充
<uni-icons size="20" color="#f07373" type="heart"></uni-icons>
user
数据表中属性article_like_ids
const db = uniCloud.database();
const dbCmd = db.command;
exports.main = async (event, context) => {
//event为客户端上传的参数
const {
user_id,
article_id
} = event;
const userinfo = await db.collection('user').doc(user_id).get();
const article_likes_ids = userinfo.data[0].article_likes_ids;
let dbCmdFun = null;
if (article_likes_ids.includes(article_id)) {
//删除
dbCmdFun = dbCmd.pull(article_id);
} else {
//添加
dbCmdFun = dbCmd.addToSet(article_id);
}
await db.collection('user').doc(user_id).update({
article_likes_ids: dbCmdFun
})
//返回数据给客户端
return {
code: 200,
msg: '数据请求成功',
data: userinfo.data[0]
}
};
写完api文件引入
//设置聚合的操作符
const $ = db.command.aggregate
//追加字段
.addField({
//$.in() 当前某个数组是否包含某个字段
is_like:$.in(['$_id',article_likes_ids])
})
uni.showLoading、uni.hideLoading、uni.showToast
实现收藏提示语"navigationStyle": "custom"
.match({
title: new RegExp(value)
})
uni.switchTab
uni-icons type="clear"
emit
触发,on
监听回调type="compose"
type="chat"
:type="formData.is_like?'heart-filled':'heart'"
:type="formData.is_thumbs_up?'hand-thumbsup-filled':'hand-thumbsup'"
position:fixed
url
进行参数的传递,通过JSON.stringify
将对象转换为字符串形式(因为URL必须传递字符串)// 为了点击文章详情进行的预加载
const params = {
_id: item._id,
title: item.title,
author: item.author,
create_time: item.create_time,
thumbs_up_count: item.thumbs_up_count,
browse_count: item.browse_count
}
// 点击文章跳转到文章详情页面
uni.navigateTo({
url: '/pages/detail/detail?params='+JSON.stringify(params)
})
home-detail
的生命周期onLoad()
JSON.parse()
将其转换成对象形式 onLoad(query) {
this.formData = JSON.parse(query.params);
this.getDetail();
this.getComment();
}
$.in([a,b])
:判断b中是否包含a字段// 手动添加三个字段
let list = await db.collection('article').aggregate().addFields({
// 是否关注作者
is_author_like: $.in(['$author.id', userinfo.author_likes_ids]),
// 是否收藏文章
is_like: $.in(['$_id', userinfo.article_likes_ids]),
// 是否点赞
is_thumbs_up: $.in(['$_id', userinfo.thumbs_up_article_ids])
})
match
进行筛选 现在查找的是所有的文章列表 只需要返回传入对应文章的信息 .match({
_id: article_id
})
project
拒绝返回评论字段.project({
comments: 0
})
<uparse :content="formData.content" :noData="noData"></uparse>
noData: '详情加载中...
'
App.vue
中加载插件中的样式/*每个页面公共css */
@import url("/components/gaoyia-parse/parse.css");
解析富文本,缺点是代码构建会复杂uni-popup
插件实现评论弹出框,该插件依赖uni-transition
组件 //ref:弹出框 type:底部弹出 maskClick:点击蒙版是否取消弹窗
<uni-popup ref="popup" type="bottom" :maskClick="false">
display: flex;justify-content: space-between;
justify-content:flex-end
// 查询条件声明符
const dbCmd = db.command
const {
user_id, // 用户id
article_id, // 文章id
content, // 评论内容
comment_id = '', // 评论id
reply_id = "", // 子回复ID
is_reply = false // 是否子回复
} = event
let commentObj = {
comment_id: getID(5), //评论ID
comment_content: content, // 评论内容
create_time: new Date().getTime(), // 创建时间
is_reply: is_reply, // 区分主回复,还是子回复
author: {
author_id: user._id, // 作者id
author_name: user.author_name, // 作者名称
avatar: user.avatar, // 作者头像
professional: user.professional // 专业 前端工程师还是后端
},
reply: [],
}
获取时间戳的原因在于:云函数中处理的时间与实际时间有差距
function getID(length) {
return Number(Math.random().toString().substr(3, length) + Date.now()).toString(36)
}
方法 num.toString(base)
返回在给定 base 进制数字系统中 num 的字符串表示形式
await db.collection('article').doc(article_id).update({
comments: commentObj
})
.unwind()
筛选数据,请求评论内容const list = await db.collection('article').aggregate().match({
_id: article_id
})
.unwind('$comments')
.project({
_id: 0,
comments: 1
})
.replaceRoot({
newRoot: '$comments'
})
.skip(pageSize*(page-1))
.limit(pageSize)
.end()
<view class="comments-reply" v-for="item in comments.reply" :key="item.comment_id">
<comments-box :comments="item" :replys="true" @reply="reply"></comments-box>
</view>
replys: {
type: Boolean,
default: false
}
dbCmd.pull()
和dbCmd.addToSet()
实现取消关注和添加关注 let dbCmdFun = null;
if(author_likes_ids.includes(author_id)) {
// 取消关注
dbCmdFun = dbCmd.pull(author_id)
} else {
// 添加关注
dbCmdFun = dbCmd.addToSet(author_id)
}
await db.collection('user').doc(user_id).update({
author_likes_ids: dbCmdFun
})
uni.emit()
onReachBottom()
onReachBottom() {
//下拉没数据 不进行数据请求
if (this.loading === 'noMore') return;
this.page++;
this.getComment();
},
// 对象复制
let oldList = JSON.parse(JSON.stringify(this.commentList));
oldList.push(...data);
this.commentList = oldList;
utils
文件里面存放一些工具类filters
使用export const parceTime = (time) => {
const format = '{year}-{month}-{day} {hour}:{minute}:{second}'
let date = null;
if (typeof date === 'string') {
time = parseInt(date)
}
date = new Date(time)
const formatObj = {
year: date.getFullYear(),
month: date.getMonth() + 1,
day: date.getDate(),
hour: date.getHours(),
minute: date.getMinutes(),
second: date.getSeconds()
}
let strTime = format.replace(/{(year|month|day|hour|minute|second)+}/g, (res, key) => {
let val = formatObj[key];
if (res.length > 0 && val < 10) {
val = '0' + val;
}
return val;
})
return strTime;
}
//引入
import {parceTime } from '@/utils/index.js'
//使用
filters: {
dateFormat(time) {
return parceTime(time);
}
},
.tab-item:nth-child(1) {
border-right: 1px solid $theme-color;
}
swiper
实现文章和作者的左右滑动效果,高度要设置100%,不然滚动不了get_follow
,同样通过聚合筛选,获取收藏的文章列表数据filter
.header-background {
position: absolute;
top: 0;
right: 0;
bottom: 0;
left: 0;
opacity: 0.3;
filter: blur(8px);
image {
width: 100%;
height: 100%;
}
}
contact
<uni-icons class="icons" type="contact" size="16" color="#666"></uni-icons>
help
<uni-icons class="icons" type="help" size="16" color="#666"></uni-icons>
vuex
保存用户的相关信息,并本地存储uni.chooseImage()
,this的指向不是vue的实例,里面的回调要使用箭头函数uniCloud.uploadFile()
async submit(){
let imagesPath = []
uni.showLoading()
for(let i = 0;i < this.imgLists.length;i++){
const filePath = this.imgLists[i]
filePath = await this.upoadFiles(filePath)
imagesPath.push(filePath)
}
uni.hideLoading()
}
async upoadFiles(filePath){
consr result = await uniCloud.uploadFile({
filePath:filePath
})
return result.fileID
}
4. 点击云存储可以看到上传好的反馈图片
loadmore
加载到文章列表的上面- 原因:由于list-card渲染完全的时间比loadmore慢
<view class="">
<!-- 为了兼容小程序 包一个外壳 -->
<list-card :item="item" v-for="item in list" :key="item._id"></list-card>
</view>
- 原因:load.loading
为undefined
,由于第一次初始渲染的时候load未定义
:status="load.loading || 'loading'"
请求云函数错误:docId必须为字符串或数字
通过watch监听vuex中userinfo状态的变化,状态变更在请求接口
position:fixed
left:0
top:0
z-index:99
<view class="navbar-fixed">
<view class="navbar-search-icon">
</view>
<view class="navbar-search-text">
uni-app
</view>
<view style="height: 45px;"></view>
</view>
在created()生命周期中使用:
created() {
// /获取手机系统信息
const info= uni.getSystemInfoSync()
console.log(info)
// 设置状态栏的高度
this.statusBarHeight = info.statusBarHeight
}
通过API接口获取小程序胶囊的位置,然后计算高度
同时将宽度也调整好
// 获取胶囊的位置
const MenuButtonInfo = uni.getMenuButtonBoundingClientRect()
// (胶囊底部高度- 状态栏的高度) +. (胶囊顶部高度-.状态栏内的高度)
// =导航栏的高度
this.navBarHeight = (MenuButtonInfo.bottom - info.statusBarHeight) + (MenuButtonInfo.top - info
.statusBarHeight)
this.windowWidth = MenuButtonInfo.left;
注意:接口getMenuButtonBoundingClientRect
在H5、app、mp-alipay不支持
==解决:==利用ifndef
#ifndef H5 || APP-PLUS || MP-ALIPAY
// 获取胶囊的位置 h5不支持
const MenuButtonInfo = uni.getMenuButtonBoundingClientRect()
// (胶囊底部高度- 状态栏的高度) +. (胶囊顶部高度-.状态栏内的高度)
// =导航栏的高度
this.navBarHeight = (MenuButtonInfo.bottom - info.statusBarHeight) + (MenuButtonInfo.top - info
.statusBarHeight)
this.windowWidth = MenuButtonInfo.left;
#endif
this.$set(this.listCatchData, current, data)
监听数组变化@click.stop="likeTap"
if (!this.mark) {
this.mark = true;
this.timer = setTimeout(() => {
this.mark = false
this.getSearch(value)
}, 1000)
}
//state
historyList: uni.getStorageSync('_history') || []
//action 将数据保存在本地
uni.setStorageSync('_history', list)
//清除本地缓存
uni.removeStorageSync('_history')
数据库操作符
str.substr()
方法substring、substr
和 slice
str.slice(start [, end])
:返回字符串从 start 到(但不包括)end 的部分。str.substring(start [, end])
:返回字符串在 start 和 end 之间 的部分,允许 start 大于 endstr.substr(start [, length])
:返回字符串从 start 开始的给定 length 的部分