Luffy /3/ 前臺主頁搭建&輪播圖介面

HammerZe發表於2022-04-21

前臺主頁搭建

vue前端元件開發

components/Homeviwe.vue

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

        <!--        推薦課程-->
        <div class="course">
            <el-row>
                <el-col :span="6" v-for="(o, index) in 8" :key="o">
                    <el-card :body-style="{ padding: '0px' }" class="course_card">
                        <img src="https://tva1.sinaimg.cn/large/e6c9d24egy1h1g0zd133mj20l20a875i.jpg" class="image">
                        <div style="padding: 14px;">
                            <span>推薦的課程</span>
                            <div class="bottom clearfix">
                                <time class="time">價格:100元</time>
                                <el-button type="text" class="button">檢視詳情</el-button>
                            </div>
                        </div>
                    </el-card>
                </el-col>
            </el-row>
        </div>
        <img src="https://tva1.sinaimg.cn/large/e6c9d24egy1h1g112oiclj224l0u0jxl.jpg" alt="" height="500px"
             width="100%">

        <Footer></Footer>
    </div>
</template>

<script>
    import Footer from "@/components/Footer";
    import Header from "@/components/Header";
    import Banner from "@/components/Banner";

    export default {
        name: 'HomeView',
        data() {
            return {}
        },
        components: {
            Footer,
            Header,
            Banner
        }
    }
</script>

<style scoped>
    .time {
        font-size: 13px;
        color: #999;
    }

    .bottom {
        margin-top: 13px;
        line-height: 12px;
    }

    .button {
        padding: 0;
        float: right;
    }

    .image {
        width: 100%;
        display: block;
    }

    .clearfix:before,
    .clearfix:after {
        display: table;
        content: "";
    }

    .clearfix:after {
        clear: both
    }

    .course {
        margin-left: 20px;
        margin-right: 20px;
    }

    .course_card {
        margin: 50px;
    }
</style>

components/Banner.vue

<template>
    <div class="banner">
        <el-carousel :interval="5000" arrow="always" 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;
    }

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

components/Header.vue

<template>
    <div class="header">
        <div class="slogan">
            <p>路飛學城 | 幫助有志向的年輕人通過努力學習獲得體面的工作和生活</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/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>

image-20220420222337241

後臺主頁輪播圖介面

建立home應用

startapp home

表設計

utils/model.py/BaseModel

from django.db import models
# 5個公共欄位
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  # 表示它是虛擬的,不在資料庫中生成表,它只用來做繼承

遷移資料,建立超級使用者

命令

# python manage.py makemigrations  ---》如果沒有變化,是app沒註冊
# python manage.py migrate
# python manage.py createsuperuser  --->建立個使用者

pycharm快捷

image-20220420222958214

引入simpleui,錄入資料

# 下載
    pip install django-simpleui
    
# dev.py註冊app
INSTALLED_APPS = [
      'simpleui',
      ...
  ]


# 在home/admin中寫
from django.contrib import admin
from .models import Banner

@admin.register(Banner)
class BannerAdmin(admin.ModelAdmin):
    list_display = ('id', 'title', 'link','is_show', 'is_delete')

    # 增加自定義按鈕
    actions = ['make_copy']
    def make_copy(self, request, queryset):
        # 選中一些資料,點選 【自定義按鈕】  觸發方法執行,傳入你選中 queryset
        # 儲存,刪除
        print(queryset)
    make_copy.short_description = '自定義按鈕'

輪播圖介面格式

格式如下,可以使用自定製的APIResponse

{code:100,msg:成功,result:[{img:地址,link:跳轉地址,orders:順序,title:名字},{img:地址,link:跳轉地址,orders:順序,title:名字}]}

輪播圖介面實現

總路由:urls.py

urlpatterns = [
    path('admin/', admin.site.urls),
    path('api/v1/home/', include('home.urls')), # http://127.0.0.1:8000/api/v1/home/banner/
]

home路由:urls.py

from django.urls import path, include
from rest_framework.routers import SimpleRouter
from .views import BannerView

router = SimpleRouter()
router.register('banner', BannerView, 'banner')
urlpatterns = [
    path('', include(router.urls)),

]

檢視類

from .models import Banner
from .serializer import BannerSerializer
from utils.response import APIResponse
from rest_framework.viewsets import GenericViewSet
from rest_framework.mixins import ListModelMixin
class BannerView(GenericViewSet,ListModelMixin):
    # 獲取所有介面-list,自動生成路由
    queryset = Banner.objects.filter(is_delete=False,is_show=True).order_by('orders')
    serializer_class =BannerSerializer

    def list(self, request, *args, **kwargs): # 重寫list
        res=super().list(request, *args, **kwargs)
        return APIResponse(result=res.data)

序列化類

from rest_framework import serializers
from .models import Banner

class BannerSerializer(serializers.ModelSerializer):
    class Meta:
        model = Banner
        fields = ['title', 'image', 'link', 'orders']

image-20220420223917615


處理跨域請求

image-20220420230040685

同源策略

同源策略(Same origin policy)是一種約定,它是瀏覽器最核心也最基本的安全功能,如果缺少了同源策略,則瀏覽器的正常功能可能都會受到影響。可以說Web是構建在同源策略基礎之上的,瀏覽器只是針對同源策略的一種實現

請求的url地址,必須與瀏覽器上的url地址處於同域上,也就是域名,埠,協議相同,否則,載入回來的資料就會禁止,比如:前端Vue專案是http://127.0.0.1:8080,後端專案地址http://127.0.0.1:8000,那麼這倆就屬於不同源,前後端分離,就會遇到這個問題。

瀏覽器上就會報錯,這個就是同源策略的保護,如果瀏覽器對javascript沒有同源策略的保護,那麼一些重要的機密網站將會很危險

image-20220420230430971

但是注意,專案2中的訪問已經發生了,說明是瀏覽器對非同源請求返回的結果做了攔截

CORS(跨域資源共享)簡介

CORS需要瀏覽器和伺服器同時支援。目前,大部分瀏覽器都支援該功能。

整個CORS通訊過程,都是瀏覽器自動完成,不需要使用者參與。對於開發者來說,CORS通訊與同源的AJAX通訊沒有差別,程式碼完全一樣。瀏覽器一旦發現AJAX請求跨源,就會自動新增一些附加的頭資訊,有時還會多出一次附加的請求,但使用者不會有感覺。

因此,實現CORS通訊的關鍵是伺服器。只要伺服器實現了CORS介面,就可以跨源通訊,只需要在響應頭中指定,允許跨域即可

比較老的技術比如:jsonp技術,如果出現了跨域問題它可以通過img,script,link標籤的連線功能,利用js的漏洞執行回撥函式解決

jsonp

CORS分類

瀏覽器將CORS請求分成兩類:簡單請求(simple request)和非簡單請求(not-so-simple request)

如何區分這兩種?

只要同時滿足以下兩大條件,就屬於簡單請求,否則就是非簡單請求

1-請求方法是以下三種方法之一:
HEAD
GET
POST
2-HTTP的頭資訊不超出以下幾種欄位:
Accept
Accept-Language
Content-Language
Last-Event-ID
Content-Type:只限於三個值application/x-www-form-urlencoded、multipart/form-data、text/plain

比如,post請求,josn格式是什麼請求? 非簡單請求

簡單請求和非簡單請求的區別

  • 簡單請求:一次請求,直接發真正的請求,如果允許,資料拿回來,如果不允許,瀏覽器攔截
  • 非簡單請求:兩次請求,在傳送資料之前會先發一次請求用於做“預檢”,只有“預檢”通過後才再傳送一次請求用於資料傳輸。非簡單請求發兩次,第一次是OPTIONS請求,如果允許跨域,再發真正的請求

解決跨域

方式一:

  1. 簡單請求再響應頭中加入:"Access-Control-Allow-Origin":"*"

  2. 非簡單,我們們要加判斷,如果是OPTIONS請求,在響應頭中加入允許

    # DRF中使用
    Response(result=res.data,headers={"Access-Control-Allow-Origin":"*"})
    

方式二

django中寫個中介軟體,處理跨域,配置到配置檔案

from django.utils.deprecation import MiddlewareMixin
class CorsMiddleWare(MiddlewareMixin):
    def process_response(self,request,response):
        if request.method=="OPTIONS":
            #可以加*
            response["Access-Control-Allow-Headers"]="Content-Type"
        response["Access-Control-Allow-Origin"] = "*"
        return response

方式三

使用第三方模組django-cors-headers

  1. 下載pip install django-cors-headers

  2. app註冊

 INSTALLED_APPS = (
    ...
    'corsheaders',
    ...
  )
  1. 中介軟體註冊
  MIDDLEWARE = [  
      # Or MIDDLEWARE_CLASSES on Django < 1.10
    ...
    'corsheaders.middleware.CorsMiddleware',
    ...
  ]
  1. 配置檔案配置
CORS_ALLOW_CREDENTIALS = True
CORS_ORIGIN_ALLOW_ALL = True
CORS_ORIGIN_WHITELIST = (
	'*'
)
CORS_ALLOW_METHODS = (
	'DELETE',
	'GET',
	'OPTIONS',
	'PATCH',
	'POST',
	'PUT',
	'VIEW',
)

CORS_ALLOW_HEADERS = (
	'XMLHttpRequest',
	'X_FILENAME',
	'accept-encoding',
	'authorization',
	'content-type',
	'dnt',
	'origin',
	'user-agent',
	'x-csrftoken',
	'x-requested-with',
	'Pragma',
)

輪播圖前後端資料互通

settings.js

export default {
    base_url: "http://127.0.0.1:8000/api/vi/"
}

banner.vue

<template>
    <div class="banner">
        <el-carousel :interval="5000" arrow="always" height="400px">
            <el-carousel-item v-for="item in banner_list">
                <img :src="item.image" alt="">
            </el-carousel-item>
        </el-carousel>
    </div>
</template>

<script>

    export default {
        name: "Banner",
        data(){
            return {
                banner_list:[]
            }
        },
        created() {
            this.$axios.get(this.$settings.base_url+'home/banner/').then(res=>{
                if(res.data.status==100){
                    this.banner_list=res.data.result
                    console.log(this.banner_list)
                }
            })
        }
    }
</script>

<style scoped>


    el-carousel-item {
        height: 400px;
        min-width: 1200px;
    }

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

後端自定義配置

在setting資料夾下新建 user_settings.py,我們可以把使用者自己的配置放在這個配置檔案中

BANNER_COUNT=3

可以繼續在主配置檔案匯入繼續使用

# 在dev.py中匯入
# 匯入使用者自定義的配置
from .user_settings import *

相關文章