大纲目录
-
-
- 第1章 课程导学
- 第2章 倘想达到最高处,就要从低处开始 (uni-app 基础)
-
- 2-3 uni-app 核心知识点概览
- 2-4 搭建uni-app开发环境
- 2-5 语法速通-模板语法与数据绑定
- 2-6 语法速通-条件判断
- 2-7 语法速通-列表渲染
- 2-8 语法速通-基础组件
- 2-9 语法速通-自定义组件
- 2-10 语法速通-api与条件编译
- 2-11 生命周期概述
- 第3章 千里之行,始于足下 (基础配置)
-
- 3-1 uni-app 项目配置
- 3-2 目录结构概述
- 3-3 配置项目底部选项卡 – tabbar 配置
- 3-4 在uni-app中如何使用sass
- 第4章 工欲善其事,必先利其器 (uniCloud 的基础用法)
-
- 4-1 认识 uniCloud开发
- 4-2 HBuilderX 中配置 uniCloud 环境
- 4-3 使用 uniCloud web 控制台
- 4-4 开始使用云函数
- 4-5 云数据库的添加和删除
- 4-6 数据库的更新和查找
- 4-7 使用云储存上传文件
- 第5章 扬帆起航,胜利在向你招手 (首页功能模块)
-
- 5-1 项目初始化
- 5-2 自定义导航栏
- 5-3 导航栏适配小程序
- 5-4 使用字体图标
- 5-5 选项卡展示
- 5-6 选项卡数据初始化
- 5-7 封装数据请求
- 5-8 选项卡切换
- 5-9 基础卡片视图实现
- 5-10 更多卡片视图实现
- 5-11 实现内容切换
- 5-12 选项卡与内容联动
- 5-13 内容卡片数据初始化
- 5-14 切换选项卡懒加载数据
- 5-15 -1 上拉加载更多(上)
- 5-16 -2 上拉加载更多(下)
- 5-17 -1 收藏按钮实现(上 )
- 5-18 -2 收藏按钮实现(下)
- 第6章 做事是否快捷,不在一时奋发,而在能否持久(搜索页功能模块)
-
- 6-1 搜索页导航栏修改
- 6-2 使用vuex 管理历史记录
- 6-3 -1 搜索逻辑实现(上 )
- 6-4 -2 搜索逻辑实现(下)
- 6-5 搜索历史数据持久化
- 第7章 锲而不舍,金石可镂(标签页功能模块)
-
- 7-1 标签管理页布局样式
- 7-2 标签页数据处理
- 7-3 编辑标签页
- 7-4 保存标签页数据
- 7-5 使用自定义事件同步数据
- 第8章 坚持就是胜利,坚持才会有所成就(详情页功能模块)
-
- 8-1 详情页页面展示
- 8-2 内容预加载
- 8-3 详情页面数据初始化
- 8-4 富文本渲染
- 8-5 发布窗口展示
- 8-6 评论内容实现(1)
- 8-7 评论内容实现(2)
- 8-8 评论内容实现(3)
- 8-9 评论内容实现(4)
- 8-10 评论内容实现 (5)
- 8-11 评论内容实现(6)
- 8-11 评论内容实现(6)
- 8-12 关注作者(上)
- 8-13 关注作者(下)
- 8-14 文章的收藏与点赞(上)
- 8-15 文章的收藏和点赞(下)
- 8-16 评论列表(上)
- 8-16 评论列表(上)
- 8-17 评论列表(下)
- 第9章 关注页功能模块
-
- 9-1 关注页导航栏实现
- 9-2 收藏文章内容实现
- 9-3 收藏与首页内容关联
- 9-4 关注作者页面实现
- 9-5 同步关注作者页面数据
- 第10章 个人信息页功能模块
-
- 10-1 个人中心页面实现
- 10-2 个人中心数据处理
- 10-3 我的文章实现
- 10-4 问题反馈页面实现
- 10-5 反馈图片选择
- 10-6 上传图片
- 第11章 积少成多,走向完善(项目优化与平台兼容)
-
- 11-1 微信小程序优化与兼容
- 11-2 支付宝小程序优化与兼容
- 11-3 其他平台优化与兼容
- 第12章 最后的冲刺,成功就在眼前(项目发行与打包)
-
- 12-1 h5端发行打包
- 12-2 小程序端发行上传
- 12-3 App 端发行打包
- 第13章 常常是最后一把钥匙打开了门(课程总结与展望)
-
- 13-1 课程回顾与总结
-
第1章 课程导学
第2章 倘想达到最高处,就要从低处开始 (uni-app 基础)
2-3 uni-app 核心知识点概览
1 条件编译
条件编译写法 | 说明 |
---|---|
#ifdef APP-PLUS 需条件编译的代码 #endif |
仅出现在 App 平台下的代码 |
#ifndef H5 需条件编译的代码 #endif |
除了 H5 平台,其他平台均存在的代码 |
ifdef H5 || MP-WEIXIN 需条件编译的代码 #endif |
在 H5 平台或微信小程序平台存在的代码(这里只有|| , 不可能出现&& , 因为没有交集) |
2 App 端的 Nvue 开发
3 HTML5+
2-4 搭建uni-app开发环境
1 安装并运行HbuiderX
2 使用 vue-cli 的方式运行项目
- 检查 node.js 版本
node -v
#v14.15.4
npm install -g cnpm --registry=https://registry.npm.taobao.org
设置镜像然后再npm install -g @vue/cli
装到全局的环境中- 自己出现了报错的情况,需要先运行
sudo chown -R $USER /usr/local
之后再安装就好了. - 检查
vue-cli
是否安装vue --version
#2.9.6
- 进入目录
vue create -p dcloudio/uni-preset-vue test-uniapp
2-5 语法速通-模板语法与数据绑定
{{title}}
绑定变量
v-bind:class="className"
绑定class,可以简写为:class="className"
v-on:click="open"
绑定事件,可以简写为@click="open"
动态数据绑定
this.title = "hello"
这个和小程序中不同. 小程序中是this.setData({xx: 'XX'})
2-6 语法速通-条件判断
①
v-if
条件判断, 为真的时候,才渲染. 为false
则不渲染.
<view v-if="true">hello uni-app</view>
②
v-if
绑定变量, 为false
和0
的时候,不渲染
<view v-if="show">hello uni-app</view>
...
data() {return {show: false}
},
③
v-if
中可以接表达式例如v-if="show === 'hello'"
④
三元表达式
{{show ? 'hello' : 'world'}}
⑤
v-if
v-else-if
v-else
, 根据参数来识别,这2个view要紧挨着.v-else-if
可以省略.
<view v-if="show === 1">uni-app</view>
<view v-else-if="show === 2">vue</view>
<view v-else></view>
2-7 语法速通-列表渲染
①
v-for
通过一个数组来渲染我们的列表
<view v-for="(item,index) in arr" >{{item}}</view>
...
<script>return {arr : ['uni-app', 'vue', 'html']}
</script>
②
v-for
加上索引项index
写法如下
<view v-for="(item,index) in arr" >{{(index+1) + ' ' +item}}</view>
...
<script>return {arr : ['uni-app', 'vue', 'html']}
</script>
③
v-for
循环打印对象
<view v-for="(key,value) in arr" >{{key + ' ' +value}}</view>
...
<script>return {arr: {name: 'LiMing',age: 18,type: 'eat'}}
</script>
2-8 语法速通-基础组件
view
text
image
…
双向绑定
< input v-model="vlue" />
2-9 语法速通-自定义组件
① 在根目录中建立
components
文件夹, 再建立一个/btn/btn.vue
btn.vue
源码如下,可以自己定义样式,行为.
<template><view class="btn-box" @click="clickBox">点击</view>
</template><script>export default {methods: {clickBox() {console.log('click');}}}
</script><style>.btn-box {width: 200px;height: 100px;text-align: center;line-height: 100px;}
</style>
在需要的地方,进入,然后注册.
components
注册组件,然后就可以直接使用了.
<template><view class="content"><btn></btn></view>
</template><script>import btn from '@/components/btn/btn.vue'export default {components: {btn},}
</script>
② 给组件传值 关键词
props
, 然后标注参数类型.
- index.vue 中
<btn color="red"></btn>- 组件中,用 <template><view class="btn-box" :style="{color: color}">点击</view>
</template><script>export default {props: {color: {type: String,default: '#000'}}}
</script>
③ 页面上拿到组件中的返回值
index.vue
中注册监听事件
<btn color="red" @change="change"></btn>
...
methods: {change(e) {console.log("我是页面的事件,我返回了" + e);}
}
- 组件中,通过
$emit()
来返回. 接受2个参数, 第一个是index.vue
的监听函数,第二个是参数
methods: {clickBox() {console.log('click');this.$emit('change', this.color)}
}
- 如上2步,组件中,通过
$emit
把this.color
传给index.vue
的change
事件. 而change
中的e
就是组件中返回来的this.color
④ 组件插槽
<slot></slot>
- 在
index.vue
中,使用<btn color="red" @change="change">主页中的内容</btn>
这样的写法, 希望把文字也插入到组件中. - 在 组价中, 使用插槽
<slot></slot>
的方式来获取内容.
2-10 语法速通-api与条件编译
文档:
https://uniapp.dcloud.io/api/README
① api的一个演示
<script>export default {onLoad() {console.log(11);uni.getSystemInfo({success(res) {console.log("success", res);},fail(err) {console.log("error", err);},complete(res) {console.log("不管成功失败都会返回: ", res);}})},}
</script>
② 条件编译 用
#ifdef 平台标识符
来让代码在规定的平台里面编译.可以加上||
(或者).
<template><view class="content"><!-- #ifdef H5 || APP-PLUS --><button>我是一个按钮</button><!-- #endif --></view>
</template>
#ifndef
加了一个n
表示在后面的平台上面,不显示.
条件编译写法 | 说明 |
---|---|
#ifdef APP-PLUS 需条件编译的代码 #endif |
仅出现在 App 平台下的代码 |
#ifndef H5 需条件编译的代码 #endif |
除了 H5 平台,其他平台均存在的代码 |
ifdef H5 || MP-WEIXIN 需条件编译的代码 #endif |
在 H5 平台或微信小程序平台存在的代码(这里只有|| , 不可能出现&& , 因为没有交集) |
文档
https://uniapp.dcloud.io/platform?id=%e8%b7%a8%e7%ab%af%e5%85%bc%e5%ae%b9
③ 在
style
中使用 条件编译
<style>/* #ifdef H5 */.../* #endif */
</style>
④ 在
style
中,page
表示这个页面
⑤ 尺寸单位
px
%
rpx
rem
vh
vw
⑥ 引入外部 css 文件
@import '@/static/index.css'
2-11 生命周期概述
文档:
https://uniapp.dcloud.io/collocation/frame/lifecycle
① 生命周期的分类
-
应用生命周期, 在
App.vue
文件中onLaunch
应用初始化完成触发一次,全局只触发一次
onShow
应用启动的时候, 或者从后台进入前台会触发
onHide
应用从前台进入后台触发 -
页面生命周期
onLoad
监听页面加载
onShow
监听页面显示,每次切换到这个页面,都会执行
onReady
监听页面初次渲染完成 (如果渲染速度快, 会在页面进入动画完成前触发)
onHide
监听页面隐藏
onUnload
监听页面卸载,页面关闭 -
组件生命周期
beforeCreate
在实例初始化之后,数据观测(data observer) 和 event/watcher 事件配置之前被调用
created
实例创建完成之后立即调用, 挂载阶段还没有开始
mounted
挂载到实例上去之后调用
destroyed
vue 实例销毁后调用 -
大概顺序
App Launch
>App Show
>component beforeCreate
>component created
>page onload
>page onshow
>component mounted
>page onready
第3章 千里之行,始于足下 (基础配置)
3-1 uni-app 项目配置
① 微信小程序
微信小程序 -> 设置 -> 安全设置 -> 服务端口 -> 开启
HBuilderX -> 配置 -> 运行配置 -> 把微信开发者工具路径 配置 起来
② app真机,模拟器
连接安卓设备
- 打开usb调试
连接ios设备
- 运行 -> 选择 ios 设备
ios 模拟器
- 打开 xcode
- 偏好配置 -> 上面倒数第三个 Components -> 选择版本(例如 IOS 12.4 Simulator) 下载 -> 右下角 安装
- 重启 HBuilderX
- 运行 -> 模拟器
③ h5, 如果直接运行到浏览器失效的话,可以按照下面操作
- 设置 -> 运行配置 -> 浏览器运行配置 把相关浏览器路径配置好
3-2 目录结构概述
components
自定义组件的目录,自己创建的pages
页面存放目录static
静态文件资源目录unpackage
编译后的文件存放目录utils
公用的工具类,自己创建的common
公用的文件, 自己创建的App.vue
项目启动页main.js
应用入口,绑定全局变量,引用一些第三方库等manifest.json
项目配置page.json
页面配置,页面地址,页面名称等 文档:https://uniapp.dcloud.io/collocation/pages
uni.scss
scss配置
3-3 配置项目底部选项卡 – tabbar 配置
pages.json
中的globalStyle
中的配置,是所有页面的通用配置.pages.json
中的pages
下面的配置,可以配置 单独终端(例如 微信小程序,h5,app等)的配置, 如下
{"pages": [ {"path": "pages/index/index","style": {"navigationBarTitleText": "uni-app","app-plus":{},"mp-weixin":{},"h5":{}}}],"globalStyle": {...}
}
tabbar
文档https://uniapp.dcloud.io/collocation/pages?id=tabbar
, 写法如下,注意图片的路径写法.
{"pages": [ //pages数组中第一项表示应用启动页,参考:https://uniapp.dcloud.io/collocation/pages...],"globalStyle": {...},"tabBar": {"color": "#666","selectedColor": "#ff5a5f","borderStyle": "black","list": [{"pagePath": "pages/index/index","text": "首页",// 本地图片, 大小 40kb, 尺寸建议 81*81px"iconPath": "static/home.png","selectedIconPath": "static/home-active.png"}, {"pagePath": "pages/about/about","text": "关于",// 本地图片, 大小 40kb, 尺寸建议 81*81px"iconPath": "static/follow.png","selectedIconPath": "static/follow-active.png"}, {"pagePath": "pages/my/my","text": "首页",// 本地图片, 大小 40kb, 尺寸建议 81*81px"iconPath": "static/my.png","selectedIconPath": "static/my-active.png"}]}
}
tabbar
会缓存每个页面,所以onLoad
只会隐藏,不会重新加载.tabbar
中有一个新的生命周期onTabItemTap(e)
, tabbar 点击就会触发, 这个e
返回例如{index: 0, text: "首页", pagePath: "pages/index/index"}
3-4 在uni-app中如何使用sass
- 如果第一次使用,需要安装sass插件
scss/sass编译
- sass 写法
<style lang="scss">
, 支持嵌套
写法,如下例
<style lang="scss">.content {display: flex;flex-direction: column;align-items: center;justify-content: center;.logo {height: 200rpx;width: 200rpx;margin-top: 200rpx;margin-left: auto;margin-right: auto;margin-bottom: 50rpx;}.text-area {display: flex;justify-content: center;.title {font-size: 36rpx;color: #8f8f94;}}}
</style>
- 使用变量
<style lang="scss">$width: 200rpx;....content{width: $width;...
</style>
- 使用父级
&.box
, 不能有空格,要接在一起写.
<style lang="scss">$width: 200rpx;.content {display: flex;// & 父级&.box {border:1px solid red;}
</style>
第4章 工欲善其事,必先利其器 (uniCloud 的基础用法)
4-1 认识 uniCloud开发
① 云函数 示例如下
'use strict';
exports.main = async (event, context) => {// event 为客户端上传的参数console.log('event:' + event)// 返回数据给客户端return event
};
② 云数据库 示例如下
'use strict'
//获取数据库引用
const db = uniCloud.database()
const collection = db.collection('user');// 伪代码
exports.main = async (event, context) => {//event 为客户端上传的参数console.log('event: ' + event)//将token写入数据库collection.where({name: event.data.name,password: event.data.password}).update({token: event.token,token_time: event.timestamp});// 获取用户信息const user_info = await collection.where({name: event.data.name}).get();// 返回数据给客户端return {code: 200,msg: '登录成功',data: user_info.data}
};
③ 云存储和CND
4-2 HBuilderX 中配置 uniCloud 环境
- 新建项目的时候, 勾选下方的,
启动uniCloud(全端可用的云开发,使用js开发服务器逻辑.)
- 之后 绑定我们的云空间
- 点击
manifest.json
文件,查看`uni-app应用标识(AppID), 如果为空要重新获取. - 在
uniCloud
文件夹下新建cloudfunctions
文件夹, 这个文件夹是存放云函数的, 可以点击新建云函数, 之后点击新建的云函数目录, 选择上传部署
. 就可以上传到后台.
4-3 使用 uniCloud web 控制台
- 右击
uniCloud
文件夹, 选择打开 uniCloud Web控制台...
, 就可以进入云开发控制台
4-4 开始使用云函数
①
云函数
运行在云端(服务器端)的函数
'use strict';
exports.main = async (event, context) => {//event为客户端上传的参数console.log('event : ', event)//返回数据给客户端return event
};
event
为客户端上传的参数content
包含了调用信息和运行状态, 获取每次调用的 上下文
②
uniCloud.callFunction
调用我们的云函数
...
methods: {open() {// 执行云函数uniCloud.callFunction({name: "get_list", //云函数的名字data: { // 参数name: 'Liming',age: 18},success(res) {console.log(res)},fail(err) {}})}
...
③ 在本地的
云函数
中如下return
返回,这个返回就是上面的success(res)
中的res
的值
'use strict';
exports.main = async (event, context) => {//event为客户端上传的参数console.log('event : ', event)//返回数据给客户端return {content: '成功'}
};
④ 注意: 如果修改了 本地的云函数,
一定要上传部署
,不然是不生效的.
4-5 云数据库的添加和删除
云数据库
的添加和删除, 只能在云函数
中运行
① 云函数中如何连接数据库
'use strict';
// 连接到数据库
const db = uniCloud.database()
exports.main = async (event, context) => {// 连接到 `user` 表const collection = db.collection('user')//返回数据给客户端return {}
};
const collection = db.collection('user')
// 连接到数据库const collection = db.collection('user')
// 连接到user
表
② 添加数据
add
方法
- 添加1条数据
let res = await collection.add({name: 'uni-app'
})
- 添加多条数据
let res = await collection.add([{name: 'vue'},{name: 'html',type: '前端'}
])
③ 删除数据
doc
选择数据 然后remove
删除
let res = await collection.doc('60092bbc6cb4fb0001f96b05').remove()
4-6 数据库的更新和查找
① 记录更新
doc
选择数据,update
或者set
2个方法使用是一样的,用来更新数据
//删除数据
let res = await collection.doc('60092bbc6cb4fb0001f96b04').update({name: 'html'
})
②
update
和set
d的区别
update
只能更新存在的记录.set
如果记录存在就更新, 如果不存在就添加.
③ 查找数据
get
where
- 查询一条数据,
doc
是查询条件,get
获取数据(并不是获取一条数据,是根据条件来获取,没有写条件就是获取全部)
let res = await collection.doc('60091e078976a900010cf515').get()
doc
只能根据id
来查询,where
可以根据条件来查询
let res = await collection.where({name: 'vue-test'
}).get()
④ 返回数据
//返回数据给客户端
return {code: 200,msg: '查询成功',data: res.data
}
⑤ 如何根据前端提交的参数来获取数据?
event
就是前端提交过来的数据,就可以根据这个数据来做筛选, 如下
let res = await collection.where({name: event.name
}).get()
4-7 使用云储存上传文件
① 上传文件
uniCloud.uploadFile
methods: {open() {// 图片上传apisuni.chooseImage({count: 1,success(res) {const tempFilePath = res.tempFilePaths[0]console.log(res)uniCloud.uploadFile({filePath: tempFilePath,cloudPath: res.tempFiles[0].name,success(res) {console.log(res);},fail(err) {console.log(err);}})},fail(err) {console.log(err);}})}
}
- 注意上面的
cloudPath
–使用阿里云时,cloudPath为云端文件名,请勿使用非法字符
- 文档:
https://uniapp.dcloud.io/uniCloud/storage?id=uploadfile
② 删除文件
uniCloud.deleteFile
阿里云不支持此API,前端运行此API会报权限错误
uniCloud.deleteFile({fileList:['59a0e604-79b9-4d58-9aae-53cc4eda7db5'],success(res) {console.log(res);},fail(err) {console.log(err);}
})
第5章 扬帆起航,胜利在向你招手 (首页功能模块)
5-1 项目初始化
①
db_init.json初始化数据库
位置:uniCloud
->database
->db_init.json
如果没有就自己新建
文档:https://uniapp.dcloud.io/uniCloud/hellodb?id=db-init
{"list": { // 集合(表名)"data": [ // 数据{"name": "tom"},{"name": "liming"}]}
}
- 写好之后,右键
初始化云数据库
, 控制台就可以看到这个数据已经同步到后台了 - 项目中, 提供了 这个文件,复制过来,然后重新
初始化云数据库
, 同步到后台.
5-2 自定义导航栏
1 取消原来的导航栏, 选用自定义导航栏
"navigationStyle":"custom",
{"pages": [ //pages数组中第一项表示应用启动页,参考:https://uniapp.dcloud.io/collocation/pages{"path": "pages/tabbar/index/index","style": {"navigationStyle":"custom",...}}
...
2 把导航栏作为一个新的自定义组件来操作, 在根目录下新建
components
, 然后再新建组件并创建同名目录navbar
3 在需要调用的页面,
import
导入,然后在components
中注册,之后就可以使用了. 但是在uni-app
中有一个简单的方法easyCom
easyCom
是局部引入, 在需要调用的文件中, 直接使用<narbar></narbar>
即可.
<template><view class="content"><!-- 自定义导航栏组件 --><navbar></navbar></view>
</template><script>export default {data() {return {title: 'Hello'}},}
</script>
- 如上代码, 并没有导入
navbar
,也没有在components
中注册,但是由于easyCom
的存在, 则可以直接使用.不会报错.
5-3 导航栏适配小程序
① 顶部状态栏高度的动态赋值
<view :style="{height: statusBarHeight+'px;'}"></view>
...
<script>//获取手机系统信息const info = uni.getSystemInfoSync();//设置状态栏高度this.statusBarHeight = info.statusBarHeight;
</script>
② 适配小程序和h5的解决方案
<template><view class="navbar"><view class="navbar-fixed"><!-- 状态栏 --><view :style="{height: statusBarHeight+'px'}"></view><!-- 导航栏内容 --><view class="navbar-content" :style="{height:navBarHeight+'px',width:windowWidth+'px'}"><view class="navbar-search"><view class="navbar-search_icon"><uni-icons type="search" size="16" color="#999"></uni-icons></view><view class="navbar-search_text">uni-app, vue</view></view></view></view><view :style="{height: statusBarHeight+navBarHeight+'px'}"></view></view>
</template><script>export default {data() {return {statusBarHeight: 20, //顶部状态栏的高度navBarHeight: 40,windowWidth: 375};},created() {//获取手机系统信息const info = uni.getSystemInfoSync();//设置状态栏高度this.statusBarHeight = info.statusBarHeight;this.windowWidth = info.windowWidth// h5 app mp-alipay// #ifndef H5 || APP-PLUS || MP-ALIPAY//获取微信右上角胶囊的位置const menuButtonInfo = uni.getMenuButtonBoundingClientRect()console.log(menuButtonInfo)// (胶囊底部高度 - 状态栏高度) + (胶囊顶部高度 - 状态栏内的高度) = 导航栏的高度this.navBarHeight = (menuButtonInfo.bottom - info.statusBarHeight) + (menuButtonInfo.top - info.statusBarHeight)this.windowWidth = menuButtonInfo.left// #endif}}
</script><style lang="scss">.navbar {.navbar-fixed {position: fixed;top: 0;left: 0;z-index: 99;width: 100%;background-color: $mk-base-color;.navbar-content {display: flex;justify-content: center;align-items: center;height: 45px;padding: 0 15px;box-sizing: border-box;.navbar-search {display: flex;align-items: center;padding: 0 10px;width: 100%;height: 30px;border-radius: 30px;background-color: #fff;.navbar-search_icon {margin-right: 10px;}.navbar-search_text {font-size: 12px;color: #999;}}}}}
</style>
5-4 使用字体图标
插件市场搜索
icons
然后下载到本地
-
引用
<uni-icons type="search" size="16" color="#999"></uni-icons>
-
文档:
https://hellouniapp.dcloud.net.cn/pages/extUI/icons/icons
5-5 选项卡展示
- 选项卡还是以
组件
的形式来写 scss
伪类写法
.tab-icons{position: relative;display: flex;justify-content: center;align-items: center;width: 45px;&::after{content: '';position: absolute;top: 12px;bottom: 12px;left: 0;width: 1px;background-color: #ddd;}
5-6 选项卡数据初始化
- 调用云函数, 且获取到返回信息. 注意这里的
const { result } = res;
和.then() 写法
methods: {getLabel() {// 调用云函数uniCloud.callFunction({name: 'get_label',}).then(res => {const { result } = res;this.tabList = result.data;})}
}
- 常用写法
// 调用云函数
uniCloud.callFunction({name: 'get_label',success(res) {console.log(res.result);},fail(err) {}
});
大概步骤
- 在
父页面
中, 获取数据, 然后赋给组件<tab :list="tabList"></tab>
- 在
组件
中, 通过props
注册一下. 这里是Array类型
<script>export default {props: {list: {type: Array,default () {return []}}},
...
- 之后,
组件
中就可以使用list
来做操作了.
5-7 封装数据请求
- 在根目录的
common
文件夹下面新建api
文件夹,再新建index.js
, 在其中封装一个 Promise(), 如下
const get_label = (data) => {return new Promise((reslove, reject) => {uniCloud.callFunction({name: 'get_label',data}).then(res => {if (res.code === 200) {// .thenreslove(res.result);} else {// catchreject(res.result);}}).catch(err => {reject(err);})})}export default {get_label
}
- 在
main.js
中,import
然后再赋值, 如下
import api from './common/api'
...
Vue.prototype.$api = api
- 在需要的地方调用这个方法
methods: {getLabel() {this.$api.get_label({name: 'get_label'}).then(res => {const {data} = res;this.tabList = data;})}
}
- 优化代码, 在
common/api
下新建list.js
文件, 把之前的 代码拷贝进入, 再export
出来
export const get_label = (data) => {return new Promise((reslove, reject) => {uniCloud.callFunction({name: 'get_label',data}).then(res => {if (res.result.code === 200) {// .thenreslove(res.result);} else {// catchreject(res.result);}}).catch(err => {reject(err);})})}
- 在
common/api
的index.js
中,修改代码如下, 这样每个代码分开管理.
import {get_label} from './list.js'export default {get_label
}
- 继续优化, 因为每个请求都要写
return Promise..
, 可以在common
文件夹下面 新进一个http.js
export default function $http(options) {const {url,data} = optionsreturn new Promise((reslove, reject) => {uniCloud.callFunction({name: url,data}).then(res => {if (res.result.code === 200) {// .thenreslove(res.result);} else {// catchreject(res.result);}}).catch(err => {reject(err);})})
}
- 将
common/api/list.js
中的内容优化如下
import $http from '../http.js'
export const get_label = (data) => {return $http({url: 'get_label',data})
}
export const get_list = (data) => {return $http({url: 'get_list',data})
}
- 如上,
list.js
优化完毕, 但是在其中每加入一个函数,都需要在index.js
中导入,然后注册. 如下,可以利用require.context
方法,实现自动导入, 之后, 在list.js
中写入新的函数,就不需要在index.js
中注册了, 已经自动帮我们注册了.之后直接写函数,直接调用即可.
//批量导出文件
const requireApi = require.context(// api 目录的相对路径'.',//是否查询子目录false,//查询文件的一个后缀/.js$/
)let module = {};
requireApi.keys().forEach((key, index) => {if (key === './index.js') return;console.log(key);Object.assign(module, requireApi(key));
})export default module
5-8 选项卡切换
-
加一个点击事件,绑定一个class
:class="{active:activeIndex === index}" @click="clickTab(item,index)"
-
把事件返回给 父页面
methods: {// 点击导航栏高亮clickTab(item, index) {this.activeIndex = index//把事件传递到父页面去this.$emit('tab', {data: item,index: index})}
}
- <tab :list=“tabList” @tab=“tab”> 绑定事件
tab
是自定义事件 - 在
methods
里面注册一下
tab(data, index) {console.log(data, index);
}
5-9 基础卡片视图实现
- 以组件的新式来实现,
5-10 更多卡片视图实现
- 在组件中,分别写3种模式(列表,大图,多图).
- 以插槽的形式,让父页面绝对调用谁
5-11 实现内容切换
- 拆分组件,例如
list
组件, 如下
<swiper-item><list-scroll class="list-scroll"><list-card mode="base"></list-card><list-card mode="image"></list-card><list-card mode="column"></list-card><list-card mode="column"></list-card><list-card mode="column"></list-card><list-card mode="column"></list-card></list-scroll></swiper-item>
- 在同级目录新建
list-item.vue
, 把中间的部分拿出来
<template><list-scroll class="list-scroll"><list-card mode="base"></list-card><list-card mode="image"></list-card><list-card mode="column"></list-card><list-card mode="column"></list-card><list-card mode="column"></list-card><list-card mode="column"></list-card></list-scroll>
</template><script></script><style lang="scss">.list-scroll {height: 100%;}
</style>
- 因为这个不符合
easyCom
的规范,所以需要重新导入,然后注册一下.如下
<template><swiper class="home-swiper"><swiper-item><list-item></list-item></swiper-item></swiper>
</template>
<script>import listItem from './list-item.vue'export default {components: {listItem},...
5-12 选项卡与内容联动
5-13 内容卡片数据初始化
5-14 切换选项卡懒加载数据
- 懒加载: 之前是每个页面刷新的时候, 获取数据,直接改变
data
的值,这样就会出现闪烁的情况. 解决方法,就是将每一页的数据,放到缓存数据中,例如数组中. 把每一页的数据加到这个数组中,则可以保证,加载的时候,不会出现闪烁的情况.
5-15 -1 上拉加载更多(上)
加载插件 loadmore
–LoadMore 加载更多 DCloudDCloud出品
- 文档:
https://ext.dcloud.net.cn/plugin?id=29
5-16 -2 上拉加载更多(下)
- 数据更新的操作
this.$set()
this.$forceUpdate()
this.$set(this.load, current, oldLoad)
// 强制渲染
this.$forceUpdate()
5-17 -1 收藏按钮实现(上 )
- 阻止事件冒泡
@click.native.stop
5-18 -2 收藏按钮实现(下)
- 加载框
uni.showLoading()
- 关闭加载框
uni.showLoading()
- 提示信息
uni.showToast({title: this.like ? '收藏成功' : '取消收藏',icon: 'none'
})
第6章 做事是否快捷,不在一时奋发,而在能否持久(搜索页功能模块)
6-1 搜索页导航栏修改
- 跳转事件
uni.navigateTo({url: '/pages/home-search/home-search'
})
6-2 使用vuex 管理历史记录
- 在目录下新建一个目录
store
- 在
store
目录下,新建index.js
- 输入下面代码
// vuex 状态管理
import Vue from 'vue'
import Vuex from 'vuex'Vue.use(Vuex)const store = new Vuex.Store({state:{}
})export default store
- 在
main.js
中注册一下
...
import store from './store'
...
const app = new Vue({store,...App
})
6-3 -1 搜索逻辑实现(上 )
6-4 -2 搜索逻辑实现(下)
- 加载组件
uni-load-more
<uni-load-more v-if="loading" status="loading" iconType="snow"></uni-load-more>// 执行
this.loading = true//关闭
this.loading = false
6-5 搜索历史数据持久化
- 返回上一页
uni.navigateBack()
- 回到 tab 页
uni.switchTab({url: '/pages/tabbar/index/index'
})
vuex
并不是持久化的存储,这里改造下vuex
中的代码
historyLists: uni.getStorageSync("__hostory")
获取本地缓存uni.setStorageSync('__hostory', list)
设置本地缓存uni.removeStorageSync('__hostory')
清空本地缓存
// vuex 状态管理
import Vue from 'vue'
import Vuex from 'vuex'Vue.use(Vuex)const store = new Vuex.Store({// 数据源state: {historyLists: uni.getStorageSync("__hostory") || []},//可以改变数据源中的数据mutations: {SET_HISTORY_LISTS(state, history) {state.historyLists = history},CLEAR_HISTORY(state, history){state.historyLists = []}},actions: {set_history({commit, state}, history) {let list = state.historyListslist.unshift(history)uni.setStorageSync('__hostory', list)commit('SET_HISTORY_LISTS', list)},clear_history({commit}){uni.removeStorageSync('__hostory')commit('CLEAR_HISTORY')}}
})export default store
第7章 锲而不舍,金石可镂(标签页功能模块)
7-1 标签管理页布局样式
7-2 标签页数据处理
7-3 编辑标签页
7-4 保存标签页数据
7-5 使用自定义事件同步数据
- 我们在内页修改了数据,之后返回上一页,此时,上一页数据应该要变化,但是实际上没有变化.
- 此时我们需要在内容修改数据之后, 要通知上一页帮我们主动会重新渲染. 此时需要用到自定义事件,
uni.$emit
- 自定义事件,只能在打开的页面触发
步骤
- 在内容调用
uni.$emit('事件名', 参数[可省略])
- 在调用页面的
onLoad()
中监听uni.$on('事件名', 参数[可省略])
uni.$on('labelChange', (res) => {this.getLabel();
})
- 在内容页中, 在
onLoad
中接受, 再将字符串通过JSON.parse(str)
解析成对象
onLoad(query) {console.log(JSON.parse(query.params));
},
第8章 坚持就是胜利,坚持才会有所成就(详情页功能模块)
8-1 详情页页面展示
8-2 内容预加载
- 当加载内容页面的时候,如果所有的数据都要立刻请求,再加载,则有一个空白的时候.
- 如上,我们可以在列表中,将一些数据带过去.达到
预加载
的效果.
步骤
- 在列表页中, 通过url的参数传过去,注意参数的个数, 这里是把 对象通过
JSON.stringify(object)
转为 字符串
const params = {_id: item._id,title: item.title,create_time: item.create_time,thumbs_up_count: item.thumbs_up_count,borwse_count: item.borwse_count
}
//...
uni.na
vigateTo({url: '/pages/home-detail/home-detail?params=' + JSON.stringify(params)
})
8-3 详情页面数据初始化
8-4 富文本渲染
- 组件
gaoyia-parse
,拷贝到本地的components
目录下,注意:这个插件需要手动导入并注册!
import uParse from '@/components/gaoyia-parse/parse.vue'
<script>import uParse from '@/components/gaoyia-parse/parse.vue'export default {components: {uParse},
//...
- 使用
<u-parse :content="fromData.content" :noData="noData"></u-parse>
- 为了美观, 在
App.vue
中引入css
<style>/*每个页面公共css */@import 'components/gaoyia-parse/parse.css';
</style>
8-5 发布窗口展示
- 弹窗的插件
uni-popup
, 下载下来,还有一个依赖的组件uni-transition
- 文档:
https://ext.dcloud.net.cn/plugin?id=329
使用步骤
- 编辑如下
<uni-popup ref="popup" type="bottom"><view class="popup-wrap">弹出层</view>
</uni-popup>
-
打开
this.$refs.popup.open()
注意, 如果一进入页面就要打开, 这个事件不可以直接放在onLoad
中,因为onLoad
时候,这个组件还没有渲染, 可以放在onReady
中. -
控制点击后面蒙版是否关闭弹窗
:maskClick="false"
<uni-popup ref="popup" type="bottom" :maskClick="false">
8-6 评论内容实现(1)
8-7 评论内容实现(2)
8-8 评论内容实现(3)
8-9 评论内容实现(4)
- 递归组件,自己调动自己
步骤
- 先
import
导入自身import commentsBox from '@/components/comments-box/comments-box.vue'
- 后 注册一下
<script>import commentsBox from '@/components/comments-box/comments-box.vue'export default {name: "comments-box",components: {commentsBox},
//...
- 如上, 递归组件, 需要加上
name
例如name: "comments-box",
8-10 评论内容实现 (5)
8-11 评论内容实现(6)
8-11 评论内容实现(6)
8-12 关注作者(上)
8-13 关注作者(下)
8-14 文章的收藏与点赞(上)
8-15 文章的收藏和点赞(下)
8-16 评论列表(上)
- 页面上拉触底事件的处理函数,页面的生命周期函数
onReachBottom
8-16 评论列表(上)
8-17 评论列表(下)
- 自己建立一个工具类
- 在根目录下建一个
utils
的文件夹, 然后新建一个index.js
文件 - 在
index.js
中输入
// 时间格式化
export const parseTime = (time) => {console.log(time)
}
- 在引用的页面中,导入这个文件
import {parseTime} from '@/utils/index.js'
- 在页面中加一个过滤器
filters
filters: {formatTime(time) {return parseTime(time)}
},
- 在页面中使用
<view>{{comments.create_time | formatTime}}</view>
过滤器使用, 如上
comments.create_time
是formatTime
的一个参数, 如果formatTime
有多个参数, 直接在后面写上,
例如<view>{{comments.create_time | formatTime(a, b)}}</view>
, 这里的a
是第二个参数,b
是第三个参数.
第9章 关注页功能模块
9-1 关注页导航栏实现
9-2 收藏文章内容实现
9-3 收藏与首页内容关联
9-4 关注作者页面实现
9-5 同步关注作者页面数据
第10章 个人信息页功能模块
10-1 个人中心页面实现
10-2 个人中心数据处理
- 使用
vuex
的记录
- 添加一个
userinfo
用来保存用户信息的记录. - 在
store/index.js
中, 添加如下代码
// vuex 状态管理
import Vue from 'vue'
import Vuex from 'vuex'Vue.use(Vuex)const store = new Vuex.Store({// 数据源state: {userinfo: uni.getStorageSync('USERINFO') || {}},//可以改变数据源中的数据mutations: {SET_USER_INFO(state, userinfo) {state.userinfo = userinfo}},actions: {set_userinfo({commit}, userinfo) {uni.setStorageSync('USERINFO', userinfo)commit('SET_USER_INFO', userinfo)}}
})export default store
- 在
app.vue
中调用,一开始获取到用户的信息,然后赋值给vuex
onLaunch: function() {console.log('App Launch')this.$api.get_user({user_id: '600966e08976a900010da78d'}).then(res => {const {data} = resthis.$store.dispatch('set_userinfo', data)})
},
- 在其他页面中,调用这个用户信息, 先导入, 后面在
computed
中声明, 在其他地方就可以调用this.userinfo
了, 如下
<script>import { mapState } from 'vuex'export default {data() {return {}},computed: {...mapState(['userinfo'])},onLoad() {console.log(this.userinfo);},methods: {}}
</script>
- 之前,我们在
common/https.js
中用一个默认的id来获取数据,现在有了vuex
中的数据, 则需要将https.js
中的代码修改一下,如下, 先导入, 再使用
import store from '../store/index.js'
export default function $http(options) {const {url,data} = optionsconst dataObj = {user_id: store.state.userinfo._id,...data}
//...
10-3 我的文章实现
10-4 问题反馈页面实现
10-5 反馈图片选择
10-6 上传图片
第11章 积少成多,走向完善(项目优化与平台兼容)
11-1 微信小程序优化与兼容
描述: 在
app.vue
中,异步
获取到了用户信息,然后放到vuex
中,但是加载到首页的时候,在首页的onload
中,我们就已经用到了用户信息,但是由于异步
, 数据此时可能还没有传递过来.这个问题,要用过监听vuex
中的userinfo
, 让首页在识别到的情况下,在做操作.
步骤
- 在首页 引入
vuex
import { mapState } from 'vuex'
- 在页面中的
computed
中注册一下
computed: {...mapState(['userinfo'])
},
- 监听一下
useinfo
的变化, 如果发生了变化,说明已经获取到了,没有变化则没有获取到
watch: {userinfo(newVal) {// 获取 tab 导航栏的信息this.getLabel();}
},