前端Vue项目——课程详情页面实现
一、详情页面路由跳转
应用 Vue Router 编程式导航通过 this.$router.push() 来实现路由跳转。
1、绑定查看详情事件
修改 src/components/Course/Course.vue 文件,给课程 div 绑定查看详情事件。
<div class="courseList">
<div class="detail" v-for="(course, index) in courseDetail" :key="course.id" @click="detailHandler(course.id)">
<div class="head">
<img :src="course.course_img" alt="" class="backImg">
<!-- 背景色:行内样式优先显示 -->
<b class="mask" :style="{background: course.bgColor}"></b>
<p>{{ course.name }}</p>
</div>
v-on,缩写 @ ,绑定事件监听器。事件类型由参数指定。表达式可以是一个方法的名字或一个内联语句,如果没有修饰符也可以省略。
2、定义详情事件
methods: {
// 课程详情时间操作
detailHandler(id) {
this.$router.push({
name: "course.detail",
params: {
detailId: id,
}
})
},
注意:path只能和query搭配使用,name可以和params/query搭配使用,使用params传参只能使用name进行引入。
3、定义新的路由规则
在 src/router/index.js 添加如下内容:
import CourseDetail from '@/components/Course/CourseDetail' // 配置路由规则
export default new Router({
linkActiveClass: 'is-active',
mode: 'history', // 改为history模式
routes: [
// 略
// 课程详情,路由:course/detail/web/3
{
path: '/course/detail/web/:detailId', // 动态匹配
name: 'course.detail', // 路由名称
component: CourseDetail // 对应组件
}
]
})
要把某种模式匹配到的所有路由,全部映射到同个组件。比如这里是课程详情组件,但是各个不同的课程有不同的 id,且都要用这个组件来渲染。那么可以在vue-router的路由路径中使用”动态路径参数“(dynamic segment)来实现这个效果。
一个“路径参数”使用冒号 :
标记。当匹配到一个路由时,参数值会被设置到 this.$route.params
,可以在每个组件内使用。于是,我们可以更新 CourseDetail
的模板,输出当前课程的 ID:
<template>
<div>
CourseID:{{$route.params.detailId}}
</div>
</template> <script>
export default {
name: "CourseDetail",
data() {
return { };
},
};
</script>
页面显示效果如下所示:
二、课程详情页面实现
1、课程详情顶部布局和样式
<template>
<div class="wrap">
<div class="web-course-banner">
<div class="container">
<div class="title">
<img src="../../../static/images/play.png" height="67" width="67" alt="">
<h1 class="course-title">Django框架学习</h1>
</div>
<span class="course-text">Python语言下最强大优秀的WEB框架从入门到进阶</span>
<div class="course-list">
<ul>
<li class="detail-item">
难度:初级
</li>
<li class="sep"></li>
<li class = detail-item>时长:32小时</li>
<li class="sep"></li>
<li class = detail-item>学习人数:632人</li>
<li class="sep"></li>
<li class = detail-item>评分 10.0</li>
</ul>
</div>
</div>
</div>
<!-- 代码略 -->
</div>
</template> <style lang="css" scoped>
.wrap{
width: 100%;
}
.web-course-banner{
width: 100%;
height: 512px;
background: url(../../../static/images/web-banner.1402933.png) no-repeat;
background-size: 100% 100%;
text-align: center;
overflow: hidden;
}
.container{
width: 1200px;
margin: 182px auto 0;
text-align: left;
}
.container img{
vertical-align: middle;
}
.container h1{
display: inline-block;
font-size: 48px;
color: #4a4a4a;
letter-spacing: .37px;
margin-left: 40px;
font-family: PingFangSC-Light;
font-weight: 500;
line-height: 1.1;
position: relative;
top: 10px;
}
.course-text{
width: 464px;
display: inline-block;
font-size: 22px;
color: #4a4a4a;
letter-spacing: .17px;
line-height: 36px;
margin-top: 33px;
}
.course-list{
width: 100%;
}
.course-list ul{
margin-top: 63px;
display: flex;
align-items: center;
justify-content: flex-start;
}
.course-list ul li.detail-item{
font-size: 18px;
color: #4a4a4a;
letter-spacing: .74px;
height: 26px;
padding: 0 20px;
}
.course-list ul li.sep{
width: 2px;
height: 14px;
border-left: 1px solid #979797;
}
</style>
显示效果如下所示:
2、课程详情顶部区域数据获取
上图中显示的数据都是写死在模板中的,需要通过axios从后端获取真实的数据信息。
(1)添加课程详情顶部接口
在封装axios的 api.js中添加新接口:
// 课程详情顶部数据
export const coursedetailtop = (courseid)=>{
return Axios.get('coursedetailtop/?courseid=${courseid}').then(res=>res.data);
};
(2)发送请求获取数据及绑定数据
<script>
export default {
name: 'CourseDetail',
data(){
return {
// 声明变量存储数据
coursedetailtop: {}, // 课程顶部详情数据
}
},
methods: {
// 发送请求获取课程详情顶部数据
getCoursedetailtop(){
this.$http.coursedetailtop(this.$route.params.detailId)
.then(res=>{
console.log(res);
if(!res.error_no){ // 取非判断没有错误
this.coursedetailtop = res.data;
}
})
.catch(err=>{
console.log(err);
})
}
},
created() {
this.getCoursedetailtop();
}
};
</script>
查看控制台输出如下所示:
3、课程详情顶部数据渲染
<div class="web-course-banner">
<div class="container">
<div class="title">
<img src="../../../static/images/play.png" height="67" width="67" alt="">
<h1 class="course-title">{{coursedetailtop.name}}</h1>
</div>
<span class="course-text">{{coursedetailtop.course_solgan}}</span>
<div class="course-list">
<ul>
<li class="detail-item">
难度:{{coursedetailtop.level}}
</li>
<li class="sep"></li>
<li class = detail-item>时长:{{coursedetailtop.hours}}小时</li>
<li class="sep"></li>
<li class = detail-item>学习人数:{{ coursedetailtop.learnnumber }}人</li>
<li class="sep"></li>
<li class = detail-item>评分 {{ coursedetailtop.course_review }}li>
</ul>
</div>
</div>
</div>
显示效果如下所示:
4、课程详情接口适配luffy新接口
由于luffy网站更新,原接口已经关闭,因此更新API接口(api.js):
// 课程详情顶部数据
export const coursedetailtop = (courseid)=>{
return Axios.get(`course/${courseid}/top/`).then(res=>res.data);
};
// 课程概述
export const coursedetail = (courseid)=>{
return Axios.get(`course/${courseid}/detail/`).then(res=>res.data);
};
更新 CourseDetail.vue 数据绑定:
<div class="web-course-banner">
<div class="container">
<div class="title">
<img src="../../../static/images/play.png" height="67" width="67" alt="">
<h1 class="course-title">{{coursedetailtop.name}}</h1>
</div>
<span class="course-text">{{coursedetailtop.course_solgan}}</span>
<div class="course-list">
<ul>
<li class="detail-item">
难度:{{coursedetailtop.level}}
</li>
<li class="sep"></li>
<li class = detail-item>课程总时长:{{coursedetailtop.numbers}}课时/{{coursedetailtop.hours}}小时</li>
<li class="sep"></li>
<li class = detail-item>学习人数:{{coursedetailtop.learn_number}}人</li>
</ul>
</div>
</div>
</div>
<div class="course-review">
<ul class="review-head-wrap">
<li class="head-item">课程概述</li>
<li class="head-item">课程章节</li>
<li class="head-item">用户评价({{coursedetailtop.review_number}})</li>
<li class="head-item">常见问题</li>
</ul>
</div>
显示效果:
三、课程详情套餐区实现
1、更新课程详情返回数据
getCourseDetail(){
this.$http.coursedetail(this.$route.params.detailId)
.then(res=>{
console.log(res);
// this.content = res.data.content;
this.coursedetail = res.data;
})
.catch(err=>{
console.log(err);
})
}
2、更新课程详情套餐区模板
<!-- 课程详情 -->
<div class="course-detail">
<div class="container">
<!-- v-html会将元素当成HTML标签解析后输出 -->
<section class="course_item" v-html="content"></section>
</div>
</div>
<div class="course-price">
<div class="container">
<span>可以根据不同的学习情况购买不一样的学习套餐哦!</span>
<ul class="course-price-item" >
<li v-for="(item, index) in coursedetail.prices" :key="item.id">
<p class="price">¥{{item.price}}</p>
<p class="time">有效期{{item.valid_period_name}}</p>
</li>
</ul>
<div class="course-action">
<button class="left">购买</button>
<button class="right">加入购物车</button>
</div>
</div>
</div>
显示效果如下所示:
3、点选课程样式切换
点击对应课程有效期,样式和颜色切换。
(1)定义li标签样式
.course-price ul li{
width: 200px;
height: 112px;
border: 1px solid #979797;
}
.course-price ul li.active{
background: #00CD23;
}
(2)动态绑定样式
给li标签条件绑定active类样式。同时添加点击事件:
<ul class="course-price-item" >
<li v-for="(item, index) in coursedetail.prices" :key="item.id"
:class="{active:index===currentIndex}" @click="priceClick(index)">
<p class="price">¥{{item.price}}</p>
<p class="time">有效期{{item.valid_period_name}}</p>
</li>
</ul>
在script中添加currentIndex原始数据和click点击事件:
<script>
export default {
name: 'CourseDetail',
data(){
return {
// 声明变量存储数据
coursedetailtop: {}, // 课程顶部详情数据
content: "",
// currentIndex: 0, // 为0时,页面刷新默认选择了第一项
currentIndex: null // 默认不选择
}
},
methods: {
priceClick(index){
this.currentIndex = index;
},
// 代码略
},
created() {
this.getCoursedetailtop();
this.getCourseDetail();
}
};
</script>
点击效果如下所示:
4、通过dom修改点击项字体和颜色(不推荐)
ref 加在普通的元素上,可用 this.ref.name 获取到的是dom元素。
<ul class="course-price-item" >
<li v-for="(item, index) in coursedetail.prices" :key="item.id"
:class="{active:index===currentIndex}" @click="priceClick(index)">
<p class="price" ref="price">¥{{item.price}}</p>
<p class="time" ref="time">有效期{{item.valid_period_name}}</p>
</li>
</ul>
通过js来操作dom:
methods: {
priceClick(index){
this.currentIndex = index;
this.$refs.price[index].style.color = '#fff';
this.$refs.time[index].style.color = '#fff';
},
5、绑定样式修改点击项字体和颜色
传给 v-bind:class
一个对象,以动态地切换 class :
<div class="course-price">
<div class="container">
<span>可以根据不同的学习情况购买不一样的学习套餐哦!</span>
<ul class="course-price-item" >
<li v-for="(item, index) in coursedetail.prices" :key="item.id"
:class="{active:index===currentIndex}" @click="priceClick(index)">
<p class="price" :class="{active:index===currentIndex}">¥{{item.price}}</p>
<p class="time" :class="{active:index===currentIndex}">有效期{{item.valid_period_name}}</p>
</li>
</ul>
<div class="course-action">
<button class="left">购买</button>
<button class="right">加入购物车</button>
</div>
</div>
</div>
上面语法表示 active 这个 class 存在与否取决于数据属性 index===currentIndex 的true/false。
添加点击项字体的 active 样式:
.course-price ul li p.active {
color: #fff;
}
如此,点击后会将点击项字体从黑色变成白色,优化显示效果。
四、课程购物车实现
添加购物车时,需要判断是否点选了课程套餐,没有点选课程套餐应提示错误信息。还需要判断用户是否登录,若用户未登录需要跳转到登录页面。
1、购物车点击事件
在购物车标签中添加点击事件:
<div class="course-action">
<button class="left">购买</button>
<button class="right" @click="addShopCart">加入购物车</button>
</div>
添加addShopCart方法:
<script>
export default {
name: 'CourseDetail',
data(){
return {
// 声明变量存储数据
coursedetailtop: {}, // 课程顶部详情数据
content: "",
// currentIndex: 0, // 为0时,页面刷新默认选择了第一项
currentIndex: null // 默认不选择
}
},
methods: {
// 加入购物车事件
addShopCart(){
if(this.currentIndex){ // 判断当前currentIndex是否有值 } else { }
},
// 代码略
};
</script>
这里将 currentIndex的默认值从0修改为null,这是因为如果默认为0,则默认选择了第一项,无需再提示未选中套餐。修改为 null 后,则是默认没有选择,因此可以通过 this.currentIndex 来判定当前是否选中了套餐。
2、用户未选中套餐消息提示
在没有选择套餐时点击添加购物车提示错误消息。这里采用element组件中 Message消息提示 来实现错误提示。
methods: {
// 加入购物车事件
addShopCart(){
if(this.currentIndex){ // 判断当前currentIndex是否有值 } else {
// element组件错误提示
this.$message({
message: '您还没有选择要加入的套餐哦!',
center: true // 使用 center 属性让文字水平居中
});
}
},
Element 注册了一个$message
方法用于调用,Message 可以接收一个字符串或一个 VNode 作为参数,它会被显示为正文内容。
使用 center
属性让文字水平居中。
3、点击购物车进入登录页面
用户点击购物车需要优先判断是否是登录用户,如果没有登录先跳转到登录页面。
(1)利用html本地存储功能实现登录用户信息保存
用户名、密码保存,自动登录等,可以通过设置cookie实现,第一次登录网站后在本地计算机的中写入cookie,之后再次登录此网站查看cookie中现有的值,用cookie值进行网站登录即可。但是 cookie 不适合大量数据的存储,因为它们由每个对服务器的请求来传递,这使得 cookie 速度很慢而且效率也不高。
HTML5提供了一个此类问题比较方便的解决方案,就是localstorage。数据不是由每个服务器请求传递的,而是只有在请求时使用数据。它使在不影响网站性能的情况下存储大量数据成为可能。对于不同的网站,数据存储于不同的区域,并且一个网站只能访问其自身的数据。HTML5 使用 JavaScript 来存储和访问数据。
因此可以使用 window.localStorage.getItem('token') 来判断用户是否登录。
(2)使用vue编程式导航跳转
methods: {
// 加入购物车事件
addShopCart(){
if(this.currentIndex){ // 判断当前currentIndex是否有值
if(window.localStorage.getItem('token')){ // 判断用户是否登录
// 添加到购物车 } else {
// 跳转登录页面
// 使用编程式导航来跳转
this.$router.push({
name: 'Login',
query: {
// window.location 只读属性,返回一个 Location 对象,其中包含有关文档当前位置的信息
return_url: window.location.href, // 将当前页面地址作为查询参数
}
})
}
} else {
// element组件错误提示
this.$message({
message: '您还没有选择要加入的套餐哦!',
center: true // 使用 center 属性让文字水平居中
});
}
},
在 Vue 实例内部,你可以通过 $router
访问路由实例。因此你可以调用 this.$router.push。
(3)添加Login组件和路由
在index.js中引入Login组件并配置路由信息:
import Login from '@/components/Login/Login' Vue.use(Router) // 配置路由规则
export default new Router({
linkActiveClass: 'is-active',
mode: 'history', // 改为history模式
routes: [
// 代码略
{
path: '/login',
name: 'Login',
component: Login // Login 组件
}
]
})
添加 src/components/Login/Login.vue 组件。
<template>
<div class="box">
<img src="https://www.luffycity.com/static/img/Loginbg.3377d0c.jpg" alt="">
<div class="login">
<div class="login-title">
<img src="https://www.luffycity.com/static/img/Logotitle.1ba5466.png" alt="">
<p>帮助有志向的年轻人通过努力学习获得体面的工作和生活!</p>
</div>
<div class="login_box">
<div class="title">
<span>密码登录</span>
<span>短信登录</span>
</div>
<div class="inp">
<input v-model = 'username' type="text" placeholder="用户名 / 手机号码" class="user">
<input v-model = 'password' type="password" name="" class="pwd" placeholder="密码">
<div id="geetest"></div>
<div class="rember">
<p>
<input type="checkbox" class="no" name="a"></input>
<span>记住密码</span>
</p>
<p>忘记密码</p>
</div>
<button class="login_btn">登录</button>
<p class="go_login" >没有账号 <span>立即注册</span></p>
</div>
</div>
</div>
</div>
</template> <script>
export default {
name: 'Login',
data(){
return {
username: "",
password: ""
}
}
};
</script>
显示效果如下所示:
前端Vue项目——课程详情页面实现的更多相关文章
- day82:luffy:课程详情页面显示&章节和课时显示&视频播放组件&CKEditor富文本编辑器
目录 1.初始课程详情页面 2.视频播放组件 3.课程详情页面后端接口实现 4.课程详情页面-前端 5.CKEditor富文本编辑器 6.课程章节和课时显示-后端接口 7.课程章节和课时显示-前端 1 ...
- Django day 33 vue中使用element-ui的使用,课程的相关介绍,vue绑定图片,课程列表接口,课程详情页面
一:vue中使用element-ui的使用, 二:课程的相关介绍, 三:vue绑定图片, 四:课程列表接口, 五:课程详情页面
- vue项目实现详情页后退缓存之前的数据
vue项目实现详情页后退缓存之前的数据 2019年02月19日 14:54:57 不想写代码的程序员 阅读数:244 一.需要缓存的内容: 1.后退缓存条件查询的数据 2.后退缓存分页信息 二.实 ...
- 团队开发前端VUE项目代码规范
团队开发前端VUE项目代码规范 2018年09月22日 20:18:11 我的小英短 阅读数 1658 一.规范目的: 统一编码风格,命名规范,注释要求,在团队协作中输出可读性强,易维护,风格一致 ...
- 前端Vue项目——首页/课程页面开发及Axios请求
一.首页轮播图 1.elementUI走马灯 elementUI中 Carousel 走马灯,可以在有限空间内,循环播放同一类型的图片.文字等内容. 这里使用指示器样式,可以将指示器的显示位置设置在容 ...
- 前端Vue项目——登录页面实现
一.geetest滑动验证 geetest官方文档地址:https://docs.geetest.com/ 产品——极速验证:基于深度学习的人机识别应用.极验「行为验证」是一项可以帮助你的网站与APP ...
- vue项目刷新当前页面
场景: 有时候我们在vue项目页面做了一些操作,需要刷新一下页面. 解决的办法及遇到的问题: this.$router.go(0).这种方法虽然代码很少,只有一行,但是体验很差.页面会一瞬间的白屏,体 ...
- vue项目,子页面刷新404问题
翻车事故分析: 因需对项目整体优化,调整过程,采用了路由的history模式,本地项目运行,刷新子页面都是OK的. 部署到测试服务器,正常跳转都ok,但刷新子页面就会出现404,请求变成了get,没有 ...
- (转)vue项目刷新当前页面
场景: 有时候我们在vue项目页面做了一些操作,需要刷新一下页面. 解决的办法及遇到的问题: this.$router.go(0).这种方法虽然代码很少,只有一行,但是体验很差.页面会一瞬间的白屏,体 ...
随机推荐
- Gin框架 - 数据绑定和验证
概述 上篇文章分享了 Gin 框架使用 Logrus 进行日志记录,这篇文章分享 Gin 框架的数据绑定与验证. 有读者咨询我一个问题,如何让框架的运行日志不输出控制台? 解决方案: engine : ...
- border和outline的区别
如果有一个需求,给一个元素增加一条边框,想必大家会习惯且娴熟的使用border来实现,我也是这样 但其实outline也能达到同样的效果,并且在有些场景下会更适用,比如下面的demo 使用bord ...
- springboot2使用外部的tomcat服务器创建项目步骤
使用内置的Servlet容器.应用打成可执行的jar.外置的Servlet容器:外面安装Tomcat---应用war包的方式打包: a).必须创建一个war项目:(利用idea创建好目录结构) b). ...
- 百度编辑器上传视频报Http请求错误,.net实现方式
在使用百度编辑器上传视频的时候遇到一个很奇怪的问题,当视频大小在20M以下的时候,上传正常.当大于20M时,一直报Http请求错误. 处理步骤: 1.修改编辑器配置信息,如图所示,改成你想要的大小 2 ...
- Java操作zip-压缩和解压文件
一.说明 rar格式的压缩包收费,java支持zip格式的压缩和解压 二.工具类 import java.io.*; import java.util.Enumeration; import java ...
- 小鸟初学Shell编程(六)变量赋值
变量的意义 我们在使用Linux命令或脚本的时候,会有一些输出,那么这些输出的信息可以用变量临时存储,以备我们下一条命令或脚本使用. 变量的定义 变量的定义建议用一个有意义的英文单词来代表变量,不要使 ...
- springmvc在使用@ModelAttribute注解获取Request和Response会产生线程并发不安全问题(转)
springmvc在获取Request和Response有很多方式:具体请看:https://www.cnblogs.com/wade-luffy/p/8867144.html 产生线程问题的代码如下 ...
- 基础系列(2)--- css1
css组成 css语法组成 选择器 和 声明 (多个声明用分号隔开) 声明包括 属性和属性值(多个属性值用空格隔开) 语法: 选择器{ 属性: 属性值; 属性: 属性值1 属性值2; } css样式表 ...
- 深入浅出讲解低功耗蓝牙(BLE)协议栈
详解BLE连接建立过程https://www.cnblogs.com/iini/p/8972635.html 详解BLE 空中包格式—兼BLE Link layer协议解析https://www.cn ...
- android内存管理-ION/PMEM【转】
转自:https://www.jianshu.com/p/0eac3d3ff6bb ION debug ION 在/sys/kernel/debug/ion/ 提供一个debugfs 接口. 每个he ...