uni-app笔记

大纲目录


第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 的方式运行项目

  1. 检查 node.js 版本 node -v # v14.15.4
  2. npm install -g cnpm --registry=https://registry.npm.taobao.org 设置镜像然后再 npm install -g @vue/cli 装到全局的环境中
  3. 自己出现了报错的情况,需要先运行 sudo chown -R $USER /usr/local 之后再安装就好了.
  4. 检查 vue-cli 是否安装 vue --version # 2.9.6
  5. 进入目录 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 绑定变量, 为false0的时候,不渲染

<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>

③ 页面上拿到组件中的返回值

  1. index.vue 中注册监听事件
<btn color="red" @change="change"></btn>
...
methods: {
	change(e) {
		console.log("我是页面的事件,我返回了" + e);
	}
}

  1. 组件中,通过 $emit() 来返回. 接受2个参数, 第一个是 index.vue的监听函数,第二个是参数
methods: {
	clickBox() {
		console.log('click');
		this.$emit('change', this.color)
	}
}
  1. 如上2步,组件中,通过 $emitthis.color 传给 index.vuechange 事件. 而 change 中的 e 就是组件中返回来的 this.color

④ 组件插槽 <slot></slot>

  1. index.vue 中,使用 <btn color="red" @change="change">主页中的内容</btn> 这样的写法, 希望把文字也插入到组件中.
  2. 在 组价中, 使用插槽 <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

① 生命周期的分类

  1. 应用生命周期, 在 App.vue 文件中

    onLaunch 应用初始化完成触发一次, 全局只触发一次
    onShow 应用启动的时候, 或者从后台进入前台会触发
    onHide 应用从前台进入后台触发

  2. 页面生命周期

    onLoad 监听页面加载
    onShow 监听页面显示,每次切换到这个页面,都会执行
    onReady 监听页面初次渲染完成 (如果渲染速度快, 会在页面进入动画完成前触发)
    onHide 监听页面隐藏
    onUnload 监听页面卸载,页面关闭

  3. 组件生命周期

    beforeCreate 在实例初始化之后,数据观测(data observer) 和 event/watcher 事件配置之前被调用
    created 实例创建完成之后立即调用, 挂载阶段还没有开始
    mounted 挂载到实例上去之后调用
    destroyed vue 实例销毁后调用

  4. 大概顺序 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'
})

updateset 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() {
		// 图片上传apis
		uni.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>
  • 小程序
    在这里插入图片描述
  • h5
    在这里插入图片描述
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) {
		
	}
});

大概步骤

  1. 父页面中, 获取数据, 然后赋给组件 <tab :list="tabList"></tab>
  2. 组件中, 通过 props 注册一下. 这里是 Array类型
<script>
	export default {
		props: {
			list: {
				type: Array,
				default () {
					return []
				}
			}
		},
...
  1. 之后, 组件 中就可以使用 list来做操作了.
5-7 封装数据请求
  1. 在根目录的 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) {
				// .then
				reslove(res.result);
			} else {
				// catch
				reject(res.result);
			}
		}).catch(err => {
			reject(err);
		})
	})

}


export default {
	get_label
}
  1. main.js 中, import 然后再赋值, 如下
import api from './common/api'
...
Vue.prototype.$api = api
  1. 在需要的地方调用这个方法
methods: {
	getLabel() {
		this.$api.get_label({
			name: 'get_label'
		}).then(res => {
			const {
				data
			} = res;
			this.tabList = data;
		})

	}
}
  1. 优化代码, 在 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) {
				// .then
				reslove(res.result);
			} else {
				// catch
				reject(res.result);
			}

		}).catch(err => {
			reject(err);
		})
	})

}

  1. common/apiindex.js 中,修改代码如下, 这样每个代码分开管理.
import {get_label} from './list.js'

export default {
	get_label
}
  1. 继续优化, 因为每个请求都要写 return Promise.., 可以在 common 文件夹下面 新进一个 http.js
export default function $http(options) {
	const {
		url,
		data
	} = options
	return new Promise((reslove, reject) => {
		uniCloud.callFunction({
			name: url,
			data
		}).then(res => {

			if (res.result.code === 200) {
				// .then
				reslove(res.result);
			} else {
				// catch
				reject(res.result);
			}

		}).catch(err => {
			reject(err);
		})
	})
}
  1. 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
	})
}
  1. 如上, 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 选项卡切换
  1. 加一个点击事件,绑定一个class :class="{active:activeIndex === index}" @click="clickTab(item,index)"

  2. 把事件返回给 父页面

methods: {
	// 点击导航栏高亮
	clickTab(item, index) {
		this.activeIndex = index
		//把事件传递到父页面去
		this.$emit('tab', {
			data: item,
			index: index
		})
	}
}
  1. <tab :list=“tabList” @tab=“tab”> 绑定事件 tab是自定义事件
  2. methods里面注册一下
tab(data, index) {
	console.log(data, index);
}
5-9 基础卡片视图实现
  • 以组件的新式来实现,
5-10 更多卡片视图实现
  • 在组件中,分别写3种模式(列表,大图,多图).
  • 以插槽的形式,让父页面绝对调用谁
5-11 实现内容切换
  1. 拆分组件,例如 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>
  1. 在同级目录新建 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>

  1. 因为这个不符合 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 搜索页导航栏修改
  1. 跳转事件
uni.navigateTo({
	url: '/pages/home-search/home-search'
})

6-2 使用vuex 管理历史记录
  1. 在目录下新建一个目录 store
  2. store 目录下,新建 index.js
  3. 输入下面代码
// vuex 状态管理
import Vue from 'vue'
import Vuex from 'vuex'

Vue.use(Vuex)

const store = new Vuex.Store({
	state:{
		
	}
})

export default store
  1. 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 搜索历史数据持久化
  1. 返回上一页 uni.navigateBack()
  2. 回到 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.historyLists
			list.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
  • 自定义事件,只能在打开的页面触发

步骤

  1. 在内容调用 uni.$emit('事件名', 参数[可省略])
  2. 在调用页面的 onLoad()中监听 uni.$on('事件名', 参数[可省略])
uni.$on('labelChange', (res) => {
	this.getLabel();
})
  1. 在内容页中, 在onLoad中接受, 再将字符串通过 JSON.parse(str) 解析成对象
onLoad(query) {
	console.log(JSON.parse(query.params));
},

第8章 坚持就是胜利,坚持才会有所成就(详情页功能模块)

8-1 详情页页面展示
8-2 内容预加载
  • 当加载内容页面的时候,如果所有的数据都要立刻请求,再加载,则有一个空白的时候.
  • 如上,我们可以在列表中,将一些数据带过去.达到预加载的效果.

步骤

  1. 在列表页中, 通过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 目录下, 注意:这个插件需要手动导入并注册!
  1. import uParse from '@/components/gaoyia-parse/parse.vue'
<script>
	import uParse from '@/components/gaoyia-parse/parse.vue'
	export default {
		components: {
			uParse
		},
//...
  1. 使用 <u-parse :content="fromData.content" :noData="noData"></u-parse>
  2. 为了美观, 在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

使用步骤

  1. 编辑如下
<uni-popup ref="popup" type="bottom">
	<view class="popup-wrap">
		弹出层
	</view>
</uni-popup>

  1. 打开 this.$refs.popup.open() 注意, 如果一进入页面就要打开, 这个事件不可以直接放在 onLoad 中,因为 onLoad时候,这个组件还没有渲染, 可以放在 onReady 中.

  2. 控制点击后面蒙版是否关闭弹窗 :maskClick="false"

<uni-popup ref="popup" type="bottom" :maskClick="false">
8-6 评论内容实现(1)
8-7 评论内容实现(2)
8-8 评论内容实现(3)
8-9 评论内容实现(4)
  • 递归组件,自己调动自己

步骤

  1. import 导入自身 import commentsBox from '@/components/comments-box/comments-box.vue'
  2. 后 注册一下
<script>
	import commentsBox from '@/components/comments-box/comments-box.vue'
	export default {
		name: "comments-box",
		components: {
			commentsBox
		},
//...
  1. 如上, 递归组件, 需要加上 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 评论列表(下)
  • 自己建立一个工具类
  1. 在根目录下建一个 utils 的文件夹, 然后新建一个 index.js 文件
  2. index.js 中输入
// 时间格式化
export const parseTime = (time) => {
	console.log(time)
}
  1. 在引用的页面中,导入这个文件
import {parseTime} from '@/utils/index.js'
  1. 在页面中加一个过滤器 filters
filters: {
	formatTime(time) {
		return parseTime(time)
	}
},
  1. 在页面中使用 <view>{{comments.create_time | formatTime}}</view>

过滤器使用, 如上 comments.create_timeformatTime 的一个参数, 如果 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 的记录
  1. 添加一个 userinfo 用来保存用户信息的记录.
  2. 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

  1. app.vue 中调用,一开始获取到用户的信息,然后赋值给 vuex
onLaunch: function() {
	console.log('App Launch')
	this.$api.get_user({
		user_id: '600966e08976a900010da78d'
	}).then(res => {
		const {
			data
		} = res
		this.$store.dispatch('set_userinfo', data)
	})
},

  1. 在其他页面中,调用这个用户信息, 先导入, 后面在 computed 中声明, 在其他地方就可以调用 this.userinfo了, 如下
<script>
	import { mapState } from 'vuex'
	export default {
		data() {
			return {

			}
		},
		computed: {
			...mapState(['userinfo'])
		},
		onLoad() {
			console.log(this.userinfo);
		},
		methods: {

		}
	}
</script>
  1. 之前,我们在 common/https.js 中用一个默认的id来获取数据,现在有了 vuex 中的数据, 则需要将 https.js 中的代码修改一下,如下, 先导入, 再使用
import store from '../store/index.js'
export default function $http(options) {
	const {
		url,
		data
	} = options
	
	const 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 , 让首页在识别到的情况下,在做操作.

步骤

  1. 在首页 引入 vuex
import { mapState } from 'vuex'
  1. 在页面中的 computed 中注册一下
computed: {
	...mapState(['userinfo'])
},
  1. 监听一下useinfo的变化, 如果发生了变化,说明已经获取到了,没有变化则没有获取到
watch: {
	userinfo(newVal) {
		// 获取 tab 导航栏的信息
		this.getLabel();
	}
},

11-2 支付宝小程序优化与兼容
11-3 其他平台优化与兼容

第12章 最后的冲刺,成功就在眼前(项目发行与打包)

12-1 h5端发行打包
12-2 小程序端发行上传
12-3 App 端发行打包

第13章 常常是最后一把钥匙打开了门(课程总结与展望)

13-1 课程回顾与总结

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值