头部、底部、轮播图组件
目录
头部组件
-
组件代码
在components小组件中新建Head.vue,并将img目录复制到在assets文件下
===点击查看代码===
<template> <div class="header"> <div class="slogan"> <p>老男孩IT教育 | 帮助有志向的年轻人通过努力学习获得体面的工作和生活</p> </div> <div class="nav"> <ul class="left-part"> <li class="logo"> <router-link to="/"> <img src="../assets/img/head-logo.svg" alt=""> </router-link> </li> <li class="ele"> <span @click="goPage('/free-course')" :class="{active: url_path === '/free-course'}">免费课</span> </li> <li class="ele"> <span @click="goPage('/actual-course')" :class="{active: url_path === '/actual-course'}">实战课</span> </li> <li class="ele"> <span @click="goPage('/light-course')" :class="{active: url_path === '/light-course'}">轻课</span> </li> </ul> <div class="right-part"> <div> <span>登录</span> <span class="line">|</span> <span>注册</span> </div> </div> </div> </div> </template> <script> export default { name: "Header", data() { return { // 当sessionStorage.url_path有值, 就将值赋值给url_path, 否则就将/根路径赋值给url_path url_path: sessionStorage.url_path || '/', } }, methods: { goPage(url_path) { // 已经是当前路由就没有必要重新跳转 if (this.url_path !== url_path) { this.$router.push(url_path); } // 更新sessionStorage对的url_path属性值 sessionStorage.url_path = url_path; }, }, created() { // $route属性是内置的属性, $route.path获取当前页面的路径, sessionStorage.url_path = this.$route.path; // 将当前路径分别赋值给 Vue对象 与 sessionStorage 对象 的 url_path属性 this.url_path = this.$route.path; } } </script> <style scoped> .header { background-color: white; box-shadow: 0 0 5px 0 #aaa; } .header:after { content: ""; display: block; clear: both; } .slogan { background-color: #eee; height: 40px; } .slogan p { width: 1200px; margin: 0 auto; color: #aaa; font-size: 13px; line-height: 40px; } .nav { background-color: white; user-select: none; width: 1200px; margin: 0 auto; } .nav ul { padding: 15px 0; float: left; } .nav ul:after { clear: both; content: ''; display: block; } .nav ul li { float: left; } .logo { margin-right: 20px; } .ele { margin: 0 20px; } .ele span { display: block; font: 15px/36px '微软雅黑'; border-bottom: 2px solid transparent; cursor: pointer; } .ele span:hover { border-bottom-color: orange; } .ele span.active { color: orange; border-bottom-color: orange; } .right-part { float: right; } .right-part .line { margin: 0 10px; } .right-part span { line-height: 68px; cursor: pointer; } </style>
-
使用组件
home页面组件中使用,使用组件可以是
<Head></Head>
也可以是<Head/>
<template> <div class="home"> <Head></Head> </div> </template> <script> import Head from '@/components/Head' export default { name: 'HomeView', // 注册组件 components: { Head, // 头部组件 } } </script>
底部组件
-
组件代码
在components小组件中新建Footer.vue
点击查看代码
<template> <div class="footer"> <ul> <li>关于我们</li> <li>联系我们</li> <li>商务合作</li> <li>帮助中心</li> <li>意见反馈</li> <li>新手指南</li> </ul> <p>Copyright © luffycity.com版权所有 | 京ICP备17072161号-1</p> </div> </template> <script> export default { name: "Footer" } </script> <style scoped> .footer { width: 100%; height: 128px; background: #25292e; color: #fff; } .footer ul { margin: 0 auto 16px; padding-top: 38px; width: 810px; } .footer ul li { float: left; width: 112px; margin: 0 10px; text-align: center; font-size: 14px; } .footer ul::after { content: ""; display: block; clear: both; } .footer p { text-align: center; font-size: 12px; } </style>
-
使用组件
在home页面组件中使用,使用组件可以是
<Footer></Footer>
也可以是<Footer/>
<template> <div class="home"> <!--头部组件--> <Head></Head> <!--导入底部组件--> <Footer></Footer> </div> </template> <script> // 导入头部组件 import Head from '@/components/Head' // 导入底部组件 import Footer from '@/components/Footer' export default { name: 'HomeView', // 注册组件 components: { Head, // 头部组件 Footer, // 底部组件 } } </script>
轮播图组件
-
组件代码
在components小组件中新建Carousel.vue ===》 element快速传送门
<template> <div id="Carousel"> <!--高400px--> <el-carousel indicator-position="outside" height="400px"> <el-carousel-item v-for="item in 4" :key="item"> <img src="../assets/img/banner1.png" alt=""> </el-carousel-item> </el-carousel> </div> </template> <script> export default { name: 'Carousel', } </script> <style scoped> /* 高400px 最小宽度1200px */ .el-carousel__item { height: 400px; min-width: 1200px; } /* 高400px 图片居中 */ .el-carousel__item img { height: 400px; margin-left: calc(50% - 1920px / 2); } </style>
-
使用组件
<template> <div class="home"> <!--头部组件--> <Head></Head> <!--轮播图组件--> <Carousel></Carousel> <!--导入底部组件--> <Footer></Footer> </div> </template> <script> // 导入头部组件 import Head from '@/components/Head' // 导入底部组件 import Footer from '@/components/Footer' // 导入轮播图组件 import Carousel from '@/components/Carousel' export default { name: 'HomeView', // 注册组件 components: { Head, // 头部组件 Footer, // 底部组件 Carousel, // 轮播图组件 } } </script>
轮播图接口
轮播图的所有图片都是向后端发送请求获取.
-
创建APP
# 切换到apps路径下创建应用 PS F:\synchro\Project\luffy> cd luffy/apps PS F:\synchro\Project\luffy\luffy\apps> python ../../manage.py startapp home
# 注册app INSTALLED_APPS = [ ... 'home', ]
-
设置数据表
-
在apps下的utils的目录下新建models.py 数据库的基础字段
from django.db import models # 表的基础字段 class BaseModel(models.Model): # 创建时间 auto_now_add=True(创建数据时自动创建) create_time = models.DateTimeField(auto_now_add=True, verbose_name='创建时间') # 最后一次更新时间 update_time = models.DateTimeField(auto_now=True, verbose_name='最后一次更新时间') # 是否删除 (默认设置为False 不删除) is_delete = models.BooleanField(default=False, verbose_name='是否删除') # 是否展示 (默认设置为False 不显示) is_show = models.BooleanField(default=False, verbose_name='是否展示') # 显示顺序 display_order = models.IntegerField(verbose_name='显示顺序') class Meta: # Abstract(抽象)可以修饰类、方法 为True则此类必须被继承使用, 此类不可生成对象, 必须被继承使用. # 如果不设置会生成这样表, 我们不需要这个表只想继承它 abstract = True
-
在home 目录的models.py 中继承继承字段类, 创建轮播图表
from django.db import models # 导入model表继承字段 from utils.model import BaseModel # 创建轮播图表 class CarouselModel(BaseModel): # 图片的名字 name = models.CharField(max_length=32, verbose_name='图片名称') # 图片 (upload_to指定图片上传的地址, help_text提示信息, null=True 图片可以为空) img = models.ImageField(upload_to='Carousel', verbose_name='轮播图', help_text='图片尺寸必须是: 3840*800', null=True) # 点击图片跳转的地址 link = models.CharField(max_length=128, verbose_name='跳转地址') # 图片信息 info = models.TextField(verbose_name='图片信息') # 在后台打印对象的时候展示名字 def __str__(self): return self.name # 在后台显示的名称 class Meta: # verbose_name = '轮播图表' # 加s verbose_name_plural = '轮播图表' # 不加s
-
数据库迁移
-
python manage.py makemigrations
-
python manage.py migrate
-
-
-
模型序列化器
在项目名目录下的utils目录下新建Serializer.py 序列模块文件
# 导入序列化器模块 from rest_framework import serializers # 导入home的模型层 from home import models # 轮播图表模型序列化器 class CarouselModelSerializer(serializers.ModelSerializer): # 定义Meta类 class Meta: # 对应的模型表 model = models.CarouselModel # 序列化的字段 fields = ['name', 'link', 'img']
-
视图类
- 在utils目录下新建const.py 文件 (记录一些常量)
# 获取轮播图的数量 CAROUSEL_SHOW_QUANTITY = 3
- 在home apps的视图层中写视图类.
# 1. 轮播图接口 # 导入ListAPIView (继承GenericAPIView, ListModelMixin from rest_framework.generics import ListAPIView # 导入模型层 from . import models # 导入序列化器模块, 自定义的响应对象 from utils import Serializer, api_response # 导入配置文件, 先从dev配置文件中加在数据, 如果没有会去内置的配置文件中找 from django.conf import settings # 导入模型 class CarouselAPI(ListAPIView): # 设置queryset属性值 过滤没有删除 要显示的数据, 查询之后按display_order排序, 在通过索取值取指定的数量 queryset = models.CarouselModel.objects.filter(is_delete=False, is_show=False).order_by('display_order')[ :settings.CAROUSEL_SHOW_QUANTITY] # 设置使用的模型序列化器 serializer_class = Serializer.CarouselModelSerializer # 写一个静态方法, 源码 return Response(serializer.data) 改为下面这个静态方法, 静态方法调用自定义的数据返回格式 @staticmethod def response(serializer_data): return api_response.ResponseDataFormat(data=serializer_data)
- ListModelMixin源码中使用在视图类中定义的方法.
class ListModelMixin: """ List a queryset. """ def list(self, request, *args, **kwargs): queryset = self.filter_queryset(self.get_queryset()) page = self.paginate_queryset(queryset) if page is not None: serializer = self.get_serializer(page, many=True) return self.get_paginated_response(serializer.data) serializer = self.get_serializer(queryset, many=True) # return Response(serializer.data) return self.response(serializer.data)
- 另一种方式: 在数图类中定义ListModelMixin的list方法, 先调用父类的ListModelMixin的list(也就是内置的),得到一个Response对象, 充对象中将数据取出放进自己定义的response对象中返回.
# 导入模型 class CarouselAPI(ListAPIView): # 设置queryset属性值 过滤没有删除 要显示的数据, 查询之后按display_order排序, 在通过索取值取指定的数量 queryset = models.CarouselModel.objects.filter(is_delete=False, is_show=False).order_by('display_order')[ :settings.CAROUSEL_SHOW_QUANTITY] # 设置使用的模型序列化器 serializer_class = Serializer.CarouselModelSerializer def list(self, request, *args, **kwargs): # 调用父类的方法, 修改的源码恢复原样 res = super().list(request, *args, **kwargs) print(res) return api_response.ResponseDataFormat(data=res.data)
- ListModelMixin源码中使用在视图类中定义的方法.
- 在utils目录下新建const.py 文件 (记录一些常量)
-
请求路由
- 路由分发, 在项目名下的总路由文件中配置路由分发.
... urlpatterns = [ # 修改为访问的页面为xadmin的页面 re_path('^xadmin/', xadmin.site.urls), re_path('^media/(?P<path>.*)', serve, {'document_root': settings.MEDIA_ROOT}), # 路由分发到user app re_path('user/', include('user.urls')), # 路由分发到home app re_path('home/', include('home.urls')) ]
- 在home app目录中新建urls.py 子路由文件
from django.urls import re_path from home import views urlpatterns = [ # 不能有^ re_path(r'api/Carousel/', views.CarouselAPI.as_view()) ]
- 路由分发, 在项目名下的总路由文件中配置路由分发.
-
注册表到后台
在home的admin.py 中把轮播图表中注册到xadmin后台管理中
import xadmin from . import models # 将轮播图表添加到后台管理中 xadmin.site.register(models.CarouselModel)
-
后台管理
启动程序 登入到后台 http://127.0.0.1:8000/xadmin/
为轮播图表添加数据
-
接口测试
启动程序访问轮播图的接口 http://127.0.0.1:8000/home/api/Carousel/
-
前端获取数据
前端 轮播图组件的生命周期钩子函数created中发送axios请求获取数据.
点击查看代码
<template> <div id="Carousel"> <!--高400px--> <el-carousel indicator-position="outside" height="400px"> <!--从遍历数组 [对象 索引] 为key设置一个唯一的值--> <el-carousel-item v-for="(item, index) in carousel_list" :key="index"> <!--对象.link 点击图片跳转的地址--> <router-link :to="item.link"> <!--key设置为一个唯一的值--> <img :src="item.img" :alt="item.name" > </router-link> </el-carousel-item> </el-carousel> </div> </template> <script> export default { name: 'Carousel', // 定义模板中使用的变量 data() { return { carousel_list: [] } }, // created() { // 发送axios请求 http://127.0.0.1:8000 + /home/api/Carousel/ 注意不会自动加/ this.$axios.get(this.$settings.base_url + '/home/api/Carousel/').then(response => { this.carousel_list = response.data.data // console.log(this.carousel_list) }).catch(error => { alert(error) }) } } </script> <style scoped> /* 高400px 最小宽度1200px */ .el-carousel__item { height: 400px; min-width: 1200px; } /* 高400px 图片居中 */ .el-carousel__item img { height: 400px; margin-left: calc(50% - 1920px / 2); } </style>
-
图片跳转路由
-
src目录views目录下新建页面组件
- FreeCourse.vue 免费课程页面组件
<!-- FreeCourse.vue 实战课程页面 --> <template> <div> <Head></Head> <h1>实战课程页面</h1> <Footer></Footer> </div> </template> <script> // 导入头部组件 import Head from '@/components/Head' // 导入底部组件 import Footer from '@/components/Footer' export default { name: "actual-course.vue", components: { Head, // 头部组件 Footer, // 底部组件 } } </script> <style scoped> </style>
- ActualCourse.vue 实战课程页面组件
<!-- ActualCourse.vue 免费课程页面 --> <template> <div> <Head></Head> <h1>免费课程页面</h1> <Footer></Footer> </div> </template> <script> // 导入头部组件 import Head from '@/components/Head' // 导入底部组件 import Footer from '@/components/Footer' export default { name: "free-course.vue", components: { Head, // 头部组件 Footer, // 底部组件 } } </script> <style scoped> </style>
- LightCourse.vue 轻课页面组件
<!-- LightCourse.vue 轻课页面 --> <template> <div> <Head></Head> <h1>轻课页面</h1> <Footer></Footer> </div> </template> <script> // 导入头部组件 import Head from '@/components/Head' // 导入底部组件 import Footer from '@/components/Footer' export default { name: "light-course.vue", components: { Head, // 头部组件 Footer, // 底部组件 } } </script> <style scoped> </style>
- FreeCourse.vue 免费课程页面组件
-
src目录下的router目录下的index.js文件中 添加路由
import Vue from 'vue' import VueRouter from 'vue-router' import HomeView from '../views/HomeView.vue' // 导入免费课程页面组件 import FreeCourse from '../views/FreeCourse.vue' // 导入实战课程页面组件 import ActualCourse from '../views/ActualCourse' // 导入轻课程页面组件 import LightCourse from '../views/LightCourse' Vue.use(VueRouter) const routes = [ // 主页路由 { path: '/', // 路由 name: 'home', // 名字 component: HomeView // 使用的的组件 }, // 免费课程页面路由 { path: '/free-course', name: 'FreeCourse', component: FreeCourse }, // 实战课程页面路由 { path: '/actual-course', name: 'ActualCourse', component: ActualCourse }, // 轻课程页面路由 { path: '/light-course', name: 'LightCourse', component: LightCourse }, ] const router = new VueRouter({ routes }) export default router
-