首页
对于首页要展示的数据和功能,我们先创建一个单独的子应用来完成。
cd renranapi/apps/
python ../../manage.py startapp home
注册子应用,settings/dev.py,代码:
INSTALLED_APPS = [
'home',
]
轮播图功能实现
安装依赖模块和配置
图片处理模块
前面项目搭建时已经安装了,如果没有安装则需要安装
pip install pillow
上传文件相关配置
settings/dev.py
# 访问静态文件的url地址前缀
STATIC_URL = '/static/'
# 设置django的静态文件目录
STATICFILES_DIRS = [
os.path.join(BASE_DIR,"static")
]
# 项目中存储上传文件的根目录[暂时配置],注意,uploads目录需要手动创建否则上传文件时报错
MEDIA_ROOT=os.path.join(BASE_DIR,"uploads")
# 访问上传文件的url地址前缀
MEDIA_URL ="/media/"
在xadmin中输出上传文件的Url地址
总路由urls.py新增代码:
from django.urls import re_path
from django.conf import settings
from django.views.static import serve
urlpatterns = [
...
re_path(r'media/(?P<path>.*)', serve, {"document_root": settings.MEDIA_ROOT}),
]
创建轮播图的模型
home/models.py
from django.db import models
# Create your models here.
class Banner(models.Model):
"""
轮播图
"""
# upload_to 存储子目录,真实存放地址会使用配置中的MADIE_ROOT+upload_to
image = models.ImageField(upload_to='banner', verbose_name='轮播图', null=True,blank=True)
name = models.CharField(max_length=150, verbose_name='轮播图名称')
note = models.CharField(null=True, blank=True, max_length=150, verbose_name='备注信息')
link = models.CharField(null=True, blank=True, max_length=150, verbose_name='轮播图广告地址')
start_time = models.DateTimeField(verbose_name="上架时间",default=None, null=True, blank=True)
end_time = models.DateTimeField(verbose_name="下架时间",default=None, null=True, blank=True)
orders = models.IntegerField(default=0, verbose_name='显示顺序')
is_http = models.BooleanField(verbose_name="是否站外地址", default=False, help_text="站内地址格式:/users/<br>站外地址格式:http://www.baidu.com")
is_show=models.BooleanField(default=False, verbose_name="是否上架")
is_delete=models.BooleanField(default=False, verbose_name="逻辑删除")
class Meta:
db_table = 'rr_banner'
verbose_name = '轮播图'
verbose_name_plural = verbose_name
def __str__(self):
return self.name
数据迁移
python manage.py makemigrations
python manage.py migrate
序列化器
home/serializers.py
from rest_framework import serializers
from .models import Banner
class BannerModelSerializer(serializers.ModelSerializer):
"""轮播图序列化器"""
class Meta:
model = Banner
fields = ["image","link","is_http"]
视图代码
views.py
from django.shortcuts import render
# Create your views here.
from rest_framework.generics import ListAPIView
from .models import Banner
from datetime import datetime
from .serializers import BannerModelSerializer
from renranapi.settings import constants
class BannerListAPIView(ListAPIView):
queryset = Banner.objects.filter(
is_show=True,
is_delete=False,
start_time__lte=datetime.now(),
end_time__gte=datetime.now()
).order_by("orders","-id")[:constants.HOME_BANNER_LENGTH]
serializer_class = BannerModelSerializer
settings/constants.py代码:
# 首页轮播图显示个数
HOME_BANNER_LENGTH = 8
路由代码
home/urls.py
from django.urls import path
from . import views
urlpatterns = [
path("banner/", views.BannerListAPIView.as_view()),
]
把home的路由urls.py注册到总路由
from django.contrib import admin
from django.urls import path,include,re_path
import xadmin
xadmin.autodiscover()
# version模块自动注册需要版本控制的 Model
from xadmin.plugins import xversion
xversion.register_models()
# 上文文件资源
from django.conf import settings
from django.views.static import serve
urlpatterns = [
re_path(r'media/(?P<path>.*)', serve, {"document_root": settings.MEDIA_ROOT}),
path(r'xadmin/', xadmin.site.urls),
# path('admin/', admin.site.urls),
path('stu/', include("students.urls")),
path('users/', include("users.urls")),
path('', include("home.urls")),
]
访问http://api.renran.cn:8000/banner/,效果:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-7AWnhPwq-1595161631872)(E:/python八期/北京python27期荏苒项目/day119/assets/1557457803586.png)]
在配置文件中注册如下应用
# 修改使用中文界面
LANGUAGE_CODE = 'zh-Hans'
# 修改时区
TIME_ZONE = 'Asia/Shanghai'
# 关闭时区转换
USE_TZ = False
注册轮播图模型到xadmin中
home/adminx.py,代码:
import xadmin
from .models import Banner
class BannerModelAdmin(object):
list_display = ["id","name","link","is_show","start_time","end_time"]
list_editable = ["is_show","start_time","end_time"]
xadmin.site.register(Banner,BannerModelAdmin)
修改后端xadmin中子应用名称
home/apps.py
class HomeConfig(AppConfig):
name = 'home'
verbose_name = '我的首页'
__init__.py
default_app_config = "home.apps.HomeConfig"
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-3Zque1kQ-1595161631874)(E:/python八期/北京python27期荏苒项目/day119/assets/1557459568731.png)]
给轮播图添加测试数据
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-RfLzGyr9-1595161631876)(E:/python八期/北京python27期荏苒项目/day119/assets/1557459669649.png)]
添加几条测试数据效果:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-kTzTKhDm-1595161631880)(E:/python八期/北京python27期荏苒项目/day119/assets/1557459949073.png)]
经过上面的操作,我们就完成了轮播图的API接口,接下来,可以考虑提交一个代码版本.
但是,我们前面创建了一个本地开发分支,所以我们如果直接提交代码,默认是在dev分支提交的.
所以就不能直接使用git push
,而是采用以下命令提交
git add .
git commit -m "服务端实现轮播图的API接口"
# 注意 dev就是dev:dev的简写 表示从本地的dev中把代码推送到线上分支dev,如果线上没有dev分支,则自动创建dev分支
客户端代码获取数据
Banner.vue代码:
<template>
<div id="home">
<Header></Header>
<div class="container">
<div class="row">
<div class="main">
<!-- Banner -->
<div class="banner">
<el-carousel height="272px" indicator-position="none" :interval="2000">
<el-carousel-item v-for="banner,key in banner_list" :key="key">
<a :href="banner.link" v-if="banner.is_http" target="_blank"><img :src="banner.image"></a>
<router-link :to="banner.link" v-else><img :src="banner.image"></router-link>
</el-carousel-item>
</el-carousel>
</div>
<div id="list-container">
<!-- 文章列表模块 -->
<ul class="note-list">
<li class="">
<div class="content">
<a class="title" target="_blank" href="">常做此运动,让你性福加倍</a>
<p class="abstract">运动,是人类在发展过程中有意识地对自己身体素质的培养的各种活动 运动的方式多种多样 不仅仅是我们常知的跑步,球类,游泳等 今天就为大家介绍一种男...</p>
<div class="meta">
<span class="jsd-meta">
<img src="/static/image/paid1.svg" alt=""> 4.8
</span>
<a class="nickname" target="_blank" href="">上班族也健身</a>
<a target="_blank" href="">
<img src="/static/image/comment.svg" alt=""> 4
</a>
<span><img src="/static/image/like.svg" alt=""> 31</span>
</div>
</div>
</li>
<li class="have-img">
<a class="wrap-img" href="" target="_blank">
<img class="img-blur-done" src="/static/image/10907624-107943365323e5b9.jpeg" />
</a>
<div class="content">
<a class="title" target="_blank" href="">“不耻下问”,正在毁掉你的人生</a>
<p class="abstract">
在过去,遇到不懂的问题,你不耻下问,找个人问问就行;在现在,如果你还这么干,多半会被认为是“搜商低”。 昨天,35岁的表姐把我拉黑了。 表姐是医...
</p>
<div class="meta">
<span class="jsd-meta">
<img src="/static/image/paid1.svg" alt=""> 6.7
</span>
<a class="nickname" target="_blank" href="">_飞鱼</a>
<a target="_blank" href="">
<img src="/static/image/comment.svg" alt=""> 33
</a>
<span><img src="/static/image/like.svg" alt=""> 113</span>
<span><img src="/static/image/shang.svg" alt=""> 2</span>
</div>
</div>
</li>
</ul>
<!-- 文章列表模块 -->
</div>
<a href="" class="load-more">阅读更多</a></div>
<div class="aside">
<!-- 推荐作者 -->
<div class="recommended-author-wrap">
<!---->
<div class="recommended-authors">
<div class="title">
<span>推荐作者</span>
<a class="page-change"><img class="icon-change" src="/static/image/exchange-rate.svg" alt="">换一批</a>
</div>
<ul class="list">
<li>
<a href="" target="_blank" class="avatar">
<img src="/static/image/avatar.webp" />
</a>
<a class="follow" state="0"><img src="/static/image/follow.svg" alt="" />关注</a>
<a href="" target="_blank" class="name">董克平日记</a>
<p>写了807.1k字 · 2.5k喜欢</p>
</li>
<li>
<a href="" target="_blank" class="avatar">
<img src="/static/image/avatar.webp" />
</a>
<a class="follow" state="0"><img src="/static/image/follow.svg" alt="" />关注</a>
<a href="" target="_blank" class="name">董克平日记</a>
<p>写了807.1k字 · 2.5k喜欢</p>
</li>
</ul>
<a href="" target="_blank" class="find-more">查看全部 ></a>
<!---->
</div>
</div>
</div>
</div>
</div>
<Footer></Footer>
</div>
</template>
<script>
import Header from "./common/Header";
import Footer from "./common/Footer";
export default {
name:"Home",
data(){
return {
banner_list:[],
}
},
components:{
Header,
Footer,
},
created(){
this.get_banner();
},
methods:{
get_banner(){
this.$axios.get(`${this.$settings.Host}/banner/`).then(response=>{
this.banner_list = response.data;
}).catch(error=>{
this.$message.error("网络异常!获取轮播图失败!");
})
}
}
}
</script>
<style>
.banner img{
max-height: 100%;
max-width: 100%;
}
</style>
导航功能实现
调整首页头部子组件的页面,Header.vue,效果:
<template>
<div class="header">
<nav class="navbar">
<div class="width-limit">
<!-- 左上方 Logo -->
<a class="logo" href="/"><img src="/static/image/nav-logo.png" /></a>
<!-- 右上角 -->
<!-- 未登录显示登录/注册/写文章 -->
<a class="btn write-btn" target="_blank" href="/writer"><img class="icon-write" src="/static/image/write.svg">写文章</a>
<router-link class="btn sign-up" id="sign_up" to="/user/register">注册</router-link>
<router-link class="btn log-in" id="sign_in" to="/user/login">登录</router-link>
<div class="container">
<div class="collapse navbar-collapse" id="menu">
<ul class="nav navbar-nav">
<li class="tab active">
<a href="/">
<i class="iconfont ic-navigation-discover menu-icon"></i>
<span class="menu-text">首页</span>
</a>
</li>
<li class="tab">
<a href="/">
<i class="iconfont ic-navigation-follow menu-icon"></i>
<span class="menu-text">关注</span>
</a>
<ul class="dropdown-menu">
<li><a href=""><i class="iconfont ic-comments"></i> <span>评论</span></a></li>
<li><a href=""><i class="iconfont ic-chats"></i> <span>简信</span></a></li>
<li><a href=""><i class="iconfont ic-requests"></i> <span>投稿请求</span></a></li>
<li><a href=""><i class="iconfont ic-likes"></i> <span>喜欢和赞</span></a></li>
<li><a href=""><i class="iconfont ic-follows"></i> <span>关注</span></a></li>
<li><a href=""><i class="iconfont ic-money"></i> <span>赞赏和付费</span></a></li>
<li><a href=""><i class="iconfont ic-others"></i> <span>其它提醒</span></a></li>
</ul>
</li>
<li class="tab">
<a href="/">
<i class="iconfont ic-navigation-notification menu-icon"></i>
<span class="menu-text">消息</span>
</a>
</li>
<li class="search">
<form target="_blank" action="/search" accept-charset="UTF-8" method="get">
<input type="text" name="q" id="q" value="" autocomplete="off" placeholder="搜索" class="search-input">
<a class="search-btn" href="javascript:void(0)"></a>
</form>
</li>
</ul>
</div>
</div>
<!-- 如果用户登录,显示下拉菜单 -->
</div>
</nav>
</div>
</template>
<script>
export default {
name: "Header"
}
</script>
<style scoped>
.header{
height: 56px;
}
.container {
width: 960px;
margin-right: auto;
margin-left: auto;
padding-left: 15px;
padding-right: 15px;
}
.container:after, .container:before {
content: " ";
display: table;
}
.container:after {
clear: both;
}
.navbar {
background-color: #fff;
border-color: #f0f0f0;
top: 0;
border-width: 0 0 1px;
border-radius: 0;
}
.navbar-nav {
float: left;
margin: 0;
}
.navbar:after, .navbar:before {
content: " ";
display: table;
box-sizing: border-box;
}
.nav:after, .nav:before {
content: " ";
display: table;
}
nav .width-limit {
min-width: 768px;
max-width: 1440px;
margin: 0 auto;
}
nav .logo {
float: left;
height: 56px;
padding: 0;
}
nav .logo img {
height: 100%;
vertical-align: middle;
border: 0;
}
.btn {
display: inline-block;
margin-bottom: 0;
font-weight: 400;
text-align: center;
vertical-align: middle;
touch-action: manipulation;
cursor: pointer;
background-image: none;
border: 1px solid transparent;
white-space: nowrap;
padding: 6px 12px;
font-size: 14px;
line-height: 1.42857;
border-radius: 4px;
}
nav .write-btn {
float: right;
width: 100px;
height: 24px;
line-height: 24px;
margin: 8px 12px 0;
border-radius: 20px;
font-size: 15px;
color: #fff;
background-color: #ea6f5a;
text-decoration: none;
}
nav .log-in, nav .log-in:hover {
color: #969696;
}
nav .log-in {
float: right;
margin: 11px 6px 0 10px;
font-size: 15px;
}
nav .sign-up {
float: right;
width: 80px;
height: 24px;
line-height: 24px;
margin: 9px 5px 0 15px;
border: 1px solid rgba(236,97,73,.7);
border-radius: 20px;
font-size: 15px;
color: #ea6f5a;
background-color: transparent;
}
nav .icon-write {
margin-right: 3px;
width: 19px;
height: 19px;
vertical-align: middle;
}
nav .menu-text{
font-size: 17px;
}
nav .active a{
color: #ea6f5a;
}
nav .menu-icon {
width: 20px;
height: 20px;
vertical-align: baseline;
margin-right: 3px;
}
.tab:hover .dropdown-menu{
display: block;
}
.dropdown-menu{position:absolute;top:100%;left:0;z-index:1000;display:none;
float:left;min-width:120px;padding:5px 0;margin:2px 0 0;list-style:none;
font-size:14px;text-align:left;background-color:#fff;border:1px solid #ccc;
border:1px solid rgba(0,0,0,.15);border-radius:4px;
box-shadow:0 6px 12px rgba(0,0,0,.175);
background-clip:padding-box}
.dropdown-menu.pull-right{right:0;left:auto}
.dropdown-menu .divider{
height:1px;margin:9px 0;overflow:hidden;background-color:#e5e5e5}
.dropdown-menu>li>a{display:block;padding:3px 20px;clear:both;font-weight:400;
line-height:1.42857;color:#333;white-space:nowrap}
.dropdown-menu>li>a:focus,.dropdown-menu>li>a:hover{
text-decoration:none;color:#262626;background-color:#f5f5f5}
.dropdown-menu>.active>a,.dropdown-menu>.active>a:focus,.dropdown-menu>.active>a:hover{
color:#fff;text-decoration:none;outline:0;background-color:#337ab7}
.dropdown-menu>.disabled>a,.dropdown-menu>.disabled>a:focus,.dropdown-menu>.disabled>a:hover{
color:#777
}
.dropdown-menu>.disabled>a:focus,.dropdown-menu>.disabled>a:hover{
text-decoration:none;background-color:transparent;background-image:none;filter:progid:DXImageTransform.Microsoft.gradient(enabled = false);cursor:not-allowed}
.open>.dropdown-menu{display:block}.open>a{outline:0}.dropdown-menu-right{left:auto;right:0}.dropdown-menu-left{left:0;right:auto}.dropdown-header{display:block;padding:3px 20px;font-size:12px;line-height:1.42857;color:#777;white-space:nowrap}.dropdown-backdrop{position:fixed;left:0;right:0;bottom:0;top:0;z-index:990}.pull-right>.dropdown-menu{right:0;left:auto}.dropup .caret,.navbar-fixed-bottom .dropdown .caret{border-top:0;border-bottom:4px dashed;border-bottom:4px solid\9;content:""}.dropup .dropdown-menu,.navbar-fixed-bottom .dropdown .dropdown-menu{top:auto;bottom:100%;margin-bottom:2px}
.navbar-right .dropdown-menu-left{left:0;right:auto}
.dropdown-menu{
width:150px;margin-top:-1px;border-radius:0 0 4px 4px
}
.dropdown-menu li{margin:0}
.dropdown-menu a{height:auto;padding:10px 20px;line-height:30px}
.dropdown-menu a:hover{background-color:#f5f5f5}
.dropdown-menu i{margin-right:15px;font-size:22px;color:#ea6f5a;
vertical-align:middle
}
.dropdown-menu span{vertical-align:middle}
.dropdown-menu .badge{position:absolute;right:15px;margin-top:7px}
nav .nav .tab a {
height: 56px;
line-height: 26px;
padding: 15px;
background: none;
}
nav .navbar-nav li {
margin-right: 10px;
float: left;
position: relative;
display: block;
box-sizing: border-box;
height: 56px;
line-height: 56px;
}
.navbar-nav {
float: left;
margin: 0;
}
nav form {
position: relative;
top: 9px;
margin: 0 0 20px;
box-sizing: border-box;
line-height: 20px;
}
nav form .search-input {
padding: 0 40px 0 20px;
height: 38px;
font-size: 14px;
border: 1px solid #eee;
border-radius: 40px;
background: #eee;
transition: width .5s;
width: 240px;
outline: none;
}
nav form .search-input:focus {
width: 320px;
outline: none;
}
.navbar-default .navbar-collapse, .navbar-default .navbar-form {
border-color: #e7e7e7;
padding-left: 0;
padding-right: 0;
box-sizing: border-box;
width: auto;
border-top: 0;
box-shadow: none;
}
.navbar {
background-color: #fff;
top: 0;
border-radius: 0;
position: fixed;
right: 0;
left: 0;
z-index: 1030;
min-height: 50px;
margin-bottom: 20px;
border-bottom: 1px solid #f0f0f0;
}
nav {
height: 56px;
}
.navbar:after, .navbar:before {
content: " ";
display: table;
}
nav form .search-btn {
position: absolute;
display: block;
top: 0;
right: 10px;
width: 30px;
height: 30px;
padding: 0;
margin: 5px -1px 0 0;
background: transparent url("../../../static/image/search-focus.svg") no-repeat 6px 6px;
background-size: 20px;
}
nav form .search-input:focus~a{
border-radius: 50%;
background-color: #696969;
background-image: url("../../../static/image/search-blur.svg");
}
nav .sign-up:hover {
color: #ec6149;
border-color: #ec6149;
background-color: rgba(236,97,73,.05);
}
nav .write-btn:focus, nav .write-btn:hover {
color: #fff;
background-color: #ec6149;
}
</style>
创建模型
id | name | pid |
---|---|---|
1 | 消息 | 0 |
2 | 广场 | 0 |
3 | 评论 | 1 |
4 | 留言 | 1 |
引入一个公共模型【抽象模型,不会在数据迁移的时候为它创建表】
from django.db import models
from renranapi.utils.models import BaseModel
# Create your models here.
class Banner(BaseModel):
"""
轮播图
"""
# upload_to 存储子目录,真实存放地址会使用配置中的MADIE_ROOT+upload_to
image = models.ImageField(upload_to='banner', verbose_name='轮播图', null=True,blank=True)
note = models.CharField(null=True, blank=True, max_length=150, verbose_name='备注信息')
link = models.CharField(null=True, blank=True, max_length=150, verbose_name='轮播图广告地址', help_text="站内地址格式:/users/<br>站外地址格式:http://www.baidu.com")
start_time = models.DateTimeField(verbose_name="上架时间",default=None, null=True, blank=True)
end_time = models.DateTimeField(verbose_name="下架时间",default=None, null=True, blank=True)
is_http = models.BooleanField(verbose_name="是否站外地址", default=False)
class Meta:
db_table = 'rr_banner'
verbose_name = '轮播图'
verbose_name_plural = verbose_name
class Nav(BaseModel):
"""导航菜单"""
POSITION = (
(1, "头部导航"),
(2, "脚部导航"),
)
pid = models.ForeignKey("Nav", related_name="son", null=True, blank=True, on_delete=models.DO_NOTHING, verbose_name="父亲导航", )
link = models.CharField(max_length=500, verbose_name='导航地址', help_text="如果是站外链接,必须加上协议, 格式如: http://www.renran.cn")
is_http = models.BooleanField(verbose_name="是否站外地址", default=False)
option = models.SmallIntegerField(choices=POSITION, default=1, verbose_name="导航位置")
class Meta:
db_table = 'rr_nav'
verbose_name = '导航菜单'
@property
def son_list(self):
"""子导航列表"""
result = self.son.filter(is_show=True,is_delete=False).order_by("orders","-id")[:8]
data = []
for nav in result:
data.append({
"name": nav.name,
"link": nav.link,
"is_http": nav.is_http,
})
return data
公共模型,保存项目的公共代码库目录下luffyapi/utils.py文件中。
from django.db import models
class BaseModel(models.Model):
"""公共模型"""
name = models.CharField(null=True, blank=True, max_length=150, verbose_name='名称')
orders = models.IntegerField(default=0, verbose_name='显示顺序')
is_show = models.BooleanField(default=False, verbose_name="是否上架")
is_delete = models.BooleanField(default=False, verbose_name="逻辑删除")
created_time = models.DateTimeField(null=True,blank=True, auto_now_add=True, verbose_name="添加时间")
updated_time = models.DateTimeField(null=True,blank=True, auto_now=True, verbose_name="更新时间")
class Meta:
# 设置当前模型在数据迁移的时候不要为它创建表
abstract = True
def __str__(self):
return self.name
数据迁移
python manage.py makemigrations
python manage.py migrate
注册导航模型到xadmin中
在home子应用adminx.py,添加如下代码
# 导航
from .models import Nav
class NavModelAdmin(object):
list_display=["name","link","is_http"]
xadmin.site.register(Nav, NavModelAdmin)
添加测试数据
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-JJI1isp0-1595161631881)(E:/Python全栈8-26/荏苒/day020/assets/1557462133673.png)]
序列化器代码
home/serializers.py,代码:
from .models import Nav
class NavModelSerializer(serializers.ModelSerializer):
"""导航菜单序列化器"""
class Meta:
model = Nav
fields = ["name","link","is_http","son_list"]
视图代码
home/views.py
from .models import Nav
from .serializers import NavModelSerializer
class NavHeaderListAPIView(ListAPIView):
queryset = Nav.objects.filter(is_show=True, is_delete=False, option=1,pid=None).order_by("orders","-id")[:constants.HEADER_NAV_LENGTH]
serializer_class = NavModelSerializer
class NavFooterListAPIView(ListAPIView):
queryset = Nav.objects.filter(is_show=True, is_delete=False, option=2,pid=None).order_by("orders","-id")[:constants.FOOTER_NAV_LENGTH]
serializer_class = NavModelSerializer
settings/constants.py,代码:
# 头部顶级导航数量
HEADER_NAV_LENGTH = 8
# 脚部顶级导航数量
FOOTER_NAV_LENGTH = 8
路由代码
urls.py
from django.urls import path
from . import views
urlpatterns = [
path("banner/", views.BannerListAPIView.as_view()),
path("nav/header/", views.NavHeaderListAPIView.as_view()),
path("nav/footer/", views.NavFooterListAPIView.as_view()),
]
客户端获取导航数据
Header.vue代码:
<template>
<div class="header">
<nav class="navbar">
<div class="width-limit">
<!-- 左上方 Logo -->
<a class="logo" href="/"><img src="/static/image/nav-logo.png" /></a>
<!-- 右上角 -->
<!-- 未登录显示登录/注册/写文章 -->
<a class="btn write-btn" target="_blank" href="/writer"><img class="icon-write" src="/static/image/write.svg">写文章</a>
<router-link class="btn sign-up" id="sign_up" to="/user/register">注册</router-link>
<router-link class="btn log-in" id="sign_in" to="/user/login">登录</router-link>
<div class="container">
<div class="collapse navbar-collapse" id="menu">
<ul class="nav navbar-nav">
<li class="tab active">
<a href="/">
<i class="iconfont ic-navigation-discover menu-icon"></i>
<span class="menu-text">首页</span>
</a>
</li>
<li class="tab" v-for="nav in nav_list">
<a :href="nav.link" v-if="nav.is_http">
<i class="iconfont ic-navigation-follow menu-icon"></i>
<span class="menu-text">{{nav.name}}</span>
</a>
<router-link :to="nav.link" v-else>
<i class="iconfont ic-navigation-follow menu-icon"></i>
<span class="menu-text">{{nav.name}}</span>
</router-link>
<ul class="dropdown-menu" v-if="nav.son_list.length>0">
<li v-for="son in nav.son_list">
<a :href="son.link" v-if="son.is_http" target="_blank"><i class="iconfont ic-comments"></i> <span>{{son.name}}</span></a>
<router-link :to="son.link" v-else><i class="iconfont ic-comments"></i> <span>{{son.name}}</span></router-link>
</li>
</ul>
</li>
<li class="search">
<form target="_blank" action="/search" accept-charset="UTF-8" method="get">
<input type="text" name="q" id="q" value="" autocomplete="off" placeholder="搜索" class="search-input">
<a class="search-btn" href="javascript:void(0)"></a>
</form>
</li>
</ul>
</div>
</div>
<!-- 如果用户登录,显示下拉菜单 -->
</div>
</nav>
</div>
</template>
<script>
export default {
name: "Header",
data(){
return {
nav_list:[
{
son_list:[]
}
],
}
},
created(){
this.get_nav();
},
methods:{
get_nav(){
this.$axios.get(`${this.$settings.Host}/nav/header/`).then(response=>{
this.nav_list = response.data;
}).catch(error=>{
this.$message.error("网络异常,无法获取头部导航信息!");
})
}
}
}
</script>
Footer.vue
<template>
<footer class="container">
<div class="row">
<div class="main">
<span :key="key" v-for="nav,key in nav_list">
<a :href="nav.link" target="_blank" v-if="nav.is_http">{{nav.name}}</a>
<router-link :to="nav.link" v-else>{{nav.name}}</router-link>
<em> · </em>
</span>
<div class="icp">©2016-2019 广州荏苒信息科技有限公司 / 荏苒 / 粤ICP备16018329号-5 /</div>
</div>
</div>
</footer>
</template>
<script>
export default {
name: "Footer",
data(){
return {
nav_list:[],
}
},
created(){
this.get_nav();
},
methods:{
get_nav(){
this.$axios.get(`${this.$settings.Host}/nav/footer/`).then(response=>{
this.nav_list = response.data;
}).catch(error=>{
this.$message.error("无法获取脚步导航信息");
})
}
}
}
</script>
ipt>
Footer.vue
```vue
<template>
<footer class="container">
<div class="row">
<div class="main">
<span :key="key" v-for="nav,key in nav_list">
<a :href="nav.link" target="_blank" v-if="nav.is_http">{{nav.name}}</a>
<router-link :to="nav.link" v-else>{{nav.name}}</router-link>
<em> · </em>
</span>
<div class="icp">©2016-2019 广州荏苒信息科技有限公司 / 荏苒 / 粤ICP备16018329号-5 /</div>
</div>
</div>
</footer>
</template>
<script>
export default {
name: "Footer",
data(){
return {
nav_list:[],
}
},
created(){
this.get_nav();
},
methods:{
get_nav(){
this.$axios.get(`${this.$settings.Host}/nav/footer/`).then(response=>{
this.nav_list = response.data;
}).catch(error=>{
this.$message.error("无法获取脚步导航信息");
})
}
}
}
</script>