uniapp快速开发小程序全流程

uniapp快速开发小程序全流程

完整项目代码:https://gitee.com/Zifasdfa/ziyi-app

欢迎fork与star

1 项目效果及环境准备

1.1 项目效果

本文主要使用uniapp实现一个简单的app应用



1.2 环境准备&项目初始化

①node环境:去node.js官网下载稳定版的node即可,下载之后配置环境变量,通过node -v查看是否配置成功

② 开发工具选择:HBuilder-X

官网下载地址:https://uniapp.dcloud.net.cn/quickstart.html#

根据自己的操作系统下载对应的环境即可,下载好之后,双击.exe文件打开HBuilderX

点击左上角:文件 - 新建项目 - 选择uni-app项目,填写对应项目名,其他默认即可【这里我采用vue2的语法】

效果:

展示效果选择手机页面方式:

当然我们也可以通过数据线,将手机与电脑连接起来,然后直接在真机上运行。

2 实现tabbar底部导航

增加底部导航,为:首页、分类、学习、我的

官网tabbar教程:https://uniapp.dcloud.net.cn/collocation/pages.html#tabbar

  • tabBar 中的 list 是一个数组,只能配置最少2个、最多5个 tab,tab 按数组的顺序排序。

①导入图片资源

导入所给源码中的static下的图片

②新建tabbar目录及对应页面

因为我们整个项目是将底部导航栏中的index默认为首页,因此删除之前pages目录的index整个文件夹,并在pages下新建tabbar目录,然后在tabbar目录下分别新建classify、index、mine、study页面

③修改页面主题颜色,修改App.vue

css 复制代码
<style>
	/*每个页面公共css 修改页面主背景色为灰色,配合白色的底部导航栏*/
	body{
		background-color: #f8f8f8;
	}
</style>

④配置底部导航栏,修改package.json

  • 配置页面

在pages配置下,修改页面配置,包括修改页面路径及是否允许下拉刷新等

js 复制代码
{
	"pages": [ //pages数组中第一项表示应用启动页,参考:https://uniapp.dcloud.io/collocation/pages
		{
			//指定有哪些页面,并配置样式
		    "path" : "pages/tabbar/index/index",
		    "style" :                                                                                    
		    {
				//页面顶部的文本
		       "navigationBarTitleText":"首页",
			   "navigationStyle":"custom"
		    }
		    
		}
		,{
		    "path" : "pages/tabbar/classify/classify",
		    "style" :                                                                                    
		    {
				"navigationBarTitleText":"分类",
				"navigationBarBackgroundColor":"#00b783",
				"navigationBarTextStyle":"white",
				//不启动下拉刷新
				"enablePullDownRefresh":false
		    }
		    
		}
		,{
		    "path" : "pages/tabbar/study/study",
		    "style" :                                                                                    
		    {
		    	"navigationBarTitleText":"学习中心",
		    	"navigationBarBackgroundColor":"#00b783",
		    	"navigationBarTextStyle":"white",
		    	"enablePullDownRefresh":false
		    }
		    
		}
		,{
		    "path" : "pages/tabbar/mine/mine",
		    "style" :                                                                                    
		    {
		    	"navigationBarTitleText":"个人中心",
		    	"navigationBarBackgroundColor":"#00b783",
		    	"navigationBarTextStyle":"white",
		    	"enablePullDownRefresh":false
		    }
		    
		}
    ],
	...
}
  • 新增tabbar配置

包括配置文本,选中未选中时候的图标等

js 复制代码
{
	"pages": [ //pages数组中第一项表示应用启动页,参考:https://uniapp.dcloud.io/collocation/pages
	....
	
	// 底部导航栏
	"tabBar":{
		"color":"#999",
		//选中时的颜色
		"selectedColor":"#00b783",
		"borderStyle":"white",
		"backgroundColor":"#FFFFFF",
		"list":[
			{
				//底部导航栏的index对应页面
				"pagePath":"pages/tabbar/index/index",
				//对应文本
				"text":"首页",
				//未选中时的图标
				"iconPath":"static/tabar1.png",
				//选中之后的图标
				"selectedIconPath":"static/tabaron1.png"
			},
			{
				"pagePath":"pages/tabbar/classify/classify",
				"text":"分类",
				"iconPath":"static/tabar2.png",
				"selectedIconPath":"static/tabaron2.png"
			},
			{
				"pagePath":"pages/tabbar/study/study",
				"text":"学习",
				"iconPath":"static/tabar3.png",
				"selectedIconPath":"static/tabaron3.png"
			},
			{
				"pagePath":"pages/tabbar/mine/mine",
				"text":"我的",
				"iconPath":"static/tabar4.png",
				"selectedIconPath":"static/tabaron4.png"
			}
		]
	}
}

⑤查看效果

然后重新运行在浏览器,如果显示不出效果,则先暂停,然后重新运行在对应浏览器

效果:

3 实现搜索框(使用第三方组件实现)

①下载第三方组件

组件 - 自定义导航栏-下载组件

选择下载并导入:

注意,下载插件是需要注册账号并登录的,如果没有账号的话,注册并登录即可

导入成功之后的效果:

②安装scss/sass插件

因为我们后续会使用到css中的scss语法,所以需要提前安装插件

工具 - 插件安装

如果已经存在则无需安装

否则,点击安装新插件,插件市场中搜索sass,然后选择下载插件并导入

③抽取nav-bar组件(防止主页面代码过多不易维护)

在components组件下新建navbar目录,然后在navbar目录下创建navbar.vue文件

navbar.vue:

html 复制代码
<template>
	<view>
		<view class="example-body">
			<!--uni-nav-bar 中的 statusBar 主要是为了适配"齐刘海",防止navbar遮盖住手机顶部的电量、时间等状态 -->
			<uni-nav-bar shadow statusBar :fixed="false" color="#333333" background-color="#FFFFFF" right-icon="scan">
				<view class="input-view">
					<uni-icons class="input-uni-icon" type="search" size="22" color="#666666" />
					<input confirm-type="search" class="nav-bar-input" type="text" placeholder="输入搜索关键词">
				</view>
			</uni-nav-bar>
		</view>
	</view>
</template>

<script>
	import uniNavBar from '@/components/uni-nav-bar/uni-nav-bar.vue'
	export default {
		data() {
			return {

			}
		},
		methods: {

		},
		components: {
			uniNavBar
		}
	}
</script>

<style lang="scss">
	.input-view {
		/* #ifndef APP-PLUS-NVUE */
		display: flex;
		/* #endif */
		flex-direction: row;
		width: 600rpx;
		flex: 1;
		background-color: #f8f8f8;
		height: 30px;
		border-radius: 15px;
		padding: 0 15px;
		flex-wrap: nowrap;
		margin: 7px 0;
		line-height: 30px;
	}

	.input-uni-icon {
		line-height: 30px;
	}

	.nav-bar-input {
		height: 30px;
		line-height: 30px;
		/* #ifdef APP-PLUS-NVUE */
		width: 370rpx;
		/* #endif */
		padding: 0 5px;
		font-size: 28rpx;
		background-color: #f8f8f8;
	}

	.example-body {
		padding: 0;
	}
</style>

④在pages/tabbar/index/index.vue中引入Navbar组件

html 复制代码
<template>
	<view>
		<!-- 引入顶部搜索框导航栏 -->
		<Navbar/>
		
	</view>
</template>

<script>
	import Navbar from "../../../components/navbar/navbar.vue"
	export default {
		data() {
			return {
				
			}
		},
		methods: {
			
		},
		components:{
			Navbar,
		}
	}
</script>

⑤效果

页面效果:

4 首页实现Banner轮播图

通过网络请求动态获取图片数据

4.1 通过网络请求获取数据

uni.request发起网络请求

pages/tabbar/index/index.vue:

html 复制代码
<script>
	import Navbar from "../../../components/navbar/navbar.vue"
	export default {
		data() {
			return {
				//多张图片,用数组存放
				topBanner: [],
				
			}
		},
		methods: {
			
		},
		mounted(){
				//vue的生命周期函数
				uni.request({
					url: "http://html5.bjsxt.cn/api/index/banner",
					//注意:网络请求必须要按照下面的方式发起,不能使用新语法等
					success: (res) => {
						// console.log(res)
						this.topBanner = res.data.top_banner
					}
				})
		},
		components:{
			Navbar,
		}
	}
</script>

②通过console.log打印网络请求所返回的数据:

③根据网络返回的结果获取图片

需要根据自己的手机型号进行样式的调整

pages/tabbar/index/index.vue:

html 复制代码
<template>
	<view class="home">
		<!-- 引入顶部搜索框导航栏 -->
		<Navbar/>
		<view class="index_banner_box">
			<!-- 顶部banner,同时配置对应参数 -->
			<swiper class="swiper" :indicator-dots="true" :autoplay="true" :interval="3000" :duration="500">
				<!-- 从图片数组中取出对应图片并展示在页面上 -->
				<swiper-item v-for="(item, index) in topBanner" :key="index">
					<image class="banner" :src="item.img_url" mode=""></image>
				</swiper-item>
			</swiper>
		</view>
	</view>
</template>

<script>
	...
</script>

<!-- 使用scss的语法 -->
<style lang="scss">
	.home {
		//flex:盒子模型
		display: flex;
		flex-direction: column;
		flex: 1;
		overflow: hidden;
		.index_banner_box {
			display: flex;
			width: 100%;
			padding: 10px;
			justify-content: center;
			align-items: center;
			border-radius: 5px;
			overflow: hidden;
			.swiper{
				width: 100%;
				height: 260rpx;
				.banner{
					width: 700rpx;
					height: 260rpx;
				}
			}
		}
	}
</style>

4.2 在页面中展示图片数据并配置样式

4.3 结果

5 实现课程导航

注意:import用于在js中引入css文件, @import用于在css中引入css文件

5.1 抽取课程导航coursenav为component,并编写页面

①引入源码中common下的图标样式,css文件等

②在components文件夹下新建coursenav

coursenav.vue:

html 复制代码
<template>
	<view class="course_nav_con">
		<view class="course_nav_info" v-for="(item, index) in list" :key="index">
			<text class="course_nav_icon icon iconfont" :class="item.icon"></text>
			<view class="course_info_text">{{item.text}}</view>
		</view>
		
	</view>
</template>

<script>
	export default {
		data() {
			return {
				list: []
			}
		},
		mounted() {
			uni.request({
				url: "http://html5.bjsxt.cn/api/index/nav",
				success: (res) => {
					this.list = res.data.data
				}
			})
		},
		methods: {
			
		}
	}
</script>

<style lang="scss">
	
	// import用于在js中引入css文件, @import用于在css中引入css文件
	@import "@/common/font/iconfont.css";

	.course_nav_con {
		display: flex;
		// 盒子模型不撑开容器本身大小
		box-sizing: border-box;
		flex-direction: row;
		flex-wrap: wrap;
		padding: 15px 10px;

		.course_nav_info {
			width: 20%;
			flex-direction: row;
			flex-wrap: wrap;
			text-align: center;
			margin-bottom: 15px;

			.course_nav_icon {
				font-size: 30px;
			}

			.icon-java {
				color: #2a83fe;
			}

			.icon-weifuwu {
				color: #fd3761;
			}

			.icon-zuzhijiagou {
				color: #2b91e2;
			}

			.icon-dashuju {
				color: #2a83fe;
			}

			.icon-h {
				color: #00b478;
			}

			.icon-icon-- {
				color: #fd6012;
			}

			.icon-rengongzhineng {
				color: #fe391f;
			}

			.icon-ruanjianceshi {
				color: #00b478;
			}

			.icon-huatong {
				color: #fea917;
			}

			.icon-bianchengshibaobiao_icon {
				color: #2a83fe;
			}

			.icon-jianmo {
				color: #00b478;
			}

			.icon-chuangye {
				color: #fe391f;
			}

			.course_info_text {
				width: 100%;
				font-size: 13px;
				margin-top: 10px;
				white-space: nowrap;
				text-overflow: ellipsis;
				overflow: hidden;
			}
		}
	}
</style>

5.2 主页导入课程

在pages/tabbar/index/index.vue中引入CourseNar

  • import CourseNav from ".../.../.../components/coursenav/coursenav.vue"
  • components中添加CourseNav,
  • template标签中添加<CourseNav/>
html 复制代码
<template>
	<view class="home">
		<!-- 引入顶部搜索框导航栏 -->
		<Navbar/>
		<view class="index_banner_box">
			<!-- 顶部banner,同时配置对应参数 -->
			<swiper class="swiper" :indicator-dots="true" :autoplay="true" :interval="3000" :duration="500">
				<!-- 从图片数组中取出对应图片并展示在页面上 -->
				<swiper-item v-for="(item, index) in topBanner" :key="index">
					<image class="banner" :src="item.img_url" mode=""></image>
				</swiper-item>
			</swiper>
		</view>
		<!-- 课程导航栏 -->
		<CourseNav/>
	</view>
</template>

<script>
	import Navbar from "../../../components/navbar/navbar.vue"
	import CourseNav from "../../../components/coursenav/coursenav.vue"
	export default {
		data() {
			return {
				//多张图片,用数组存放
				topBanner: [],
				
			}
		},
		methods: {
			
		},
		mounted(){
				//vue的生命周期函数
				uni.request({
					url: "http://html5.bjsxt.cn/api/index/banner",
					//注意:网络请求必须要按照下面的方式发起,不能使用新语法等
					success: (res) => {
						// console.log(res)
						this.topBanner = res.data.top_banner
					}
				})
		},
		components:{
			Navbar,
			CourseNav,
		}
	}
</script>

5.3 效果

部分网络上的css及图标样式已经获取不到了,所以大家可以替换新的网络地址来获取对应的图标

6 实现限时免费

6.1 创建free-card的components

新建free-card目录,然后新建free-card.vue文件

html 复制代码
<template>
	<view>
		<view class="free_card_box" v-for="(item, index) in teaList" :key="index">
			<!-- 老师图片 -->
			<view class="free_card_img">
				<image :src="item.teacher_logo" mode=""></image>
			</view>
			<!-- 限时免费文本信息 -->
			<view class="free_card_txt">
				<view class="free_card_T">{{ item.limitName }}</view>
				<view class="free_card_info">
					<view class="free_card_info_txt">
						<view class="info_txt1">{{ item.teacher_name }}{{ item.teacher_job }}</view>
						<view>{{ item.limitNum }}人学过</view>
					</view>
					<view class="free_card_info_btn" v-if="item.baoming == '马上报名'">{{ item.baoming }}</view>
					<view class="free_card_info_btn free_card_info_btn1" v-else>{{ item.baoming }}</view>
				</view>
			</view>
		</view>
	</view>
</template>

<script>
	export default {
		name:"free-card",
		data() {
			return {
				teaList:[]
			}
		},
		mounted(){
			uni.request({
				url:"http://html5.bjsxt.cn/api/index/specific?userid=2162",
				success: (res) => {
					this.teaList = res.data.data
				}
			})
		},
		methods: {
			
		}
	}
</script>

<!-- .free_card_box的class里面再点.free_card_img的class 为 scss语法 -->
<style lang="scss">
	.free_card_box{
		display: flex;
		padding: 10px 0;
		margin: 10px;
		border-radius: 10px;
		box-shadow: 0 0  5px 1px rgba($color: #000000, $alpha: 0.1);
		box-sizing: border-box;
		align-items: center;
		margin-bottom: 15px;
		background-color: #fff;
		.free_card_img{
			flex-shrink: 0;
			width: 91rpx;
			height: 91rpx;
			border-radius: 100%;
			margin: 0 15px;
			image{
				width: 100%;
				height: 100%;
				border-radius: 100%;
			}
		}
		.free_card_txt{
			width: 100%;
			display: flex;
			box-sizing: border-box;
			flex-direction: column;
			padding: 0 15px 0 0;
			.free_card_T{
				font-size: 16px;
				white-space: nowrap;
				text-overflow: ellipsis;
				overflow: hidden;
				margin: 10px 0;
			}
			.free_card_info{
				width: 100%;
				display: flex;
				box-sizing: border-box;
				flex-flow: row nowrap;
				justify-content: space-between;
				.free_card_info_txt{
					width: 60%;
					overflow: hidden;
					font-size: 16px;
					color: #666;
					.info_txt1{
						height: 20px;
						font-size:14px;
						overflow: hidden;
					}
				}
				.free_card_info_btn{
					width: 100px;
					height: 34px;
					text-align: center;
					line-height: 34px;
					border-radius: 34px;
					background-color: #00b783;
					color: #fff;
					font-size: 16px;
					margin-top: 10px;
				}
				.free_card_info_btn1{
					background-color: #ddd;
				}
			}
		}
	}
</style>

6.2 首页引入free-card

  1. 在script标签中导入
  2. 在component中导入
  3. 在页面中引用

修改pages/tabbar/index/index.vue

①在课程导航栏下方添加FreeCard组件及在线课程图标

html 复制代码
		<!-- 课程导航栏 -->
		<CourseNav/>
		<!-- 在线课程图标 -->
		<view class="online_box">
			<image :src="index_banner.img_url" class="online_img"></image>
		</view>
		<view class="free_box">
			<view class="free_T_box public_tow_box">
				<view class="public_T">
					限时免费
				</view>
			</view>
			<FreeCard />
		</view>

②在script中获取图片和文本数据,并引入FreeCard组件

html 复制代码
<script>
	import Navbar from "../../../components/navbar/navbar.vue"
	import CourseNav from "../../../components/coursenav/coursenav.vue"
	import FreeCard from "../../../components/free-card/free-card.vue"
	export default {
		data() {
			return {
				//多张图片,用数组存放
				topBanner: [],
				index_banner:{},
			}
		},
		methods: {
			
		},
		mounted(){
				//vue的生命周期函数
				uni.request({
					url: "http://html5.bjsxt.cn/api/index/banner",
					//注意:网络请求必须要按照下面的方式发起,不能使用新语法等
					success: (res) => {
						// console.log(res)
						this.topBanner = res.data.top_banner
						this.index_banner = res.data.index_banner
					}
				})
		},
		components:{
			Navbar,
			CourseNav,
			FreeCard, //引入限时免费组件
		}
	}
</script>

③在style中新增css样式

css 复制代码
<!-- 使用scss的语法 -->
<style lang="scss">
	.home {
		//flex:盒子模型
		display: flex;
		flex-direction: column;
		flex: 1;
		overflow: hidden;
		.index_banner_box {
			display: flex;
			width: 100%;
			padding: 10px;
			justify-content: center;
			align-items: center;
			border-radius: 5px;
			overflow: hidden;
			.swiper{
				width: 100%;
				height: 260rpx;
				.banner{
					width: 700rpx;
					height: 260rpx;
				}
			}
		}
		.online_box{
			display: flex;
			width: 724rpx;
			justify-content: center;
			align-items: center;
			box-sizing: border-box;
			overflow: hidden;
			margin-bottom: 15px;
			
			.online_img{
				//1px 约等于2 rpx
				width: 724rpx;
				height: 132rpx;
			}
			
		}
		.public_tow_box{
			display: flex;
			width: 100%;
			justify-content: center;
			align-items: center;
			box-sizing: border-box;
			overflow: hidden;
			padding: 0 15px;
			justify-content: space-between;
			align-content: space-between;
			flex-wrap: wrap;
			.public_T{
				font-size: 20px;
				font-weight: 700;
			}
		}
		.public_title{
			width: 100%;
			display: flex;
			padding: 0 15px;
			flex-direction: column;
			.public_class_t{
				font-size: 22px;
				font-weight: 700;
				margin-bottom: 15px;
			}
		}
	}
</style>

6.4 效果

7 实现就业班模块

view标签与div标签区别:

  • view标签通常具有更丰富的功能,比如数据绑定、事件处理等。而div标签只是一个简单的容器,没有特定的功能。

7.1 创建jobScroll

步骤与前面大同小异

html 复制代码
<template>
	<!-- 就业班模块:根据接口返回数据拼装内容 -->
	<view class="job_scroll_box">
		<scroll-view scroll-x="true" class="job_scroll_con_box">
			<view class="job_scroll_con">
				<view class="job_scroll_info" v-for="(item,index) in list" :key="index">
					<view class="job_scroll_card" :class="item.colors">
						<view class="job_scroll_card_T">{{ item.textT }}</view>
						<view class="job_scroll_card_icon">
							<view class="icon iconfont" :class="item.icon"></view>
						</view>
						<view class="job_scroll_card_des">{{ item.text }}</view>
						<view class="job_scroll_card_btn">免费试学</view>
					</view>
				</view>
			</view>
		</scroll-view>
	</view>
</template>

<script>
	export default {
		data() {
			return {
				list: []
			}
		},
		mounted() {
			uni.request({
				url: "http://html5.bjsxt.cn/api/index/course",
				success: (res) => {
					this.list = res.data.data
				}
			})
		},
		methods: {

		}
	}
</script>

<style lang="scss">
	// @import :从css中引入css
	@import "@/common/font/iconfont.css";

	.job_scroll_box {
		width: 100%;
		margin-bottom: 30px;
		box-sizing: border-box;

		.job_scroll_con {
			display: flex;
			align-items: center; //垂直据中
			flex-wrap: nowrap; //不换行
			box-sizing: border-box;

			.job_scroll_info {
				width: 225px;
				height: 260px;
				flex-shrink: 0;
				margin: 0 10px;

				.job_scroll_card {
					display: flex;
					flex-flow: column;
					box-sizing: border-box;
					align-items: center; //水平据中
					width: 100%;
					height: 248px;
					background-color: #b0def5;
					border-radius: 5px;
					margin-top: 12px;

					.job_scroll_card_T {
						display: flex;
						align-items: center; //水平据中
						justify-content: center; //垂直居中
						width: 210px;
						height: 38px;
						background-color: #e4f3fb;
						font-size: 16px;
						text-align: center;
						margin-top: -15px;
						border-bottom-left-radius: 25px;
						border-bottom-right-radius: 25px;
						border-top-left-radius: 15px;
						border-top-right-radius: 15px;
					}

					.job_scroll_card_icon {
						display: flex;
						align-items: center; //水平据中
						justify-content: center; //垂直居中
						box-sizing: border-box;
						width: 90px;
						height: 90px;
						background-color: #d3ecf9;
						border-radius: 100%;
						margin: 20px 0 15px;

						view {
							font-size: 42px;
							color: #2a83fe;
						}

					}

					.job_scroll_card_des {
						display: flex;
						box-sizing: border-box;
						align-items: center; //水平据中
						font-size: 14px;
					}

					.job_scroll_card_btn {
						display: flex;
						box-sizing: border-box;
						align-items: center;
						justify-content: center; //垂直居中
						width: 118px;
						height: 32px;
						line-height: 32px;
						color: #0a5ea0;
						font-size: 16px;
						border-radius: 34px;
						border: 1px solid #0a5ea0;
						margin-top: 15px;
					}
				}

				.job_scroll_card2 {
					background-color: #fed2b0;

					.job_scroll_card_T {
						background-color: #fff2e7;
					}

					.job_scroll_card_icon {
						background-color: #fee6d3;

						view {
							color: #d87e4e;
						}
					}

					.job_scroll_card_btn {
						color: #c44606;
						border: 1px solid #c44606;
					}
				}

				.job_scroll_card3 {
					background-color: #fee4b7;

					.job_scroll_card_T {
						background-color: #fef4e2;
					}

					.job_scroll_card_icon {
						background-color: #fef0d7;

						view {
							color: #b17001;
						}
					}

					.job_scroll_card_btn {
						color: #b17001;
						border: 1px solid #b17001;
					}
				}

				.job_scroll_card4 {
					background-color: #f5bcf7;

					.job_scroll_card_T {
						background-color: #fae0fb;
					}

					.job_scroll_card_icon {
						background-color: #f9d9fa;

						view {
							color: #8f0494;
						}
					}

					.job_scroll_card_btn {
						color: #8f0494;
						border: 1px solid #8f0494;
					}
				}

				.job_scroll_card5 {
					background-color: #cff2cb;

					.job_scroll_card_T {
						background-color: #ebf9e9;
					}

					.job_scroll_card_icon {
						background-color: #e4f7e2;

						view {
							color: #138a06;
						}
					}

					.job_scroll_card_btn {
						color: #138a06;
						border: 1px solid #138a06;
					}
				}

				.job_scroll_card6 {
					background-color: #f9cbc8;

					.job_scroll_card_T {
						background-color: #fce8e6;
					}

					.job_scroll_card_icon {
						background-color: #fbe2e0;

						view {
							color: #980c03;
						}
					}

					.job_scroll_card_btn {
						color: #980c03;
						border: 1px solid #980c03;
					}
				}

				.job_scroll_card7 {
					background-color: #f3eaa3;

					.job_scroll_card_T {
						background-color: #f8f3cc;
					}

					.job_scroll_card_icon {
						background-color: #f8f3cc;

						view {
							color: #786b03;
						}
					}

					.job_scroll_card_btn {
						color: #786b03;
						border: 1px solid #786b03;
					}
				}

				.job_scroll_card8 {
					background-color: #b4eef3;

					.job_scroll_card_T {
						background-color: #e4f9fb;
					}

					.job_scroll_card_icon {
						background-color: #d5f5f8;

						view {
							color: #088691;
						}
					}

					.job_scroll_card_btn {
						color: #088691;
						border: 1px solid #088691;
					}
				}

				.job_scroll_card9 {
					background-color: #f7c8a4;

					.job_scroll_card_T {
						background-color: #fcebdd;
					}

					.job_scroll_card_icon {
						background-color: #fae0cc;

						view {
							color: #9c4604;
						}
					}

					.job_scroll_card_btn {
						color: #9c4604;
						border: 1px solid #9c4604;
					}
				}

				.job_scroll_card10 {
					background-color: #cfd2fe;

					.job_scroll_card_T {
						background-color: #edefff;
					}

					.job_scroll_card_icon {
						background-color: #e4e6fe;

						view {
							color: #4e06ab;
						}
					}

					.job_scroll_card_btn {
						color: #4e06ab;
						border: 1px solid #4e06ab;
					}
				}
			}
		}
	}
</style>

7.2 首页中引入

pages/tabbar/index/index.vue:

html 复制代码
		<!-- view标签功能更强大:表示一个视图 -->
		<view class="public_title">
			<view class="public_class_t">零基础就业班</view>
			<JobScroll />
		</view>

其他和前面类似,导入JobScroll组件,然后在页面中引用即可

7.3 效果

8 实现课程推荐部分

8.1 新增course-card这个component

html 复制代码
<template>
	<view class="course_card_box">
		<view class="course_card_con">
			<view class="course_card_info" v-for="(item,index) in list" :key="index">
				<view class="course_card_img">
					<image :src="item.logo" mode=""></image>
				</view>
				<view class="course_card_des">
					<view class="course_card_des_T">{{ item.textT }}</view>
					<view class="course_card_des_info">
						<view class="course_card_des_pay">¥{{item.money}}</view>
						<view class="course_card_des_icon">
							<text class="icon iconfont icon-yonghu2"></text>
							{{item.hits}}人学过
						</view>
					</view>
				</view>
			</view>
		</view>
	</view>
</template>

<script>
	export default {
		data(){
			return{
				list:[]
			}
		},
		mounted(){
			uni.request({
				url:"http://html5.bjsxt.cn/api/index/recommend",
				success: (res) => {
					this.list = res.data.data
				}
			})
		}
	}
	
</script>

<style lang="scss">
	@import '@/common/font/iconfont.css';

	.course_card_box {
		width: 100%;
		display: flex;
		box-sizing: border-box;
		padding: 0 15px;
		margin-bottom: 15px;
		overflow: hidden;
		align-items: center;
		justify-content: center;

		.course_card_info {
			display: flex;
			box-sizing: border-box;
			width: 100%;
			background: #fff;
			border-radius: 15px;
			padding: 10px;
			margin-bottom: 15px;
			flex-direction: row;
			align-items: center; //子元素垂直居中

			.course_card_img {
				flex-shrink: 0;
				margin-right: 15px;

				image {
					width: 240rpx;
					height: 140rpx;
				}
			}

			.course_card_des {
				width: 100%;
				display: flex;
				box-sizing: border-box;
				flex-direction: column;

				.course_card_des_T {
					font-size: 16px;
					line-height: 24px;
					margin-bottom: 5px;
				}

				.course_card_des_info {
					width: 100%;
					display: flex;
					flex-direction: row; //横向排列
					box-sizing: border-box;
					justify-content: space-between;
					/* 横向中间自动空间 */
					align-content: space-between;
					/* 竖向中间自动空间 */
					flex-wrap: wrap;

					/* 换行 */
					.course_card_des_pay {
						font-size: 12px;
						color: #ff5200;

						text {
							font-size: 16px;
						}
					}

					.course_card_des_icon {
						font-size: 14px;
						color: #333;

						text {
							font-size: 14px;
							color: #666;
							margin: 0 2px 0 0;
						}
					}
				}
			}
		}
	}
</style>

8.2 首页引入

html 复制代码
<template>
	<view class="home">
 	...
		<!-- view标签功能更强大:表示一个视图 -->
		<view class="public_title">
			<view class="public_class_t">零基础就业班</view>
			<JobScroll />
		</view>
		<view class="recommend_box">
			<view class="recommed_T_box public_tow_box">
				<view class="public_T">推荐课程</view>
			</view>
			<CourseCard />
		</view>
		<view class="daotu_box">
			<view class="daotu_T">驱动教学-贯穿教|学|练|测|评</view>
			<image :src="fontBanner.img_url" mode=""></image>
		</view>
	</view>
</template>
<script>
	import Navbar from "../../../components/navbar/navbar.vue"
	import CourseNav from "../../../components/coursenav/coursenav.vue"
	import FreeCard from "../../../components/free-card/free-card.vue"
	import JobScroll from "../../../components/jobscroll/jobscroll.vue"
	import CourseCard from "../../../components/course_card/course_card.vue"
	export default {
		data() {
			return {
				//多张图片,用数组存放
				topBanner: [],
				index_banner:{},
				fontBanner:{}
			}
		},
		methods: {
			
		},
		mounted(){
				//vue的生命周期函数
				uni.request({
					url: "http://html5.bjsxt.cn/api/index/banner",
					//注意:网络请求必须要按照下面的方式发起,不能使用新语法等
					success: (res) => {
						// console.log(res)
						this.topBanner = res.data.top_banner
						this.index_banner = res.data.index_banner
						this.fontBanner = res.data.foot_banner
					}
				})
		},
		components:{
			Navbar,
			CourseNav,
			FreeCard, //引入限时免费组件
			JobScroll,
			CourseCard
		}
	}
</script>

8.3 效果

9 课程列表详情、课程介绍详情实现

9.1 新建courseIntroduce页面

①新建courseIntroduce目录及页面

②修改pages.json

js 复制代码
//在"pages"配置下新增courseIntroduce配置
        ,{
            "path" : "pages/course/courseIntroduce/courseIntroduce",
            "style" :                                                                                    
            {
                "navigationBarTitleText": "课程介绍",
				"navigationBarBackgroundColor":"#0c9c8f",
				"navigationBarTextStyle":"white",
                "enablePullDownRefresh": false
            }
        }

9.2 给coursenav.vue新增点击事件

html 复制代码
		//template部分:新增点击事件
		<view class="course_nav_info" v-for="(item, index) in list" :key="index" @click="courseItemHandle(item.id,item.course)">
			<text class="course_nav_icon icon iconfont" :class="item.icon"></text>
			<view class="course_info_text">{{item.text}}</view>
		</view>
		
		...
<script>
		...
		methods: {
			// 点击事件,点击图标跳转页面,并传入id和course
			courseItemHandle(id, course){
				uni.navigateTo({
					// url为pages中配置的courseIntroduce配置的页面路径,同时将id和course传过去
					url:"/pages/couser/courseIntroduce/courseIntroduce?id=" + id +"&course="+course
				})
			}
		}
</script>

9.3 新增course-jieshao、courseList、courseIntroduce-data component

course-jieshao.vue:

html 复制代码
<template>
	<view class="course_jieshao_box">
		<image :src="images" mode="" :style="{ height:imageHeight + 'rpx' }"></image>
	</view>
</template>

<script>
	export default {
		data() {
			return {
				
			}
		},
		props:{
			images:{
				type:String,
				defualt:""
			},
			imageHeight:{
				type:String,
				default:""
			}
		},
		methods: {
			
		}
	}
</script>

<style lang="scss">
	.course_jieshao_box{
		display: flex;
		box-sizing: box;
		flex-direction: column;
		justify-content: center;
		width: 100%;
		image{
			width: 750rpx;
			
		}
	}
</style>

courseList.vue:

html 复制代码
<template>
	<view class="course_list_box">
		<view class="course_list_con">
			<view class="course_list_info" @click="clickViode" v-for="(item,index) in videoList" :key="index">
				<view class=".course_list_info_txt">{{ item.type_name }}</view>
			</view>
		</view>
	</view>
</template>

<script>
	export default {
		data() {
			return {

			}
		},
		props: {
			videoList: {
				type: Array,
				default: function() {
					return []
				}
			}
		},
		methods: {
			clickViode(){
				uni.navigateTo({
					url:"/pages/couser/video/video"
				})
			}
		}
	}
</script>

<style lang="scss">
	.course_list_box {
		display: flex;
		box-sizing: border-box;
		flex-direction: column;
		width: 100%;
		padding: 0 15px;

		.course_list_con {
			display: flex;
			box-sizing: border-box;
			flex-direction: column;
			flex-grow: 1;

			.course_list_info {
				display: flex;
				box-sizing: border-box;
				flex-direction: center;
				overflow: hidden;
				flex: 1;
				width: 100%;
				height: 45px;
				line-height: 45px;
				font-size: 14px;
				border-bottom: 1px solid #efefef;

				.course_list_info_txt {
					white-space: nowrap;
					overflow: hidden;
					text-overflow: ellipsis;
				}
			}
		}
	}
</style>

courseIntroduce-data.vue

html 复制代码
<template>
	<view class="courseIntroduce_data_box">
		<view class="courseIntroduce_data_info" v-for="(item,index) in msg" :key="index">
			<view class="courseIntroduce_data_txt1"><text>{{ item.num }}</text></view>
			<view class="courseIntroduce_data_txt2"><text>{{ item.txt }}</text></view>
		</view>
	</view>
</template>

<script>
	export default {
		data() {
			return {
				
			}
		},
		props:{
			msg:{
				type:Array,
				default:function(){
					return []
				}
			}
		},
		methods: {
			
		}
	}
</script>

<style lang="scss">
	.courseIntroduce_data_box {
		display: flex;
		box-sizing: border-box;
		flex-direction: row;
		/*横向排列*/
		flex-wrap: wrap;
		/* 换行排列 */
		justify-content: center;
		/*居中对齐*/
		width: 100%;
		padding: 15px 10px;

		.courseIntroduce_data_info {
			display: flex;
			box-sizing: box;
			flex-direction: column;
			justify-content: center;
			align-items: center;
			width: 25%;
			height: 80px;
			flex-grow: 1;
			position: relative;

			.courseIntroduce_data_txt1 {
				text-align: center;
				width: 100%;
				font-size: 12px;
				color: #ff5200;
				overflow: hidden;
				white-space: nowrap;
				text-overflow: ellipsis;
				margin-bottom: 10px;

				text {
					font-size: 16px;
				}
			}

			.courseIntroduce_data_txt2 {
				text-align: center;
				width: 100%;
				font-size: 13px;
				color: #333;
				overflow: hidden;
				white-space: nowrap;
				text-overflow: ellipsis;
			}
		}

	}
</style>

9.4 courseIntroduce页面中引入course-jieshao、courseList、courseIntroduce-data组件

courseIntroduce.vue:

html 复制代码
<template>
	<view class="home">
		<view class="courseIntroduce_box">
			<view class="courseIntroduce_des">
				<view class="courseIntroduce_info">{{ introduce }}</view>
			</view>
			<CourseIintroduceData :msg="introduceList"/>
			<view class="question_line"></view>
			<view class="courseIntroduce_tab_box">
				<view class="courseIntroduce_tab_nav">
					<view v-for="(item,index) in items" :class="{ 'btna':count === index }" @tap="change(index)" :key="index">{{ item }}</view>
				</view>
				<view class="courseIntroduce_tab_con">
					<view class="discount_info" :class="{dis:count === 0}">
						<CourseList :videoList="Clist"/>
					</view>
					<view class="discount_info" :class="{dis:count === 1}">
						<CourseJieshao :images="imageT" :imageHeight="imageHeight"/>
					</view>
				</view>
			</view>
		</view>
	</view>
</template>

<script>
	
	import CourseIintroduceData from "../../../components/courseIntroduce-data/courseIntroduce-data.vue"
	import CourseList from "../../../components/courseList/courseList.vue"
	import CourseJieshao from "../../../components/course-jieshao/course-jieshao.vue"
	export default {
		data() {
			return {
				introduce:"",
				introduceList:[],
				items:["课程章节","课程介绍"],
				count:0,
				Clist:[],
				imageT:"",
				imageHeight:""
			}
		},
		components:{
			CourseIintroduceData,
			CourseList,
			CourseJieshao
		},
		onLoad(options) {
			uni.request({
				url: "https://www.itbaizhan.cn/api/course/detail",
				// 参数
				data: {
					id: options.id,
					course: options.course
				},
				success: (res) => {
					this.introduce = res.data.data.introduce
					this.introduceList = res.data.data.introduceList
					this.Clist = res.data.data.Clist
					this.imageT = res.data.data.image
					this.imageHeight = res.data.data.height
				}
			})
		},
		methods: {
			change(index){
				this.count = index;
			}
		}
	}
</script>
<style lang="scss">
	.courseIntroduce_box {
		display: flex;
		box-sizing: box;
		flex-direction: column;
		margin-bottom: 90px;

		.courseIntroduce_des {
			display: flex;
			box-sizing: border-box;
			flex-direction: column;
			justify-content: center;
			align-items: center;
			width: 100%;
			background-color: #0c9c8f;
			padding: 0 10px 15px;
			overflow: hidden;

			.courseIntroduce_info {
				display: flex;
				box-sizing: box;
				width: 100%;
				color: #fff;
				font-size: 16px;
				line-height: 24px;
			}
		}

		//tab
		.courseIntroduce_tab_box {
			display: flex;
			box-sizing: border-box;
			flex-direction: column;

			.courseIntroduce_tab_nav {
				display: flex;
				box-sizing: border-box;
				flex-direction: row;
				background-color: #fff;
				border-bottom: 1px solid #e4e4e4;
				margin-bottom: 20px;

				view {
					height: 50px;
					line-height: 50px;
					font-size: 16px;
					flex-grow: 1;
					text-align: center;
					background-color: #fff;

				}
			}

			.discount_info {
				display: none;
			}

			.btna {
				display: flex;
				box-sizing: border-box;
				justify-content: center; //水平方向对齐
				color: #00b783;
				position: relative;
			}

			.btna::after {
				content: '';
				width: 40px;
				height: 3px;
				background-color:#00b783;
				position: absolute;
				bottom: 0;
				left: 50%;
				margin-left: -20px;
			}

			.dis {
				display: block;
			}
		}
	}
</style>

9.5 效果

10 播放页面实现(webView)

web-view:在浏览器中内嵌网页,可以理解为一个内嵌的浏览器

10.1 创建video页面

video.vue:

html 复制代码
<template>
	<view>
		<!-- 后期根据课程详情页面跳转时传过来的数据,请求后端或者拼接对应视频地址替换即可 -->
		<web-view src="https://www.bilibili.com/video/BV1ZM4y177kh/"></web-view>
	</view>
</template>

<script>
	export default {
		data() {
			return {
				
			}
		},
		methods: {
			
		}
	}
</script>

<style>

</style>

10.2 给courseList添加点击事件跳转视频播放

courseList.vue:

html 复制代码
<template>
	<view class="course_list_box">
		<view class="course_list_con">
			<view class="course_list_info" @click="clickViode" v-for="(item,index) in videoList" :key="index">
				<view class=".course_list_info_txt">{{ item.type_name }}</view>
			</view>
		</view>
	</view>
</template>
<script>
		methods: {
			clickViode(){
				uni.navigateTo({
					// 跳转视频播放页面
					url:"/pages/course/video/video"
				})
			}
		}
	}
</script>

10.3 效果

bug

如果运行项目发现报错:'core-js/modules/es.string.iterator.js'

  • 则表明缺少core-js环境,在终端cmd执行下面命令
bash 复制代码
# 安装core-js之后,重新启动项目
npm i core-js -D

11 打包发布项目

11.1 app打包

①在manifest.json中配置AppID、图标等,如果没有AppID则重新获取

②选择应用顶部的发行 - 云打包 - 填写对应信息(证书等)

11.2 小程序打包

以微信小程序为例

①下载微信开发者工具,并开放端口供uniapp调用(设置-安全-打开服务端口)

②从uniapp直接跳转到微信开发者工具

③接下来的发布就和小程序发布一样了

详情参考:https://blog.csdn.net/weixin_45565886/article/details/130918238

填写AppId等

相关推荐
shitian08111 小时前
用轻量云服务器搭建一个开源的商城系统,含小程序和pc端
服务器·小程序·开源
计算机-秋大田2 小时前
基于微信小程序的农场管理系统的设计与实现,LW+源码+讲解
java·spring boot·微信小程序·小程序·vue
_处女座程序员的日常7 小时前
Rollup failed to resolve import “destr“ from ***/node_modules/pinia-plugin-pers
javascript·uni-app·vue
说私域9 小时前
私域流量圈层在新消费时代的机遇与挑战:兼论开源 AI 智能名片、2 + 1 链动模式、S2B2C 商城小程序的应用
人工智能·小程序
亥时科技12 小时前
相亲小程序(源码+文档+部署+讲解)
java·小程序·开源·源代码管理
wayuncn12 小时前
网站小程序app怎么查有没有备案?
小程序
2401_8441379514 小时前
PHP中小学优校管理系统小程序源码
微信·微信小程序·小程序·微信公众平台·微信开放平台
慢慢雨夜16 小时前
uniapp打包华为,提示请提供64位版本软件包后再提交审核
uni-app
秋雨凉人心16 小时前
uniapp 设置安全区域
前端·javascript·vue.js·uni-app
Little_Code16 小时前
uniapp 如何使用vuex store (亲测)
uni-app·vuex·store