1. 程式人生 > 其它 >前臺主頁搭建、後臺主頁輪播圖介面設計、跨域問題詳解、前後端互通、後端自定義配置、git軟體的初步介紹

前臺主頁搭建、後臺主頁輪播圖介面設計、跨域問題詳解、前後端互通、後端自定義配置、git軟體的初步介紹

今日內容概要

  • 前臺主頁
  • 後臺主頁輪播圖介面
  • 跨域問題詳解
  • 前後端打通
  • 後端自定義配置
  • git介紹和安裝

內容詳細

1、前臺主頁

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>

新建:\src\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>

新建:\src\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>

新建:\src\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>

2、後臺主頁輪播圖介面(luffy_api)

# 輪播圖介面

# 導航條寫死的---》如果想動態變化---》也要寫成介面

# 首頁推薦的8個課程---》介面---》按銷量排序取前8個課程


### 在pycharm開啟後臺專案 luffy_api:
# cmd視窗 註冊app: home
	cd到apps目錄下
	python ../../manage.py startapp home
	到配置檔案註冊:
		INSTALLED_APPS = [
			'home',
		]

2.1 表設計

新建 utils/model.py:

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  # 表示它是虛擬的,不在資料庫中生成表,它只用來做繼承

apps/home/models.py :

from django.db import models
from utils.model import BaseModel


# 輪播圖介面---》輪播圖表
class Banner(BaseModel):
    # 順序,插入時間, 是否顯示,是否刪除。。。----》後期寫課程的表也會用到這些欄位--->仿AbstractUser,寫一個基表,以後繼承這個表
    # 繼承過來,只需要寫自有欄位即可:title,image,info,link
    title = models.CharField(max_length=16, unique=True, verbose_name='名稱')
    image = models.ImageField(upload_to='banner', verbose_name='圖片')
    # 寫介面---》app---》前端配合一個介面---》實現開啟app,就有廣告圖片---》點選廣告圖片調整到app內部或者使用瀏覽器開啟
    # 一開啟app,先開啟的頁面是什麼,寫app的人寫的---》整一張大圖充滿全屏即可--》配合一個介面,返回一張大圖
    # app開啟廣告介面---》{code:100,msg:成功,img:{img:127.0.0.1/img/1.png,link:'www.baidu.com',type:2}}
    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
# 表設計完之後 遷移資料 並建立超級使用者
	python manage.py makemigrations  ---》如果沒有變化,是app沒註冊
	python manage.py migrate
	python manage.py createsuperuser  --->建立個使用者

2.2 引入simpleui

# 下載
	pip install django-simpleui
    
# 註冊app(寫在最頂上)
	INSTALLED_APPS = [
		'simpleui',
		...
	]
    
# 在admin.py中寫:
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 = '自定義按鈕'
    
    
    
# 進入後臺admin管理頁面:
	增加四條輪播圖資料

2.3 輪播圖介面

# 返回資料格式
	{code:100, msg:成功,result:[{img:地址,link:跳轉地址,orders:順序,title:名字},{img:地址,link:跳轉地址,orders:順序,title:名字}]}

檢視類 home/views.py中寫:

from django.shortcuts import render
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):
    # class BannerView(GenericViewSet,ListModelMixin):
    # 獲取所有介面-list,自動生成路由
    # qs物件可以像列表一樣,切片
    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)

新建序列化類 home/serializer.py:

from rest_framework import serializers
from .models import Banner


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

新建分路由 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)),
]

總路由 urls.py:

from django.contrib import admin
from django.urls import path, include


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

3、跨域問題詳解(回到前端書寫 luffycity:)

# 在前端專案中寫:
	用 pycharm開啟前端專案 luffycity
    
# 現在寫好了後端介面,前端載入資料---》載入不過來,報錯,--》報跨域的錯誤

#  同源策略 ---》瀏覽器的規定
	請求的url地址,必須與瀏覽器上的url地址處於同域上,也就是域名,埠,協議相同,否則,載入回來的資料就會禁止
    
	前端:http://127.0.0.1:8080
	後端:http://127.0.0.1:8000
	這倆屬於不同源,協議,地址一樣,但是埠不一樣,所以請求成功,但是到了瀏覽器被禁止掉了,因為瀏覽器的同源策略
	前後端分離,就會遇到這個問題,現在解決這個問題
    
    
    
# jsonp 解決:出現了跨域問題---》有的東西不出跨域問題---》img,script,link--》回撥
	https://www.zhihu.com/question/19966531
	但是目前已經不用了 所以不再介紹
    
    
    
# 通過CORS(跨域資源共享)解決:
	CORS需要瀏覽器和伺服器同時支援。目前,所有瀏覽器都支援該功能

	實現CORS通訊的關鍵是伺服器。只要伺服器實現了CORS介面,就可以跨源通訊
	只需要在響應頭中指定,允許跨域即可
    
# 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請求,如果允許跨域,再發真正的請求
    
    
# 解決跨域-->分成簡單和非簡單請求處理
	簡單請求再響應頭中加入:"Access-Control-Allow-Origin":"*"
	非簡單,咱們要加判斷,如果是OPTIONS請求,在響應頭中加入允許
    
# 自行解決跨域---》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
  

    
# 經常遇到的東西,一定會有第三方解決方案---》我們使用第三方解決
	第一步:下載(開啟後臺專案操作 luffy_api):
		pip install django-cors-headers
	
	第二步:app中註冊 dev.py:
		INSTALLED_APPS = (
			...
			'corsheaders',
			...
		)
        
	第三步:中介軟體註冊
		MIDDLEWARE = [  # Or MIDDLEWARE_CLASSES on Django < 1.10
			...
			'corsheaders.middleware.CorsMiddleware',
		]
        
	第四步:配置檔案配置
### 跨域問題處理
# 允許簡單請求,所有地址 相當於CORS_ORIGIN_ALLOW_ALL="*"
CORS_ALLOW_ALL_ORIGINS = True
# 允許的請求方式
CORS_ALLOW_METHODS = (
    'DELETE',
    'GET',
    'OPTIONS',
    'POST',
    'PUT',
)
# 允許的請求頭
CORS_ALLOW_HEADERS = (
    'accept-encoding',
    'authorization',  # jwt
    'content-type',  # json
    'origin',
    'user-agent',
    'Pragma',
)

修改 src/assets/js/settings.js:

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

修改 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>

4、前後端打通

修改後臺總路由:

from django.contrib import admin
from django.urls import path, include, re_path
from django.views.static import serve
from django.conf import settings

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

    # 開啟media的訪問
    path('media/<path:path>', serve, {'document_root': settings.MEDIA_ROOT})
]

修改banner.py:

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

5、後端自定義配置

# 在setting資料夾下新建 user_settings.py:
	# 使用者自己的配置,單獨放到一個py檔案中
	BANNER_COUNT = 3


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

6、git介紹和安裝

# 公司裡是協同開發,多人開發同一個專案
# 程式碼已經寫到v3版本了,忽然想看一下v1版本什麼樣
# git:
	程式碼版本管理工具/軟體,同類型的是 svn--但是用得少
	幫助開發者合併開發的程式碼
	如果出現衝突程式碼的合併,會提示後提交合並程式碼的開發者,讓其解決衝突
	做程式碼版本管理,可以快速回到某個版本上
  
# win:下載
	https://git-scm.com/download
  
# mac下載:
	https://github.com/timcharper/git_osx_installer/releases/download/2.2.1/git-2.2.1-intel-universal-mavericks.dmg

# 一路下一步,其他都不用選
	安裝完成後 滑鼠在桌面右鍵 會顯示兩個功能出來 代表安裝成功