路飞项目搭建2 luffy前台主页, xadmin后台管理, 前后台分离跨域交互, 自定义配置, 浏览器屏幕缩放bug修复

前端主页

图片准备

将提供的资料中的图片移植到项目的img文件夹下

页头组件:components/Header.vue

<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 {
                url_path: sessionStorage.url_path || '/',
            }
        },
        methods: {
            goPage(url_path) {
                // 已经是当前路由就没有必要重新跳转
                if (this.url_path !== url_path) {
                    this.$router.push(url_path);
                }
                sessionStorage.url_path = url_path;
            },
        },
        created() {
            sessionStorage.url_path = this.$route.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>

轮播图组件:components/Banner.vue

<template>
    <div class="banner">
        <el-carousel 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: "Banner"
    }
</script>

<style scoped>
    .el-carousel__item {
        height: 400px;
        min-width: 1200px;    /*屏幕在1200px内不变,超过1200px变大*/
    }
    .el-carousel__item img {
        height: 400px;    /*等比例缩放*/
        margin-left: calc(50% - 1920px / 2);    /*图片放到中央*/
    }
</style>

页脚组件: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>

主页组件:views/Home.vue

<template>
    <div class="home">
        <Header />
        <Banner />
        <br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br>
        <Footer />
    </div>
</template>

<script>
    import Header from '../components/Header'
    import Footer from '../components/Footer'
    import Banner from '../components/Banner'

    export default {
        name: "Home",
        components: {
            Header,
            Footer,
            Banner,
        }
    }
</script>

后台主页模块设计

home模块

创建home模块

前提:在 luffy 虚拟环境下

1.终端从项目根目录进入apps目录
>: cd luffyapi & cd apps

2.创建app
>: python ../../manage.py startapp home

路由分发

主路由:luffyapi/urls.py
from django.urls import path, re_path, include
urlpatterns = [
    # ...
    path('home/', include('home.urls')),
    # ...
]
子路由:home/urls.py
from django.urls import path, re_path
urlpatterns = [

]

Banner数据表model设计

utils/model.py
from django.db import models

class BaseModel(models.Model):
    created_time = models.DateTimeField(auto_now_add=True, verbose_name='创建时间')
    updated_time = models.DateTimeField(auto_now=True, verbose_name='最后更新时间')
    is_delete = models.BooleanField(default=False, verbose_name='是否删除')
    is_show = models.BooleanField(default=True, verbose_name='是否上架')
    orders = models.IntegerField(verbose_name='优先级')

    class Meta:
        abstract = True
home/models.py
from django.db import models
from utils.model import BaseModel

class Banner(BaseModel):
    title = models.CharField(max_length=16, unique=True, verbose_name='名称')
    image = models.ImageField(upload_to='banner', verbose_name='图片')
    link = models.CharField(max_length=64, verbose_name='跳转链接')
    info = models.TextField(verbose_name='详情')  # 也可以用详情表,宽高出处

    class Meta:
        db_table = 'luffy_banner'
        verbose_name_plural = '轮播图表'

    def __str__(self):
        return self.title
数据迁移:在大luffyapi路径下的终端
>: python manage.py makemigrations
>: python manage.py migrate

注册home模块:dev.py

INSTALLED_APPS = [
    # ...
    'rest_framework',
    'home',
]

设计Banner数据接口

home/serializers.py
from rest_framework import serializers
from . import models
class BannerSerializer(serializers.ModelSerializer):
    class Meta:
        model = models.Banner
        fields = ['title', 'image', 'link']
home/views.py
from rest_framework.viewsets import ModelViewSet
from rest_framework import mixins
from . import models, serializers

class BannerViewSet(ModelViewSet, mixins.ListModelMixin):
    queryset = models.Banner.objects.filter(is_delete=False, is_show=True).all()
    serializer_class = serializers.BannerSerializer
home/urls.py
from django.urls import path, include
from utils.router import router
from . import views
# 注册ViewSet的路由
router.register('banners', views.BannerViewSet, 'banner')

urlpatterns = [
    path('', include(router.urls)),
]
接口
http://localhost:8000/home/banners/

xadmin后台管理

可以用simpleui代替,地址:https://github.com/newpanjing/simpleui

 安装: luffy虚拟环境下    

>: pip install https://codeload.github.com/sshwsfc/xadmin/zip/django2
注册app:dev.py
INSTALLED_APPS = [
    # ...
    # xadmin主体模块
    'xadmin',
    # 渲染表格模块
    'crispy_forms',
    # 为模型通过版本控制,可以回滚数据
    'reversion',
]
xadmin:需要自己的数据库模型类,完成数据库迁移
python manage.py makemigrations
python manage.py migrate
设置主路由替换掉admin:主urls.py
# xadmin的依赖
import xadmin
xadmin.autodiscover()
# xversion模块自动注册需要版本控制的 Model
from xadmin.plugins import xversion
xversion.register_models()

urlpatterns = [
    # ...
    path(r'xadmin/', xadmin.site.urls),
]
创建超级用户:大luffyapi路径终端
# 在项目根目录下的终端
python manage.py createsuperuser
# 账号密码设置:admin | Admin123
完成xadmin全局配置:新建home/adminx.py
# home/adminx.py
# xadmin全局配置
import xadmin
from xadmin import views

class GlobalSettings(object):
    """xadmin的全局配置"""
    site_title = "路飞学城"  # 设置站点标题
    site_footer = "路飞学城有限公司"  # 设置站点的页脚
    menu_style = "accordion"  # 设置菜单折叠

xadmin.site.register(views.CommAdminView, GlobalSettings)
在adminx.py中注册model:home/adminx.py
from . import models
# 注册
xadmin.site.register(models.Banner)

前后台分离跨域交互

问题:前后台分离项目交互时,如果出现了CORS,代表什么?如何解决

    1)服务器已经接收到了客户端请求
    2)服务器发现客户端非同域客户端(不是自家的)(ip、port、协议存在不一致)
    3)服务器不对客户端做需要响应,而是一种CORS错误响应(就是在响应头中做文章)
    处理CORS错误响应的本质:处理响应头  Access-Control-Allow-Origin

后台处理跨域

安装插件
>: pip install django-cors-headers

插件参考地址:https://github.com/ottoyiu/django-cors-headers/
项目配置:dev.py
# 注册app
INSTALLED_APPS = [
    ...
    'corsheaders',
]

# 添加中间件
MIDDLEWARE = [
    ...
    'corsheaders.middleware.CorsMiddleware',
]

# 允许跨域源
CORS_ORIGIN_ALLOW_ALL = True

# 允许的请求头
CORS_ALLOW_HEADERS = (
    "accept",
    "accept-encoding",
    "authorization",
    "content-type",
    "dnt",
    "origin",
    "user-agent",
    "x-csrftoken",
    "x-requested-with",

    # 额外允许的请求头
    'token',
)

特殊处理(不用)

views.py中

from rest_framework.response import Response
class BannerViewSet(ModelViewSet,mixins.ListModelMixin):
    queryset = models.Banner.objects.filter(is_delete=False,is_show=True).all()
    serializer_class = serializers.BannerSerializer

    # 了解CORS本质,处理还是在中间件中用插件,因为可以控制所有接口
    '''
    def list(self,request,*args,**kwargs):
        response = super().list(request,*args,**kwargs)
        # 响应头设置'Access-Control-Allow-Origin' 为'*'就代表该接口可以对任何请求完成响应
        return Response(response.data,headers={'Access-Control-Allow-Origin':'*'})
    '''

前台请求Banner数据

修订Banner.vue
<template>
    <div class="banner">
<!--        <el-carousel height="400px">-->
<!--            <el-carousel-item v-for="item in 4" :key="item">-->
<!--                <img src="../assets/img/banner1.png" alt="">-->
<!--            </el-carousel-item>-->
<!--        </el-carousel>-->
        <el-carousel height="400px">
            <el-carousel-item v-for="banner in banner_list" :key="banner.title">
                <router-link :to="banner.link">
                    <img :src="banner.image" alt="">
                </router-link>
            </el-carousel-item>
        </el-carousel>
    </div>
</template>

<script>
    export default {
        name: "Banner",
        data() {
            return {
                banner_list: []
            }
        },

        // 在created钩子中
        created() {
            this.$axios({
                url: this.$settings.base_url + '/home/banners/',    // 所有请求默认为get发送
                headers: {  // 测试前台给后台提交请求头
                    // authorization: 'jwt abc.def.xyz',    解决跨域问题,为后台默认请求头
                    // token: 'jwt abc.def.xyz',    自定义请求后,后台也必须设置该自定义请求头,否则跨域问题
                }
            }).then(response => {
                console.log(response.data);
                this.banner_list = response.data;
            }).catch(error => {
                console.log(">>>", error);
            })
        }

    }
</script>

<style scoped>
    .el-carousel__item {
        height: 400px;
        min-width: 1200px;
    }
    .el-carousel__item img {
        height: 400px;
        margin-left: calc(50% - 1920px / 2);
    }
</style>

自定义配置

自定义常量配置文件:settings/const.py

# 自定义的常量配置文件,在settings中 from 该文件 import *,将名字全部丢给settings
BANNER_COUNT = 4

加载自定义配置名称空间:settings/dev.py

# 加载自定义配置名称空间
from .const import *

在轮播图接口中应用:banner/views.py

class BannerViewSet(ModelViewSet, mixins.ListModelMixin):
    queryset = models.Banner.objects.filter(is_delete=False, is_show=True).order_by('-orders')[:settings.BANNER_COUNT]    # 反向
    serializer_class = serializers.BannerSerializer

浏览器屏幕缩放bug修复

问题:浏览器缩放时,轮播图显示不全,滚动水平滚动条,发现图片缺失

其实是element-ui插件的问题,也可以换成swiper插件解决

解决:隐藏水平滚动条,页面都只提供垂直滚动条的需求

global.css
/* 水平超出部分默认隐藏 */
#app {
    overflow: hidden;
}

猜你喜欢

转载自www.cnblogs.com/ludingchao/p/12381045.html