1. 项目分析
首页
导航、登录注册栏、轮播图、地板导航
登录注册
选项卡
免费课
课程分类、筛选、课程列表
免费课详情
课程封面视频、优惠活动倒计时、选项卡
我的购物车
全选、商品价格统计
购买结算
购买成功
我的订单
课时播放页面
2. 项目搭建
2.1 创建项目目录
cd 项目目录
vue init webpack luffy
例如,我要把项目保存在桌面下 ~/Desktop/luffy ,可以如下操作:
cd Desktop
vue init webpack luffy
效果:
根据需要在生成项目时,我们选择对应的选项。
根据上面的提示,我们已经把vue项目构建好了,接下来我们可以在pycharm编辑器中把项目打开并根据上面黄色提示,运行测试服务器。
打开项目已经,在pycharm的终端下运行vue项目,查看效果。
npm run dev
接下来,我们根据终端上效果显示的对应地址来访问项目(如果有多个vue项目在运行,8080端口被占据了,服务器会自动改端口,所以根据自己实际在操作中看到的地址来访问。)
2.2 初始化项目
清除默认的HelloWorld.vue组件和APP.vue中的默认模板代码和默认样式
<template>
<div id="app">
</div>
</template>
<script>
export default {
name: 'App',
components: {
}
}
</script>
<style>
</style>
修改后效果:
接下来,我们可以查看效果了,一张白纸~
2.3 安装路由vue-router
2.3.1 下载路由组件
npm i vue-router -S
执行效果:
2.3.2 配置路由
2.3.2.1 初始化路由对象
在src目录下创建router路由目录,在router目录下创建index.js路由文件
效果:
index.js路由文件中,编写初始化路由对象的代码 .
import Vue from "vue"
import Router from "vue-router"
// 这里导入可以让让用户访问的组件
Vue.use(Router);
export default new Router({
// 设置路由模式为‘history’,去掉默认的#
mode: "history",
routes:[
// 路由列表
]
})
2.3.2.2 注册路由信息
打开main.js文件,把router路由规则对象注册到vue中.
代码:
// The Vue build version to load with the `import` command
// (runtime-only or standalone) has been set in webpack.base.conf with an alias.
import Vue from 'vue'
import App from './App'
import router from './router/index';
Vue.config.productionTip = false
/* eslint-disable no-new */
new Vue({
el: '#app',
router,
components: { App },
template: '<App/>'
});
2.3.2.3 在视图中显示路由对应的内容
在App.vue组件中,添加显示路由对应的内容。
代码:
<template>
<div id="app">
<router-view/>
</div>
</template>
<script>
export default {
name: 'App',
components: {
}
}
</script>
<style>
</style>
3. 引入ElementUI
对于前端页面布局,我们可以使用一些开源的UI框架来配合开发,Vue开发前端项目中,比较常用的就是ElementUI了。
ElementUI是饿了么团队开发的一个UI组件框架,这个框架提前帮我们提供了很多已经写好的通用模块,我们可以在Vue项目中引入来使用,这个框架的使用类似于我们前面学习的bootstrap框架,也就是说,我们完全可以把官方文档中的组件代码拿来就用,有定制性的内容,可以直接通过样式进行覆盖修改就可以了。
中文官网:http://element-cn.eleme.io/#/zh-CN
文档快速入门:http://element-cn.eleme.io/#/zh-CN/component/quickstart
3.1 快速安装ElementUI
项目根目录执行以下命令:
npm i element-ui -S
上面的命令等同于 npm install element-ui --save
执行命令效果:
3.2 配置ElementUI到项目中
在main.js中导入ElementUI,并调用。代码:
// elementUI 导入
import ElementUI from 'element-ui';
import 'element-ui/lib/theme-chalk/index.css';
// 调用插件
Vue.use(ElementUI);
效果:
成功引入了ElementUI以后,接下来我们就可以开始进入前端页面开发,首先是首页。
4. 首页
首页采用了上下页面布局,首页是导航栏、轮播图。。。脚部等几个小模块。所以我们可以把首页作为一个组件进行开发,然后把首页的这些小模块作为单独的组件来进行开发。
4.1 创建首页组件
在src/components目录下创建文件 Home.vue
代码:
<template>
<div id="home">
首页
</div>
</template>
<script>
export default {
name:"Home",
data(){
return {
}
}
}
</script>
<style scoped>
</style>
效果:
4.1.1 创建首页对应的路由
在router/index.js中引入Home组件,并设置Home组件作为首页路由。
代码:
import Vue from "vue"
import Router from "vue-router"
// 后面这里引入可以被用户访问的页面组件
import Home from "../components/Home"
Vue.use(Router);
export default new Router({
// 路由跳转模式,注意使用 history
mode: "history",
// 路由规则
routes:[
{
// name:"路由别名",
name:"Home",
// path: "路由地址",
path: "/",
// component: 组件类名,
component: Home,
},{
// name:"路由别名",
name:"Home",
// path: "路由地址",
path: "/home",
// component: 组件类名,
component: Home,
},
]
})
效果:
4.2 开发导航子组件
经过前面的观察,可以发现导航不仅在首页出现,其他页面也有,所以对于这些不同页面中公共的内容,可以创建一个单独的组件目录存放。
创建src/components/common/Header.vue目录路径,编写代码:
<template>
</template>
<script>
export default {
name: "Header",
data(){
return {
};
}
}
</script>
<style scoped>
</style>
效果:
4.2.1 在首页引入导航组件
代码:
<template>
<div class="home">
<Header/>
</div>
</template>
<script>
import Header from "./common/Header"
export default {
name: "Home",
data(){
return {
};
},
components:{
Header,
}
}
</script>
<style scoped>
</style>
效果:
接下来,我们就可以在组件中参考ElementUI文档来进行样式开发了。
Header的子组件代码:
<template>
<div class="header">
<el-container>
<el-header>
<el-row>
<el-col class="logo" :span="3">
<a href="/">
<img src="@/assets/head-logo.svg" alt="">
</a>
</el-col>
<el-col class="nav" :span="16">
<el-row>
<el-col :span="3"><router-link to="/">免费课</router-link></el-col>
<el-col :span="3"><router-link to="/">轻课</router-link></el-col>
<el-col :span="3"><router-link to="/">学位课</router-link></el-col>
<el-col :span="3"><router-link to="/">题库</router-link></el-col>
<el-col :span="3"><router-link to="/">教育</router-link></el-col>
</el-row>
</el-col>
<el-col class="login-bar" :span="5">
<el-row>
<el-col class="cart-ico" :span="9">
<router-link to="">
<b class="goods-number">0</b>
<img class="cart-icon" src="@/assets/cart.svg" alt="">
<span>购物车</span>
</router-link>
</el-col>
<el-col class="study" :span="8" :offset="2"><router-link to="">学习中心</router-link></el-col>
<el-col class="member" :span="5">
<el-menu class="el-menu-demo" mode="horizontal">
<el-submenu index="2">
<template slot="title"><router-link to=""><img src="@/assets/logo@2x.png" alt=""></router-link></template>
<el-menu-item index="2-1">我的账户</el-menu-item>
<el-menu-item index="2-2">我的订单</el-menu-item>
<el-menu-item index="2-3">我的优惠卷</el-menu-item>
<el-menu-item index="2-3">退出登录</el-menu-item>
</el-submenu>
</el-menu>
</el-col>
</el-row>
</el-col>
</el-row>
</el-header>
</el-container>
</div>
</template>
<script>
export default {
name: "Header",
data(){
return {
// 设置一个登录标识,表示是否登录
token: false,
};
}
}
</script>
<style scoped>
.header{
box-shadow: 0 0.5px 0.5px 0 #c9c9c9;
}
.header .el-container{
1200px;
margin: 0 auto;
}
.el-header{
height: 80px!important;
padding:0;
}
.logo{
}
.logo img{
padding-top: 22px;
}
.nav{
margin-top: 22px;
}
.nav .el-col a{
display: block;
text-align: center;
padding-bottom: 16px;
padding-left: 5px;
padding-right: 5px;
position: relative;
font-size: 16px;
}
.login-bar{
margin-top: 22px;
}
.cart-ico{
position: relative;
border-radius: 17px;
}
.cart-ico:hover{
background: #f0f0f0;
}
.goods-number{
16px;
height: 16px;
line-height: 17px;
font-size: 12px;
color: #fff;
text-align: center;
background: #fa6240;
border-radius: 50%;
transform: scale(.8);
position: absolute;
left: 16px;
top: -1px;
}
.cart-icon{
15px;
height: auto;
margin-left: 6px;
}
.cart-ico span{
margin-left: 12px;
}
.member img{
26px;
height: 26px;
border-radius: 50%;
display: inline-block;
}
.member img:hover{
border: 1px solid yellow;
}
</style>
App.vue,中设置一些公共样式的代码:
<style>
body{
padding: 0;
margin:0;
}
a{
text-decoration: none;
color: #4a4a4a;
}
a:hover{
color: #000;
}
.header .el-menu li .el-submenu__title{
height: 26px!important;
line-height: 26px!important;
}
.el-menu--popup{
min- 140px;
}
</style>
Home组件中引入使用Header子组件,代码无需改变,直接访问效果:
4.3 开发轮播图子组件
4.3.1 创建Banner.vue组件文件
代码:
<template>
<div class="banner">
</div>
</template>
<script>
export default {
name:"Banner",
data(){
return {};
}
}
</script>
<style scoped>
</style>
4.3.1 在Home组件中引入Banner子组件
<template>
<div class="home">
<Header/>
<Banner/>
</div>
</template>
<script>
import Header from "./common/Header"
import Banner from "./common/Banner"
export default{
name:"Home",
data(){
return {};
},
components:{
Header,
Banner,
}
}
</script>
<style scoped>
.home{
padding-top: 80px;
}
</style>
效果:
接下来,在ElementUI中有对应的轮播图[跑马灯]效果,可以直接提取过来使用。
注意,图片保存到static目录下。保存在assets目录下的图片等同于保存在static/img目录下。
对于图片的使用,如果是vue代码中直接要使用的图片,可以保存accets目录下,如果是第三方插件要使用到的图片,需要保存在static目录下。其实本质上来说,所有的图片都是保存在static目录下的,而assets目录下的内容,最终被vue解析成地址的时候,也是在static目录的.
Banner.vue组件,代码:
<template>
<div class="banner">
<el-carousel trigger="click" height="506px">
<el-carousel-item v-for="banner in banner_list">
<a :href="banner.link"><img width="100%" :src="banner.img" alt=""></a>
</el-carousel-item>
</el-carousel>
</div>
</template>
<script>
export default {
name:"Banner",
data(){
return {
banner_list:[
{link:"http://www.baidu.com",img:"/static/banner/1.png"},
{link:"http://www.baidu.com",img:"/static/banner/2.png"},
{link:"http://www.baidu.com",img:"/static/banner/3.png"},
]
};
}
}
</script>
<style scoped>
</style>
效果:
4.5 页面脚部
4.5.1 创建脚部组件文件
代码:
<template>
<el-container>
</el-container>
</template>
<script>
export default {
name:"Footer",
data(){
return {}
}
}
</script>
<style scoped>
</style>
4.5.2 在Home组件中引入Footer组件
Home组件代码:
<template>
<div class="home">
<Header/>
<Banner/>
<Footer/>
</div>
</template>
<script>
import Header from "./common/Header"
import Banner from "./common/Banner"
import Footer from "./common/Footer"
export default{
name:"Home",
data(){
return {};
},
components:{
Header,
Banner,
Footer,
}
}
</script>
<style scoped>
.home{
padding-top: 80px;
}
</style>
效果:
4.5.3 编写脚部样式
<template>
<div class="footer">
<el-container>
<el-row>
<el-col :span="4"><router-link to="">关于我们</router-link></el-col>
<el-col :span="4"><router-link to="">联系我们</router-link></el-col>
<el-col :span="4"><router-link to="">商务合作</router-link></el-col>
<el-col :span="4"><router-link to="">帮助中心</router-link></el-col>
<el-col :span="4"><router-link to="">意见反馈</router-link></el-col>
<el-col :span="4"><router-link to="">新手指南</router-link></el-col>
<el-col :span="24"><p class="copyright">Copyright © luffycity.com版权所有 | 京ICP备17072161号-1</p></el-col>
</el-row>
</el-container>
</div>
</template>
<script>
export default {
name:"Footer",
data(){
return {}
}
}
</script>
<style scoped>
.footer{
100%;
height: 128px;
background: #25292e;
}
.footer .el-container{
1200px;
margin: auto;
}
.footer .el-row {
align-items: center;
padding: 0 200px;
padding-bottom: 15px;
100%;
margin-top: 38px;
}
.footer .el-row a{
color: #fff;
font-size: 14px;
}
.footer .el-row .copyright{
text-align: center;
color: #fff;
font-size: 14px;
}
</style>
效果:
首页的三大块我们已经完成了,但是我们开始新的页面出现之前,我们需要把链接补充上, 新增课程的导航链接.
接下来,我们就可以创建免费课的组件.
4.6 固定头部
App.vue
<style>
body{
padding: 0;
margin:0;
margin-top: 80px;
}
</style>
Header.vue,代码:
<style scoped>
.header{
top:0;
left:0;
right:0;
margin: auto;
background-color: #fff;
height: 80px;
z-index: 1000;
position: fixed;
box-shadow: 0 0.5px 0.5px 0 #c9c9c9;
}
</style>
调整轮播图左右两边的按钮
注意,style标签中要设置全局样式,所以不需要scoped
Banner.vue
<style>
.el-carousel__arrow{
100px!important;
height: 100px!important;
}
.el-icon-arrow-left{
font-size: 35px;
margin-left: 50px;
}
.el-carousel__arrow--left{
left: -50px;
}
</style>
5. 免费课
在组件目录components下创建Course.vue组件文件,代码如下:
<template>
<div class="course">
</div>
</template>
<script>
export default {
name: "Course",
data(){
return {
}
},
}
</script>
<style scoped>
</style>
5.1 在routers/index.js路由中注册路由
import Vue from "vue"
import Router from "vue-router"
// 导入可以被用户访问的组件
import Home from "@/components/Home"
import Course from "@/components/Course"
Vue.use(Router);
export default new Router({
mode: "history",
routes:[
// 路由列表
{
path: "/",
name: "Home",
component:Home,
},
{
path: "/home",
name: "Home",
component:Home,
},
{
path: "/course",
name: "Course",
component:Course,
},
]
})
5.2 完成免费课课程列表
5.2.2 文件代码结构
Course.vue,代码:
<template>
<div class="course">
<Header/>
<div class="main">
<!-- 筛选功能 -->
<div class="top">
</div>
<!-- 课程列表 --->
<div class="list">
</div>
</div>
<Footer/>
</div>
</template>
<script>
import Header from "./common/Header"
import Footer from "./common/Footer"
export default {
name: "Course",
data(){
return {
}
},
components:{Header,Footer}
}
</script>
<style scoped>
</style>
5.2.3 筛选条件的样式实现
<template>
<div class="courses">
<Header/>
<div class="main">
<!--filter function-->
<div class="top">
<ul class="condition condition1">
<li class="cate-condition">课程分类</li>
<li class="item current">全部</li>
<li class="item">Python</li>
<li class="item">Linux运维</li>
<li class="item">开发工具</li>
<li class="item">Go语言</li>
<li class="item">机器学习</li>
<li class="item">技术生涯</li>
</ul>
<ul class="condition condition2">
<li class="cate-condition">筛 选</li>
<li class="item current">默认</li>
<li class="item">人气</li>
<li class="item price">价格</li>
<li class="courses-length">共21个课程</li>
</ul>
</div>
<!--courses list-->
<div class="list">
</div>
</div>
<Footer/>
</div>
</template>
<script>
import Header from "./common/Header"
import Footer from "./common/Footer"
export default{
name: "Courses",
data(){
return {}},
components:{
Header,
Footer,
},
methods:{}
}
</script>
<style scoped>
.main{
1100px;
height: auto;
margin: 0 auto;
padding-top: 35px;
}
.main .top{
margin-bottom: 35px;
padding: 25px 30px 25px 20px;
background: #ffffff;
border-radius: 4px;
box-shadow: 0 2px 4px 0 #f0f0f0;
}
.condition{
border-bottom: 1px solid #333333;
border-bottom-color: rgba(51, 51, 51, .05);
padding-bottom: 18px;
margin-bottom: 17px;
overflow: hidden;
}
.condition li{
float: left;
}
.condition .cate-condition{
color: #888888;
font-size: 16px;
}
.condition .item{
padding: 6px 16px;
line-height: 16px;
margin-left: 14px;
position: relative;
transition: all .3s ease;
cursor: pointer;
color: #4a4a4a;
}
.condition1 .current{
color: #ffc210;
border: 1px solid #ffc210!important;
border-radius: 30px;
}
.condition2 .current{
color: #ffc210;
}
.condition .price::before{
content: "";
0;
border: 5px solid transparent;
border-top-color: #ffc210;
position: absolute;
right: 0;
bottom: 2.5px;
}
.condition .price::after{
content: "";
0;
border: 5px solid transparent;
border-bottom-color: #d8d8d8;
position: absolute;
right: 0;
top: 2.5px;
}
.condition2 .courses-length{
float: right;
font-size: 14px;
color: #9b9b9b;
}
</style>
App.vue针对列表标签进行初始化,代码:
ul{
list-style: none;
padding:0;
margin:0;
}
效果:
5.2.4 课程类表的样式实现和特效
<template>
<div class="courses">
<Header/>
<div class="main">
<!--filter function-->
<div class="top">
<ul class="condition condition1">
<li class="cate-condition">课程分类</li>
<li class="item current">全部</li>
<li class="item">Python</li>
<li class="item">Linux运维</li>
<li class="item">开发工具</li>
<li class="item">Go语言</li>
<li class="item">机器学习</li>
<li class="item">技术生涯</li>
</ul>
<ul class="condition condition2">
<li class="cate-condition">筛 选</li>
<li class="item current">默认</li>
<li class="item">人气</li>
<li class="item price">价格</li>
<li class="courses-length">共21个课程</li>
</ul>
</div>
<!--courses list-->
<div class="list">
<ul>
<li class="course-item">
<div class="course-cover">
<img src="../../static/courses/1.jpeg" alt=""/>
</div>
<div class="course-info">
<div class="course-title">
<h3>Python开发21天入门</h3>
<span>69939人已经加入学习</span>
</div>
<p class="teacher">
<span class="info">Alex 金角大王 老男孩Python教学总监</span>
<span class="lesson">共154课时/更新完成</span>
</p>
<ul class="lesson-list">
<li>
<p class="lesson-title">01 | 常用模块学习-模块的种类和导入方法</p>
<span class="free">免费</span>
</li>
<li>
<p class="lesson-title">02 | 编程语言介绍(三)高级语言</p>
<span class="free">免费</span>
</li>
<li>
<p class="lesson-title">03 | 编程语言介绍(一)</p>
<span class="free">免费</span>
</li>
<li>
<p class="lesson-title">04 | 课程介绍(二)-Python与其他语言的区别</p>
<span class="free">免费</span>
</li>
</ul>
<div class="buy-info">
<span class="discount">限时免费</span>
<span class="present-price">¥0.00元</span>
<span class="original-price">原价:9.00元</span>
<span class="buy-now">立即购买</span>
</div>
</div>
</li>
</ul>
</div>
</div>
<Footer/>
</div>
</template>
<script>
import Header from "./common/Header"
import Footer from "./common/Footer"
export default{
name: "Courses",
data(){
return {}},
components:{
Header,
Footer,
},
methods:{}
}
</script>
<style scoped>
.main{
1100px;
height: auto;
margin: 0 auto;
padding-top: 35px;
}
.main .top{
margin-bottom: 35px;
padding: 25px 30px 25px 20px;
background: #ffffff;
border-radius: 4px;
box-shadow: 0 2px 4px 0 #f0f0f0;
}
.condition{
border-bottom: 1px solid #333333;
border-bottom-color: rgba(51, 51, 51, .05);
padding-bottom: 18px;
margin-bottom: 17px;
overflow: hidden;
}
.condition li{
float: left;
}
.condition .cate-condition{
color: #888888;
font-size: 16px;
}
.condition .item{
padding: 6px 16px;
line-height: 16px;
margin-left: 14px;
position: relative;
transition: all .3s ease;
cursor: pointer;
color: #4a4a4a;
}
.condition1 .current{
color: #ffc210;
border: 1px solid #ffc210!important;
border-radius: 30px;
}
.condition2 .current{
color: #ffc210;
}
.condition .price::before{
content: "";
0;
border: 5px solid transparent;
border-top-color: #ffc210;
position: absolute;
right: 0;
bottom: 2.5px;
}
.condition .price::after{
content: "";
0;
border: 5px solid transparent;
border-bottom-color: #d8d8d8;
position: absolute;
right: 0;
top: 2.5px;
}
.condition2 .courses-length{
float: right;
font-size: 14px;
color: #9b9b9b;
}
.course-item{
background: #ffffff;
padding: 20px 30px 20px 20px;
margin-bottom: 35px;
border-radius: 2px;
cursor: pointer;
box-shadow: 2px 3px 16px rgba(0, 0, 0, .1);
transition: all .2s ease;
overflow: hidden;
}
.course-cover{
423px;
height: 210px;
margin-right: 30px;
float: left;
}
.course-info{
597px;
float: left;
}
.course-title{
margin-bottom: 8px;
overflow: hidden;
}
.course-title h3{
font-size: 26px;
color: #333333;
float: left;
}
.course-title span{
float: right;
font-size: 14px;
color: #9b9b9b;
margin-top: 12px;
text-indent: 1em;
background: url("../assets/people.svg") no-repeat 0px 3px;
}
.teacher{
justify-content: space-between;
font-size: 14px;
color: #9b9b9b;
margin-bottom: 14px;
padding-bottom: 14px;
border-bottom: 1px solid #333333;
border-bottom-color: rgba(51, 51, 51, .05);
}
.teacher .lesson{
float: right;
}
.lesson-list{
overflow: hidden;
}
.lesson-list li{
49%;
margin-bottom: 15px;
cursor: pointer;
float: left;
margin-right: 1%;
}
.lesson-list li .player{
16px;
height: 16px;
vertical-align: text-bottom;
}
.lesson-list li .lesson-title{
display: inline-block;
max- 227px;
text-overflow: ellipsis;
color: #666666;
overflow: hidden;
white-space: nowrap;
font-size: 14px;
vertical-align: text-bottom;
text-indent: 1.5em;
background: url("../../static/2.svg") no-repeat 0px 3px;
}
.lesson-list .free{
34px;
height: 20px;
color: #fd7b4d;
margin-left: 10px;
border-radius: 2px;
border: 1px solid #fd7b4d;
text-align: center;
font-size: 13px;
white-space: nowrap;
}
.lesson-list li:hover .lesson-title{
color: #ffc210;
background-image: url(../../static/2.svg);
}
.lesson-list li:hover .free{
border-color: #ffc210;
color: #ffc210;
}
.buy-info .discount{
padding: 0px 10px;
font-size: 16px;
color: #fff;
display: inline-block;
height: 36px;
text-align: center;
margin-right: 8px;
background: #fa6240;
border: 1px solid #fa6240;
border-radius: 10px 0 10px 0;
line-height: 36px;
}
.present-price{
font-size: 24px;
color: #fa6240;
}
.original-price{
text-decoration: line-through;
font-size: 14px;
color: #9b9b9b;
margin-left: 10px;
}
.buy-now{
120px;
height: 38px;
background: transparent;
color: #fa6240;
font-size: 16px;
border: 1px solid #fd7b4d;
border-radius: 3px;
transition: all .2s ease-in-out; /* 过渡动画 */
float: right;
margin-top: 5px;
}
.buy-now:hover{
color: #fff;
background: #ffc210;
border: 1px solid #ffc210;
cursor: pointer;
}
</style>
App.vue
<style>
body,h3,ul,p{
padding: 0;
margin:0;
font-weight: normal;
}
body{
margin-top: 80px;
}
a{
text-decoration: none;
color: #4a4a4a;
}
a:hover{
color: #000;
}
ul{
list-style: none;
}
img{
100%;
}
.header .el-menu li .el-submenu__title{
height: 26px!important;
line-height: 26px!important;
}
.el-menu--popup{
min- 140px;
}
</style>
6. 针对页面头部部分增加高亮和登录按钮
6.1 增加当前页面导航高亮效果
<template>
<div class="header">
<el-container>
<el-header>
<el-row>
<el-col class="logo" :span="3">
<img src="@/assets/head-logo.svg" alt=""/>
</el-col>
<el-col class="nav" :span="16">
<el-row>
<!-- 加入current 实现高亮效果 -->
<el-col :span="3"><router-link class="current" to="/home">免费课</router-link></el-col>
<el-col :span="3"><router-link to="/">轻课</router-link></el-col>
<el-col :span="3"><router-link to="/">学位课</router-link></el-col>
<el-col :span="3"><router-link to="/">题库</router-link></el-col>
<el-col :span="3"><router-link to="/">教育</router-link></el-col>
</el-row>
</el-col>
<el-col class="login-bar" :span="5">
<el-row>
<el-col class="cart-ico" :span="9">
<router-link to="">
<b class="goods-number">0</b>
<img class="cart-icon" src="@/assets/download.svg" alt=""/>
<span>购物车</span>
</router-link>
</el-col>
<el-col class="study" :span="8" :offset="2"><router-link to="">学习中心</router-link></el-col>
<el-col class="member" :span="5">
<el-menu class="el-menu-demo" mode="horizontal">
<el-submenu index="2">
<template slot="title"><router-link to=""><img src="@/assets/logo@2x.png" alt=""/></router-link></template>
<el-menu-item index="2-1">我的账户</el-menu-item>
<el-menu-item index="2-2">我的订单</el-menu-item>
<el-menu-item index="2-3">我的优惠券</el-menu-item>
<el-menu-item index="2-4">退出登录</el-menu-item>
</el-submenu>
</el-menu>
</el-col>
</el-row>
</el-col>
</el-row>
</el-header>
</el-container>
</div>
</template>
<script>
export default {
name: "Header",
data(){
return {};
}
}
</script>
<style scoped>
.header{
top: 0;
left: 0;
right: 0;
margin: auto;
background-color: #ffffff;
height: 80px;
z-index: 1000;
position: fixed;
100%;
box-shadow: 0 0.5px 0.5px 0 #c9c9c9;
}
.header .el-container{
1200px;
margin: 0 auto;
}
.el-header{
height: 80px!important;
padding: 0;
}
.logo img{
padding-top: 17px;
}
.nav{
margin-top: 22px;
}
.nav .el-col a{
display: block;
text-align: center;
margin-left: 30px;
padding-bottom: 16px;
padding-left: 5px;
padding-right: 5px;
position: relative;
font-size: 16px;
text-decoration: none;
}
/* 加入current实现高亮效果 */
.nav .el-col .current{
color: #4a4a4a;
border-bottom: 4px solid #ffc210;
}
.login-bar{
margin-top: 22px;
}
.cart-ico{
position: relative;
border-radius: 17px;
}
.cart-ico:hover{
background: #f0f0f0;
}
.goods-number{
16px;
height: 16px;
line-height: 17px;
font-size: 12px;
color: #ffffff;
text-align: center;
background: #fa6240;
border-radius: 50%;
transform: scale(.8);
position: absolute;
left: 16px;
top: -1px;
}
.cart-icon{
15px;
height: auto;
margin-left: 6px;
}
.cart-ico span{
margin-left: 12px;
}
.cart-ico a{
text-decoration: none;
}
.member img{
26px;
height: 26px;
border-radius: 50%;
display: inline-block;
}
.member img:hover{
border: 1px solid yellow;
}
.study a{
text-decoration: none;
}
</style>
6.2 根据登录状态显示登录注册按钮
<template>
<div class="header">
<el-container>
<el-header>
<el-row>
<el-col class="logo" :span="3">
<a href="/">
<img src="@/assets/head-logo.svg" alt="">
</a>
</el-col>
<el-col class="nav" :span="16">
<el-row>
<el-col :span="3"><router-link class="current" to="/">免费课</router-link></el-col>
<el-col :span="3"><router-link to="/">轻课</router-link></el-col>
<el-col :span="3"><router-link to="/">学位课</router-link></el-col>
<el-col :span="3"><router-link to="/">题库</router-link></el-col>
<el-col :span="3"><router-link to="/">教育</router-link></el-col>
</el-row>
</el-col>
<el-col class="login-bar" :span="5">
<el-row v-if="token">
<el-col class="cart-ico" :span="9">
<router-link to="">
<b class="goods-number">0</b>
<img class="cart-icon" src="@/assets/cart.svg" alt="">
<span>购物车</span>
</router-link>
</el-col>
<el-col class="study" :span="8" :offset="2"><router-link to="">学习中心</router-link></el-col>
<el-col class="member" :span="5">
<el-menu class="el-menu-demo" mode="horizontal">
<el-submenu index="2">
<template slot="title"><router-link to=""><img src="@/assets/logo@2x.png" alt=""></router-link></template>
<el-menu-item index="2-1">我的账户</el-menu-item>
<el-menu-item index="2-2">我的订单</el-menu-item>
<el-menu-item index="2-3">我的优惠卷</el-menu-item>
<el-menu-item index="2-3">退出登录</el-menu-item>
</el-submenu>
</el-menu>
</el-col>
</el-row>
<el-row v-else>
<el-col class="cart-ico" :span="9">
<router-link to="">
<img class="cart-icon" src="@/assets/cart.svg" alt="">
<span>购物车</span>
</router-link>
</el-col>
<el-col :span="10" :offset="5">
<span class="register">
<router-link to="/login">登录</router-link>
|
<router-link to="/register">注册</router-link>
</span>
</el-col>
</el-row>
</el-col>
</el-row>
</el-header>
</el-container>
</div>
</template>
<script>
export default {
name: "Header",
data(){
return {
// 设置一个登录标识,表示是否登录
token: false,
};
}
}
</script>
<style scoped>
.header{
top:0;
left:0;
right:0;
margin: auto;
background-color: #fff;
height: 80px;
z-index: 1000;
position: fixed;
box-shadow: 0 0.5px 0.5px 0 #c9c9c9;
}
.header .el-container{
1200px;
margin: 0 auto;
}
.el-header{
height: 80px!important;
padding:0;
}
.logo{
}
.logo img{
padding-top: 22px;
}
.nav{
margin-top: 22px;
}
.nav .el-col a{
display: inline-block;
text-align: center;
padding-bottom: 16px;
padding-left: 5px;
padding-right: 5px;
position: relative;
font-size: 16px;
margin-left: 20px;
}
.nav .el-col .current{
color: #4a4a4a;
border-bottom: 4px solid #ffc210;
}
.login-bar{
margin-top: 22px;
}
.cart-ico{
position: relative;
border-radius: 17px;
}
.cart-ico:hover{
background: #f0f0f0;
}
.goods-number{
16px;
height: 16px;
line-height: 17px;
font-size: 12px;
color: #fff;
text-align: center;
background: #fa6240;
border-radius: 50%;
transform: scale(.8);
position: absolute;
left: 16px;
top: -1px;
}
.cart-icon{
15px;
height: auto;
margin-left: 6px;
}
.cart-ico span{
margin-left: 12px;
}
.member img{
26px;
height: 26px;
border-radius: 50%;
display: inline-block;
}
.member img:hover{
border: 1px solid yellow;
}
</style>
data数据中使用token控制显示登录和未登录状态的效果:
token:false
token: true
7. 购物车页面
在头部公共组件中打通购物车的链接地址,Header.vue
<span><router-link to="/cart">购物车</router-link></span>
7.1 创建购物车页面组件
在components/创建Cart .vue组件文件
<template>
<div class="cart">
<Header/>
<Footer/>
</div>
</template>
<script>
import Header from "./common/Header"
import Footer from "./common/Footer"
export default {
name: "Cart",
data(){
return{
}
},
components:{Header,Footer}
}
</script>
<style scoped>
</style>
7.2 注册路由地址
routers/index.js代码:
import Cart from "@/components/Cart"
export default new Router({
// 路由跳转模式,注意使用 history
mode: "history",
// 路由规则
routes:[
。。。
,{
name:"Cart",
path: "/cart",
component: Cart,
},
]
})
7.3 显示表格数据
<template>
<div class="cart">
<Header/>
<div class="main">
<div class="cart-title">
<h3>我的购物车 <span> 共2门课程</span></h3>
<el-table :data="courseData" style="100%">
<el-table-column type="selection" label="" width="87"></el-table-column>
<el-table-column prop="title" label="课程" width="540"></el-table-column>
<el-table-column prop="expire" label="有效期" width="216"></el-table-column>
<el-table-column prop="price" label="单价" width="162"></el-table-column>
<el-table-column label="操作" width="162"></el-table-column>
</el-table>
</div>
<div calss="cart-info"></div>
</div>
<Footer/>
</div>
</template>
<script>
import Header from "./common/Header"
import Footer from "./common/Footer"
export default {
name: "Cart",
data(){
return{
courseData:[
{title:"课程标题一",expire:"2016",price:"12.00"},
{title:"课程标题一",expire:"2016",price:"12.00"},
{title:"课程标题一",expire:"2016",price:"12.00"},
{title:"课程标题一",expire:"2016",price:"12.00"},
{title:"课程标题一",expire:"2016",price:"12.00"},
{title:"课程标题一",expire:"2016",price:"12.00"},
{title:"课程标题一",expire:"2016",price:"12.00"},
{title:"课程标题一",expire:"2016",price:"12.00"},
]
}
},
components:{Header,Footer}
}
</script>
<style scoped>
.main{
1200px;
margin: 0 auto;
overflow: hidden; /* 解决body元素和标题之间的上下外边距的塌陷问题 */
}
.cart-title h3{
font-size: 18px;
color: #666;
margin: 25px 0;
}
.cart-title h3 span{
font-size: 12px;
color: #d0d0d0;
display: inline-block;
}
</style>
接下来, 我们需要在表格中输出其他的图片或者链接信息,在elementUI提供的表格组件中,我们可以使用template标签来完成.
<el-table-column prop="title" label="课程" width="540">
<template slot-scope="scope">
<img src="../../static/course/1544059695.jpeg" alt="">
<a href="">千台服务器管理系统开发实战</a>
</template>
</el-table-column>
7.4完善购物车中的数据展示
Cart.vue,代码:
<template>
<div class="cart">
<Header/>
<div class="main">
<div class="cart-title">
<h3>我的购物车 <span> 共2门课程</span></h3>
</div>
<div class="cart-info">
<el-table :data="courseData" style="100%">
<el-table-column type="selection" label="" width="87"></el-table-column>
<el-table-column label="课程" width="540">
<template slot-scope="scope">
<div class="course-box">
<img :src="scope.row.img" alt="">
{{scope.row.title}}
</div>
</template>
</el-table-column>
<el-table-column label="有效期" width="216">
<template slot-scope="scope">
<el-form ref="form" label-width="60px">
<el-form-item>
<el-select v-model="expire" placeholder="请选择有效期">
<el-option v-for="item in expire_list" :key="item.id" :label="item.title" :value="item.id"></el-option>
</el-select>
</el-form-item>
</el-form>
</template>
</el-table-column>
<el-table-column label="单价" width="162">
<template slot-scope="scope">¥{{ scope.row.price }}</template>
</el-table-column>
<el-table-column label="操作" width="162">
<a href="">删除</a>
</el-table-column>
</el-table>
</div>
<div class="cart-bottom">
<div class="select-all"><el-checkbox>全选</el-checkbox></div>
<div class="delete-any"><img src="../../static/img/ico3.png" alt="">删除</div>
<div class="cart-bottom-right">
<span class="total">总计:¥<span>0.0</span></span>
<span class="go-pay">去结算</span>
</div>
</div>
</div>
<Footer/>
</div>
</template>
<script>
import Header from "./common/Header"
import Footer from "./common/Footer"
export default {
name: "Cart",
data(){
return{
expire:3,
expire_list:[
{title:"一个月有效",id:1},
{title:"两个月有效",id:2},
{title:"三个月有效",id:3},
{title:"永久有效",id:4},
],
courseData:[
{img:"../../static/course/1544059695.jpeg",title:"课程标题一",expire:"2016",price:"12.00"},
{img:"../../static/course/1544059695.jpeg",title:"课程标题一",expire:"2016",price:"12.00"},
]
}
},
components:{Header,Footer}
}
</script>
<style scoped>
.main{
1200px;
margin: 0 auto;
overflow: hidden; /* 解决body元素和标题之间的上下外边距的塌陷问题 */
}
.cart-title h3{
font-size: 18px;
color: #666;
margin: 25px 0;
}
.cart-title h3 span{
font-size: 12px;
color: #d0d0d0;
display: inline-block;
}
.course-box img{
max- 175px;
max-height: 115px;
margin-right: 35px;
vertical-align: middle;
}
.cart-bottom{
overflow: hidden;
height: 80px;
background: #F7F7F7;
margin-bottom: 300px;
margin-top: 50px;
}
.select-all{
float: left;
margin-right: 58px;
line-height: 80px;
}
.delete-any{
cursor: pointer;
float: left;
line-height: 80px;
}
.delete-any img{
18px;
height: 18px;
vertical-align: middle;
padding-right: 15px;
}
.cart-bottom-right{
float: right;
text-align: right; /* 文本右对齐 */
}
.total{
margin-right: 62px;
font-size: 18px;
color: #666;
}
.go-pay{
outline: none;
background: #ffc210;
display: inline-block;
padding: 27px 50px;
font-size: 18px;
cursor: pointer;
color: #fff;
}
</style>
App.vue,增加修改css样式的代码:
.el-checkbox__inner{
16px;
height: 16px;
border: 1px solid #999;
}
.el-checkbox__inner:after{
6px;
height: 8px;
}
.el-form-item__content{
margin-left:0px!important;
120px;
}
8.课程详情页
创建课程详情页的组件Detai.vue,基本代码结构:
<template>
<div class="detail">
<Header/>
<div class="main">
</div>
<Footer/>
</div>
</template>
<script>
import Header from "./common/Header"
import Footer from "./common/Footer"
export default {
name: "Detail",
data(){
return {}
},
components:{
Header,
Footer,
}
}
</script>
<style scoped>
</style>
在router/index.js中增加路由
import Detail from "@/components/Detail"
// 路由规则
routes:[
,{
name:"Detail",
path: "/detail",
component: Detail,
},
]
})
在课程列表页中的li里面新增一个router-link 跳转链接。
<template>
<div class="course">
<Header/>
<div class="main">
<!-- 筛选功能 -->
<div class="top">
<ul class="condition condition1">
<li class="cate-condition">课程分类:</li>
<li class="item current">全部</li>
<li class="item">Python</li>
<li class="item">Linux运维</li>
<li class="item">Python进阶</li>
<li class="item">开发工具</li>
<li class="item">Go语言</li>
<li class="item">机器学习</li>
<li class="item">技术生涯</li>
</ul>
<ul class="condition condition2">
<li class="cate-condition">筛 选:</li>
<li class="item current">默认</li>
<li class="item">人气</li>
<li class="item price">价格</li>
<li class="course-length">共21个课程</li>
</ul>
</div>
<!-- 课程列表 --->
<div class="list">
<ul>
<li class="course-item">
<router-link to="/detail" class="course-link">
<div class="course-cover">...
<div class="course-info">...
</router-link>
</li>
...../// 省略代码
</template>
<style scoped>
.course-link{
overflow: hidden;
}
</style>
8.1课程基本信息展示
Detail.vue,代码:
<template>
<div class="detail">
<Header/>
<div class="main">
<div class="course-info">
<div class="wrap-left"></div>
<div class="wrap-right">
<h3 class="name">Linux系统基础5周入门精讲</h3>
<p class="data">23475人在学 课程总时长:148课时/180小时 难度:初级</p>
<div class="sale-time">
<p class="sale-type">限时免费</p>
<p class="expire">距离结束:仅剩 01天 04小时 33分 <span class="second">08</span> 秒</p>
</div>
<p class="course-price">
<span>活动价</span>
<span class="discount">¥0.00</span>
<span class="original">¥29.00</span>
</p>
<div class="buy">
<div class="buy-btn">
<button class="buy-now">立即购买</button>
<button class="free">免费试学</button>
</div>
<div class="add-cart"><img src="@/assets/cart-yellow.svg" alt="">加入购物车</div>
</div>
</div>
</div>
</div>
<Footer/>
</div>
</template>
<script>
import Header from "./common/Header"
import Footer from "./common/Footer"
export default {
name: "Detail",
data(){
return {}
},
components:{
Header,
Footer,
}
}
</script>
<style scoped>
.main{
background: #fff;
padding-top: 30px;
}
.course-info{
1200px;
margin: 0 auto;
overflow: hidden;
}
.wrap-left{
float: left;
690px;
height: 388px;
background-color: #000;
}
.wrap-right{
float: left;
position: relative;
height: 388px;
}
.name{
font-size: 20px;
color: #333;
padding: 10px 23px;
letter-spacing: .45px;
}
.data{
padding-left: 23px;
padding-right: 23px;
padding-bottom: 16px;
font-size: 14px;
color: #9b9b9b;
}
.sale-time{
464px;
background: #fa6240;
font-size: 14px;
color: #4a4a4a;
padding: 10px 23px;
overflow: hidden;
}
.sale-type {
font-size: 16px;
color: #fff;
letter-spacing: .36px;
float: left;
}
.sale-time .expire{
font-size: 14px;
color: #fff;
float: right;
}
.sale-time .expire .second{
24px;
display: inline-block;
background: #fafafa;
color: #5e5e5e;
padding: 6px 0;
text-align: center;
}
.course-price{
background: #fff;
font-size: 14px;
color: #4a4a4a;
padding: 5px 23px;
}
.discount{
font-size: 26px;
color: #fa6240;
margin-left: 10px;
display: inline-block;
margin-bottom: -5px;
}
.original{
font-size: 14px;
color: #9b9b9b;
margin-left: 10px;
text-decoration: line-through;
}
.buy{
464px;
padding: 0px 23px;
position: absolute;
left: 0;
bottom: 20px;
overflow: hidden;
}
.buy .buy-btn{
float: left;
}
.buy .buy-now{
125px;
height: 40px;
border: 0;
background: #ffc210;
border-radius: 4px;
color: #fff;
cursor: pointer;
margin-right: 15px;
outline: none;
}
.buy .free{
125px;
height: 40px;
border-radius: 4px;
cursor: pointer;
margin-right: 15px;
background: #fff;
color: #ffc210;
border: 1px solid #ffc210;
}
.add-cart{
float: right;
font-size: 14px;
color: #ffc210;
text-align: center;
cursor: pointer;
margin-top: 10px;
}
.add-cart img{
20px;
height: 18px;
margin-right: 7px;
vertical-align: middle;
}
</style>
效果:
8.2使用vue-video播放器
线上的路飞学城使用了AliPlayer阿里播放器。
我们本次项目使用vue-video播放器,是专门提供给vue项目使用。使用只需要完成四个步骤:
- 安装依赖
npm install vue-video-player --save
- 在main.js中注册加载组件
// The Vue build version to load with the `import` command
// (runtime-only or standalone) has been set in webpack.base.conf with an alias.
import Vue from 'vue'
import App from './App'
import router from "./routers/index"
// ElementUI plugin
import ElementUI from "element-ui"
import 'element-ui/lib/theme-chalk/index.css'
Vue.use(ElementUI);
// vue-video plugin
import 'video.js/dist/video-js.css';
import "vue-video-player/src/custom-theme.css";
import VideoPlayer from "vue-video-player";
Vue.use(VideoPlayer);
Vue.config.productionTip = false;
/* eslint-disable no-new */
new Vue({
el: '#app',
router,
components: { App },
template: '<App/>'
});
- 在课程详情页中的script标签配置播放器的参数,以下代码:
import {videoPlayer} from 'vue-video-player';
export default {
data () {
return {
playerOptions: {
playbackRates: [0.7, 1.0, 1.5, 2.0], // 播放速度
autoplay: false, //如果true,则自动播放
muted: false, // 默认情况下将会消除任何音频。
loop: false, // 循环播放
preload: 'auto', // 建议浏览器在<video>加载元素后是否应该开始下载视频数据。auto浏览器选择最佳行为,立即开始加载视频(如果浏览器支持)
language: 'zh-CN',
aspectRatio: '16:9', // 将播放器置于流畅模式,并在计算播放器的动态大小时使用该值。值应该代表一个比例 - 用冒号分隔的两个数字(例如"16:9"或"4:3")
fluid: true, // 当true时,Video.js player将拥有流体大小。换句话说,它将按比例缩放以适应其容器。
sources: [{
type: "video/mp4",
src: "http://img.ksbbs.com/asset/Mon_1703/05cacb4e02f9d9e.mp4" //你的视频地址(必填)
}],
poster: "../static/courses/675076.jpeg", //视频封面图
document.documentElement.clientWidth,
notSupportedMessage: '此视频暂无法播放,请稍后再试', //允许覆盖Video.js无法播放媒体源时显示的默认信息。
}
}
},
components: {
videoPlayer
},
methods: {
onPlayerPlay(player) {
alert("play");
},
onPlayerPause(player){
alert("pause");
},
player() {
return this.$refs.videoPlayer.player
}
}
}
在html模板中调用video-player标签显示播放器
<div class="warp-left" style=" 690px;height: 388px;background-color: #000;">
<video-player class="video-player vjs-custom-skin"
ref="videoPlayer"
:playsinline="true"
:options="playerOptions"
@play="onPlayerPlay($event)"
@pause="onPlayerPause($event)"
>
</video-player>
</div>
效果:
集成了编辑器以后的课程详情页组件代码
<template>
<div class="detail">
<Header/>
<div class="main">
<div class="course-info">
<div class="wrap-left">
<video-player class="video-player vjs-custom-skin"
ref="videoPlayer"
:playsinline="true"
:options="playerOptions"
@play="onPlayerPlay($event)"
@pause="onPlayerPause($event)"
>
</video-player>
</div>
<div class="wrap-right">
<h3 class="name">Linux系统基础5周入门精讲</h3>
<p class="data">23475人在学 课程总时长:148课时/180小时 难度:初级</p>
<div class="sale-time">
<p class="sale-type">限时免费</p>
<p class="expire">距离结束:仅剩 01天 04小时 33分 <span class="second">08</span> 秒</p>
</div>
<p class="course-price">
<span>活动价</span>
<span class="discount">¥0.00</span>
<span class="original">¥29.00</span>
</p>
<div class="buy">
<div class="buy-btn">
<button class="buy-now">立即购买</button>
<button class="free">免费试学</button>
</div>
<div class="add-cart"><img src="@/assets/cart-yellow.svg" alt="">加入购物车</div>
</div>
</div>
</div>
</div>
<Footer/>
</div>
</template>
<script>
import Header from "./common/Header"
import Footer from "./common/Footer"
import {videoPlayer} from 'vue-video-player';
export default {
name: "Detail",
data(){
return {
playerOptions: {
playbackRates: [0.7, 1.0, 1.5, 2.0], // 播放速度
autoplay: false, //如果true,则自动播放
muted: false, // 默认情况下将会消除任何音频。
loop: false, // 循环播放
preload: 'auto', // 建议浏览器在<video>加载元素后是否应该开始下载视频数据。auto浏览器选择最佳行为,立即开始加载视频(如果浏览器支持)
language: 'zh-CN',
aspectRatio: '16:9', // 将播放器置于流畅模式,并在计算播放器的动态大小时使用该值。值应该代表一个比例 - 用冒号分隔的两个数字(例如"16:9"或"4:3")
fluid: true, // 当true时,Video.js player将拥有流体大小。换句话说,它将按比例缩放以适应其容器。
sources: [{ // 播放资源和资源格式
type: "video/mp4",
src: "http://img.ksbbs.com/asset/Mon_1703/05cacb4e02f9d9e.mp4" //你的视频地址(必填)
}],
poster: "../static/courses/675076.jpeg", //视频封面图
document.documentElement.clientWidth, // 默认视频全屏时的最大宽度
notSupportedMessage: '此视频暂无法播放,请稍后再试', //允许覆盖Video.js无法播放媒体源时显示的默认信息。
}
}
},
methods: {
// 视频播放事件
onPlayerPlay(player) {
alert("play");
},
// 视频暂停播放事件
onPlayerPause(player){
alert("pause");
},
// 视频插件初始化
player() {
return this.$refs.videoPlayer.player;
}
},
components:{
Header,
Footer,
videoPlayer,
}
}
</script>
<style scoped>
.main{
background: #fff;
padding-top: 30px;
}
.course-info{
1200px;
margin: 0 auto;
overflow: hidden;
}
.wrap-left{
float: left;
690px;
height: 388px;
background-color: #000;
}
.wrap-right{
float: left;
position: relative;
height: 388px;
}
.name{
font-size: 20px;
color: #333;
padding: 10px 23px;
letter-spacing: .45px;
}
.data{
padding-left: 23px;
padding-right: 23px;
padding-bottom: 16px;
font-size: 14px;
color: #9b9b9b;
}
.sale-time{
464px;
background: #fa6240;
font-size: 14px;
color: #4a4a4a;
padding: 10px 23px;
overflow: hidden;
}
.sale-type {
font-size: 16px;
color: #fff;
letter-spacing: .36px;
float: left;
}
.sale-time .expire{
font-size: 14px;
color: #fff;
float: right;
}
.sale-time .expire .second{
24px;
display: inline-block;
background: #fafafa;
color: #5e5e5e;
padding: 6px 0;
text-align: center;
}
.course-price{
background: #fff;
font-size: 14px;
color: #4a4a4a;
padding: 5px 23px;
}
.discount{
font-size: 26px;
color: #fa6240;
margin-left: 10px;
display: inline-block;
margin-bottom: -5px;
}
.original{
font-size: 14px;
color: #9b9b9b;
margin-left: 10px;
text-decoration: line-through;
}
.buy{
464px;
padding: 0px 23px;
position: absolute;
left: 0;
bottom: 20px;
overflow: hidden;
}
.buy .buy-btn{
float: left;
}
.buy .buy-now{
125px;
height: 40px;
border: 0;
background: #ffc210;
border-radius: 4px;
color: #fff;
cursor: pointer;
margin-right: 15px;
outline: none;
}
.buy .free{
125px;
height: 40px;
border-radius: 4px;
cursor: pointer;
margin-right: 15px;
background: #fff;
color: #ffc210;
border: 1px solid #ffc210;
}
.add-cart{
float: right;
font-size: 14px;
color: #ffc210;
text-align: center;
cursor: pointer;
margin-top: 10px;
}
.add-cart img{
20px;
height: 18px;
margin-right: 7px;
vertical-align: middle;
}
</style>
8.3完成课程的选项卡内容部分以及讲师信息
<template>
<div class="detail">
<Header/>
<div class="main">
<div class="course-info">
<div class="wrap-left">
<video-player class="video-player vjs-custom-skin"
ref="videoPlayer"
:playsinline="true"
:options="playerOptions"
@play="onPlayerPlay($event)"
@pause="onPlayerPause($event)"
>
</video-player>
</div>
<div class="wrap-right">
<h3 class="course-name">Linux系统基础5周入门精讲</h3>
<p class="data">23475人在学 课程总时长:148课时/180小时 难度:初级</p>
<div class="sale-time">
<p class="sale-type">限时免费</p>
<p class="expire">距离结束:仅剩 01天 04小时 33分 <span class="second">08</span> 秒</p>
</div>
<p class="course-price">
<span>活动价</span>
<span class="discount">¥0.00</span>
<span class="original">¥29.00</span>
</p>
<div class="buy">
<div class="buy-btn">
<button class="buy-now">立即购买</button>
<button class="free">免费试学</button>
</div>
<div class="add-cart"><img src="@/assets/cart-yellow.svg" alt="">加入购物车</div>
</div>
</div>
</div>
<div class="course-tab">
<ul class="tab-list">
<li :class="tabIndex==1?'active':''" @click="tabIndex=1">详情介绍</li>
<li :class="tabIndex==2?'active':''" @click="tabIndex=2">课程章节 <span :class="tabIndex!=2?'free':''">(试学)</span></li>
<li :class="tabIndex==3?'active':''" @click="tabIndex=3">用户评论 (42)</li>
<li :class="tabIndex==4?'active':''" @click="tabIndex=4">常见问题</li>
</ul>
</div>
<div class="course-content">
<div class="course-tab-list">
<div class="tab-item" v-if="tabIndex==1">
<p><img alt="" src="https://hcdn1.luffycity.com/static/frontend/course/12/Linux01_1547102274.4025493.jpeg" width="840"></p>
<p><img alt="" src="https://hcdn1.luffycity.com/static/frontend/course/12/Linux02_1547102275.9939013.jpeg" width="840"></p>
<p><img alt="" src="https://hcdn1.luffycity.com/static/frontend/course/12/Linux03_1547102275.730511.jpeg" width="840"></p>
</div>
<div class="tab-item" v-if="tabIndex==2">
<div class="tab-item-title">
<p class="chapter">课程章节</p>
<p class="chapter-length">共11章 147个课时</p>
</div>
<div class="chapter-item">
<p class="chapter-title"><img src="@/assets/1.svg" alt="">第1章·Linux硬件基础</p>
<ul class="lesson-list">
<li class="lesson-item">
<p class="name"><span class="index">1-1</span> 课程介绍-学习流程<span class="free">免费</span></p>
<p class="time">07:30 <img src="@/assets/chapter-player.svg"></p>
<button class="try">立即试学</button>
</li>
<li class="lesson-item">
<p class="name"><span class="index">1-2</span> 服务器硬件-详解<span class="free">免费</span></p>
<p class="time">07:30 <img src="@/assets/chapter-player.svg"></p>
<button class="try">立即试学</button>
</li>
</ul>
</div>
<div class="chapter-item">
<p class="chapter-title"><img src="@/assets/1.svg" alt="">第2章·Linux发展过程</p>
<ul class="lesson-list">
<li class="lesson-item">
<p class="name"><span class="index">2-1</span> 操作系统组成-Linux发展过程</p>
<p class="time">07:30 <img src="@/assets/chapter-player.svg"></p>
<button class="try">立即购买</button>
</li>
<li class="lesson-item">
<p class="name"><span class="index">2-2</span> 自由软件-GNU-GPL核心讲解</p>
<p class="time">07:30 <img src="@/assets/chapter-player.svg"></p>
<button class="try">立即购买</button>
</li>
</ul>
</div>
</div>
<div class="tab-item" v-if="tabIndex==3">
用户评论
</div>
<div class="tab-item" v-if="tabIndex==4">
常见问题
</div>
</div>
<div class="course-side">
<div class="teacher-info">
<h4 class="side-title"><span>授课老师</span></h4>
<div class="teacher-content">
<div class="cont1">
<img src="//hcdn1.luffycity.com/static/frontend/activity/头像@3x_1509542508.019424.png">
<div class="name">
<p class="teacher-name">李泳谊</p>
<p class="teacher-title">老男孩LInux学科带头人</p>
</div>
</div>
<p class="narrative" >Linux运维技术专家,老男孩Linux金牌讲师,讲课风趣幽默、深入浅出、声音洪亮到爆炸</p>
</div>
</div>
</div>
</div>
</div>
<Footer/>
</div>
</template>
<script>
import Header from "./common/Header"
import Footer from "./common/Footer"
import {videoPlayer} from 'vue-video-player';
export default {
name: "Detail",
data(){
return {
tabIndex:2, // 当前选项卡显示的下标
playerOptions: {
playbackRates: [0.7, 1.0, 1.5, 2.0], // 播放速度
autoplay: false, //如果true,则自动播放
muted: false, // 默认情况下将会消除任何音频。
loop: false, // 循环播放
preload: 'auto', // 建议浏览器在<video>加载元素后是否应该开始下载视频数据。auto浏览器选择最佳行为,立即开始加载视频(如果浏览器支持)
language: 'zh-CN',
aspectRatio: '16:9', // 将播放器置于流畅模式,并在计算播放器的动态大小时使用该值。值应该代表一个比例 - 用冒号分隔的两个数字(例如"16:9"或"4:3")
fluid: true, // 当true时,Video.js player将拥有流体大小。换句话说,它将按比例缩放以适应其容器。
sources: [{ // 播放资源和资源格式
type: "video/mp4",
src: "http://img.ksbbs.com/asset/Mon_1703/05cacb4e02f9d9e.mp4" //你的视频地址(必填)
}],
poster: "../static/courses/675076.jpeg", //视频封面图
document.documentElement.clientWidth, // 默认视频全屏时的最大宽度
notSupportedMessage: '此视频暂无法播放,请稍后再试', //允许覆盖Video.js无法播放媒体源时显示的默认信息。
}
}
},
methods: {
// 视频播放事件
onPlayerPlay(player) {
alert("play");
},
// 视频暂停播放事件
onPlayerPause(player){
alert("pause");
},
// 视频插件初始化
player() {
return this.$refs.videoPlayer.player;
}
},
components:{
Header,
Footer,
videoPlayer,
}
}
</script>
<style scoped>
.main{
background: #fff;
padding-top: 30px;
}
.course-info{
1200px;
margin: 0 auto;
overflow: hidden;
}
.wrap-left{
float: left;
690px;
height: 388px;
background-color: #000;
}
.wrap-right{
float: left;
position: relative;
height: 388px;
}
.course-name{
font-size: 20px;
color: #333;
padding: 10px 23px;
letter-spacing: .45px;
}
.data{
padding-left: 23px;
padding-right: 23px;
padding-bottom: 16px;
font-size: 14px;
color: #9b9b9b;
}
.sale-time{
464px;
background: #fa6240;
font-size: 14px;
color: #4a4a4a;
padding: 10px 23px;
overflow: hidden;
}
.sale-type {
font-size: 16px;
color: #fff;
letter-spacing: .36px;
float: left;
}
.sale-time .expire{
font-size: 14px;
color: #fff;
float: right;
}
.sale-time .expire .second{
24px;
display: inline-block;
background: #fafafa;
color: #5e5e5e;
padding: 6px 0;
text-align: center;
}
.course-price{
background: #fff;
font-size: 14px;
color: #4a4a4a;
padding: 5px 23px;
}
.discount{
font-size: 26px;
color: #fa6240;
margin-left: 10px;
display: inline-block;
margin-bottom: -5px;
}
.original{
font-size: 14px;
color: #9b9b9b;
margin-left: 10px;
text-decoration: line-through;
}
.buy{
464px;
padding: 0px 23px;
position: absolute;
left: 0;
bottom: 20px;
overflow: hidden;
}
.buy .buy-btn{
float: left;
}
.buy .buy-now{
125px;
height: 40px;
border: 0;
background: #ffc210;
border-radius: 4px;
color: #fff;
cursor: pointer;
margin-right: 15px;
outline: none;
}
.buy .free{
125px;
height: 40px;
border-radius: 4px;
cursor: pointer;
margin-right: 15px;
background: #fff;
color: #ffc210;
border: 1px solid #ffc210;
}
.add-cart{
float: right;
font-size: 14px;
color: #ffc210;
text-align: center;
cursor: pointer;
margin-top: 10px;
}
.add-cart img{
20px;
height: 18px;
margin-right: 7px;
vertical-align: middle;
}
.course-tab{
100%;
background: #fff;
margin-bottom: 30px;
box-shadow: 0 2px 4px 0 #f0f0f0;
}
.course-tab .tab-list{
1200px;
margin: auto;
color: #4a4a4a;
overflow: hidden;
}
.tab-list li{
float: left;
margin-right: 15px;
padding: 26px 20px 16px;
font-size: 17px;
cursor: pointer;
}
.tab-list .active{
color: #ffc210;
border-bottom: 2px solid #ffc210;
}
.tab-list .free{
color: #fb7c55;
}
.course-content{
1200px;
margin: 0 auto;
background: #FAFAFA;
overflow: hidden;
padding-bottom: 40px;
}
.course-tab-list{
880px;
height: auto;
padding: 20px;
background: #fff;
float: left;
box-sizing: border-box;
overflow: hidden;
position: relative;
box-shadow: 0 2px 4px 0 #f0f0f0;
}
.tab-item{
880px;
background: #fff;
padding-bottom: 20px;
box-shadow: 0 2px 4px 0 #f0f0f0;
}
.tab-item-title{
justify-content: space-between;
padding: 25px 20px 11px;
border-radius: 4px;
margin-bottom: 20px;
border-bottom: 1px solid #333;
border-bottom-color: rgba(51,51,51,.05);
overflow: hidden;
}
.chapter{
font-size: 17px;
color: #4a4a4a;
float: left;
}
.chapter-length{
float: right;
font-size: 14px;
color: #9b9b9b;
letter-spacing: .19px;
}
.chapter-title{
font-size: 16px;
color: #4a4a4a;
letter-spacing: .26px;
padding: 12px;
background: #eee;
border-radius: 2px;
display: -ms-flexbox;
display: flex;
-ms-flex-align: center;
align-items: center;
}
.chapter-title img{
18px;
height: 18px;
margin-right: 7px;
vertical-align: middle;
}
.lesson-list{
padding:0 20px;
}
.lesson-list .lesson-item{
padding: 15px 20px 15px 36px;
cursor: pointer;
justify-content: space-between;
position: relative;
overflow: hidden;
}
.lesson-item .name{
font-size: 14px;
color: #666;
float: left;
}
.lesson-item .index{
margin-right: 5px;
}
.lesson-item .free{
font-size: 12px;
color: #fff;
letter-spacing: .19px;
background: #ffc210;
border-radius: 100px;
padding: 1px 9px;
margin-left: 10px;
}
.lesson-item .time{
font-size: 14px;
color: #666;
letter-spacing: .23px;
opacity: 1;
transition: all .15s ease-in-out;
float: right;
}
.lesson-item .time img{
18px;
height: 18px;
margin-left: 15px;
vertical-align: text-bottom;
}
.lesson-item .try{
86px;
height: 28px;
background: #ffc210;
border-radius: 4px;
font-size: 14px;
color: #fff;
position: absolute;
right: 20px;
top: 10px;
opacity: 0;
transition: all .2s ease-in-out;
cursor: pointer;
outline: none;
border: none;
}
.lesson-item:hover{
background: #fcf7ef;
box-shadow: 0 0 0 0 #f3f3f3;
}
.lesson-item:hover .name{
color: #333;
}
.lesson-item:hover .try{
opacity: 1;
}
.course-side{
300px;
height: auto;
margin-left: 20px;
float: right;
}
.teacher-info{
background: #fff;
margin-bottom: 20px;
box-shadow: 0 2px 4px 0 #f0f0f0;
}
.side-title{
font-weight: normal;
font-size: 17px;
color: #4a4a4a;
padding: 18px 14px;
border-bottom: 1px solid #333;
border-bottom-color: rgba(51,51,51,.05);
}
.side-title span{
display: inline-block;
border-left: 2px solid #ffc210;
padding-left: 12px;
}
.teacher-content{
padding: 30px 20px;
box-sizing: border-box;
}
.teacher-content .cont1{
margin-bottom: 12px;
overflow: hidden;
}
.teacher-content .cont1 img{
54px;
height: 54px;
margin-right: 12px;
float: left;
}
.teacher-content .cont1 .name{
float: right;
}
.teacher-content .cont1 .teacher-name{
188px;
font-size: 16px;
color: #4a4a4a;
padding-bottom: 4px;
}
.teacher-content .cont1 .teacher-title{
188px;
font-size: 13px;
color: #9b9b9b;
white-space: nowrap;
}
.teacher-content .narrative{
font-size: 14px;
color: #666;
line-height: 24px;
}
</style>
效果: