Loading

头部、底部、轮播图组件

头部组件

  • 组件代码

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

    image

底部组件

  • 组件代码

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

    image

轮播图组件

  • 组件代码

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

轮播图接口

轮播图的所有图片都是向后端发送请求获取.

  • 创建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)
        
  • 请求路由

    • 路由分发, 在项目名下的总路由文件中配置路由分发.
      ...
      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/

    image

    为轮播图表添加数据

    image

  • 接口测试

    启动程序访问轮播图的接口 http://127.0.0.1:8000/home/api/Carousel/

    image

  • 前端获取数据

    前端 轮播图组件的生命周期钩子函数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>
    

    image

  • 图片跳转路由

    image

    • 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>
        
        image
    • 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
      
      image
posted @ 2022-12-03 14:13  爱learn  阅读(104)  评论(0编辑  收藏  举报