从零到一搭建一个属于自己的博客系统(弍)

     阅读:63

前言:在上篇博客从零到一搭建一个属于自己的博客系统(弌)中我们讲到了登录界面以及功能的实现,接下来我们来看看首页制作以及文章的发布


  1. 环境:vue+webpack
  2. 请求的发送:axios
  3. 后端接口:Django
  4. 数据库:mysql

项目结构图:
在这里插入图片描述

在这里插入图片描述

(- - -在上篇文章中,我们少了很多的细节,接下来这篇博文中我会来给大家补上的哦- - -)

一.路由守护:


我们深知,必须登录之后才可以进行页面之间的的跳转访问,也就是路由的相互跳转,但是我们上一篇文章中却疏忽了这一点,这次来补上(详情请移步:Vue中进行全局守卫):

 this.$get('/login').then(res => {
          var a = ''
          var b = ''
          console.log(res)
          for (var i = 0; i < res.length; i++) {
            if (this.user === res[i][0] && this.pwd === res[i][1]) {
              a = res[i][0]
              b = res[i][1]
              this.time = this.timestampToTime(Date.now() / 1000)
              sessionStorage.setItem('sid', '已登录') // 设置本地存储信息
              sessionStorage.setItem('user', this.user) // 设置本地存储信息
              sessionStorage.setItem('time', this.time) // 设置本地存储信息
              this.$message({
                message: '恭喜你,登录成功!',
                type: 'success'
              })
              this.$router.push({
                name: 'homepage'
              })
            }

在我们登录成功时候向session中插入我们需要的信息,如下图:
在这里插入图片描述
进行了信息的存储也提示了我们登录成功的消息,并且进行了页面之间的跳转。

接下来我们在main.js中进行以下配置:

// 全局守卫
router.beforeEach((to, from, next) => {
  // 获取登陆状态
  let isLogin = sessionStorage.getItem('sid')
  if (to.name === 'login') { // 如果是登录页,则跳过验证
    next()
    return
  }
  if (!isLogin) { //  判断登陆状态,sessionStorage不存在的情况下
    ElementUI.Message({
      message: '请先登录系统',
      type: 'error'
    })
    next({
      name: 'login'
    }) // 如果未登录,则跳转到登录页
  } else {
    next() // 如果已经登陆,那就可以跳转
  }
})

这样子就只有登录了才能进入我们的系统哦~~~~


二.axios封装:

发送请求肯定不止止是一个,那么我们可以进行axios的封装,有利于我们更好的发送请求(Vue中进行对于axios的封装):


三.Homepage(首页):

既然登录成功了,那么肯定有个目标页,我们一起来看看首页:
在这里插入图片描述
(有可能会有点丑,但是还得大家多多包涵俺的设计水平 _ )

1.需求:

  • 个人的信息以及登录时间;
  • 切换账号和退出登录;
  • 可以进行的操作(发布文章、个人中心、点赞、评论);
  • 博文数据的显示;

2.HTML代码:

明白需求那么开始进行页面的设计:

<template>
  <div class="homepage">
    <el-container>
      <el-header>
        <!-- 头部样式 -->
        <div class="head">
          <div class="head-center">
            <span style="font-weight: 600;font-size:18px;float: left;">欢迎您:{{text}} | 登录时间:{{time}}</span>
            <span class="span_text" @click="exit"> 退出登录 </span>
            <span style="float:right">&nbsp;<em>|</em>&nbsp;</span>
            <span class="span_text" @click="exit">切换账号</span>
            <div style="float:right">
              <el-dropdown>
                <div class='img el-dropdown-link'>
                  <el-avatar src="https://cube.elemecdn.com/0/88/03b0d39583f48206768a7534e55bcpng.png"></el-avatar>
                </div>
                <el-dropdown-menu slot="dropdown">
                  <el-dropdown-item icon="el-icon-edit" @click.native='bumittext()'>发布文章</el-dropdown-item>
                  <el-dropdown-item icon="el-icon-user-solid">个人中心</el-dropdown-item>
                  <el-dropdown-item icon="el-icon-plus">点赞</el-dropdown-item>
                  <el-dropdown-item icon="el-icon-circle-plus">评论</el-dropdown-item>
                </el-dropdown-menu>
              </el-dropdown>
            </div>
          </div>
        </div>
      </el-header>
      <!-- 中心内容 -->
      <el-main>
        <div class="content-text" v-for='(item,index) in data'>
          <!-- 标题 -->
          <div class="content-title">
            <strong> {{item[2]}}</strong>
          </div>
          <!-- 中心内容缩略显示 -->
          <div class="content-center">
            <p>{{item[3]}}</p>
          </div>
          <!-- 点赞,评论 -->
          <div class="content-dzpl">
            <span style="margin-right: 20px;font-size: 14px;color: #999999">点赞:{{item[4]}}</span>
            <span style="margin-right: 20px;font-size: 14px;color: #999999">评论:{{item[5]}}</span>
          </div>
          <!-- 右下角信息 -->
          <div class="content-bottom">
            <span>发布<strong>博客</strong>与 {{item[6]}}</span>
          </div>
        </div>
      </el-main>
      <!-- 最底部样式 -->
      <el-footer>趁年轻,给自己一个机会,加油! <a href="https://beian.miit.gov.cn/">陕ICP备2021001587号-1</a></el-footer>
    </el-container>
  </div>
</template>

3.CSS代码:

单纯的结构层肯定不能凸显一些美,这时候我们需要用css来对页面进行具体的美化:

<style scoped>
/* 整体框架 */
  .homepage {
    width: 100%;
    height: 100%;
  }
/* strong标签,标题 */
  .content-title strong {
    font-size: 28px;
  }

  /* 顶部文字样式 */
  .head-center {
    width: 1200px;
    height: 100%;
    margin: 0 auto;
    text-align: center;
  }

  /* 切换账号以及退出登陆样式 */
  .span_text {
    float: right;
    cursor: pointer;
    font-weight: 600;
    font-size: 15px;
  }

  /* 鼠标划过样式 */
  .span_text:hover {
    color: #315efb;
  }

  /* 头像 */
  .img {
    margin-right: 10px;
    width: 50px;
    height: 50px;
    line-height: 85px;
  }

  /* 中心内容文本框 */
  .content-text {
    width: 1000px;
    height: 200px;
    margin: 0 auto;
    position: relative;
    margin-top: 10px;
    overflow: hidden;
    background-color: #dfdfdf;
    cursor: pointer;
  }

  /* 标题 */
  .content-title {
    position: absolute;
    top: 10px;
    left: 10px;
    width: 30%;
    height: 50px;
    line-height: 50px;
    text-align: left;
  }

  /* 中心内容 */
  .content-center {
    position: absolute;
    top: 60px;
    left: 10px;
    width: 98.2%;
    height: 80px;
    text-align: left;
  }

  /* 点赞,评论 */
  .content-dzpl {
    position: absolute;
    bottom: 10px;
    left: 10px;
    width: 30%;
    height: 30px;
    line-height: 30px
  }

  /* 右下角的信息 */
  .content-bottom {
    position: absolute;
    bottom: 10px;
    right: 20px;
    width: 30%;
    height: 30px;
    line-height: 30px;
  }

  .el-dropdown-link {
    cursor: pointer;
    color: #409EFF;
  }

  .el-icon-arrow-down {
    font-size: 12px;
  }

  .demonstration {
    display: block;
    color: #8492a6;
    font-size: 14px;
    margin-bottom: 20px;
  }

  /* 布局样式 */
  .el-header,
  .el-footer {
    background-color: #B3C0D1;
    color: #333;
    text-align: center;
    line-height: 60px;
  }

  .el-main {
    background-color: #E9EEF3;
    color: #333;
    text-align: center;
    line-height: 50px;
  }

  body>.el-container {
    margin-bottom: 40px;
  }

  .el-container:nth-child(5) .el-aside,
  .el-container:nth-child(6) .el-aside {
    line-height: 260px;
  }

  .el-container:nth-child(7) .el-aside {
    line-height: 320px;
  }

</style>

4.js代码:

export default {
  name: 'homepage',
  data () {
    return {
      text: '',
      time: '',
      data: '' // 存储拿到的数据
    }
  },
  created () {
    var that = this
    // 获取信息
    that.text = sessionStorage.getItem('user')
    // 获取当前时间
    that.time = sessionStorage.getItem('time')
    // 参数,方便识别当前的用户进行不同用户显示自己的数据
    var data = {
      username: sessionStorage.getItem('user')
    }
    // 发送请求
    this.$get('/homepage', data).then(res => {
      for (var i = 0; i < res.length; i++) {
        that.data = res
      }
    })
  },
  components: {},
  mounted () {},
  methods: {
    // 时间转换以及补零操作
    timestampToTime (timestamp) {
      var date = new Date(timestamp * 1000)
      var Y = date.getFullYear() + '-'
      var M = (date.getMonth() + 1).toString().padStart(2, '0') + '-'
      var D = date.getDate().toString().padStart(2, '0') + ' '
      var h = date.getHours().toString().padStart(2, '0') + ':'
      var m = date.getMinutes().toString().padStart(2, '0') + ':'
      var s = date.getSeconds().toString().padStart(2, '0')
      return Y + M + D + h + m + s
    },
    // 点击退出按钮或者切换账号按钮
    exit () {
      sessionStorage.clear()
      this.$router.push({
        name: 'login'
      })
      this.$message({
        message: '当前账号已退出',
        type: 'success'
      })
    },
    // 点击书写文章
    bumittext () {
      this.$router.push({
        name: 'marktext'
      })
    }
  }
}

</script>

5.不同用户不同数据:

因为我们在登录时候采用了:

sessionStorage.setItem('sid', '已登录') // 设置本地存储信息
sessionStorage.setItem('user', this.user) // 设置本地存储信息,登录用户
sessionStorage.setItem('time', this.time) // 设置本地存储信息,登录时间

所以我们的首页就会显示,我们当前登录的用户以及登录的时间:

例如:

  1. xxadmin用户登录:
    在这里插入图片描述
  2. admin用户登录:
    在这里插入图片描述

四.编写文章(marktext):

首页homepage显示的那样,我们鼠标滑到头像时候会有我们可以执行的操作:
在这里插入图片描述
我们主要进行文章编写的讲解,在首页的js代码中我们发现有如下的代码:

// 点击书写文章
    bumittext () {
      this.$router.push({
        name: 'marktext'
      })
    }

那么我们来看一下marktext页面,我们使用的是div进行书写文本内容,并且进行自适应的操作:
在这里插入图片描述

1.HTML代码:

<template>
  <div class="marktext">
    <el-container>
      <!-- 头部 -->
      <el-header>
        <div class="head">
          <div v-on:click='back'>
            <span style="float: left;font-size: 18px"><i class="el-icon-back"></i>文章管理</span>
          </div>
          <el-input placeholder="请输入标题(5-15字)" v-model="title" clearable>
          </el-input>
            <span  @click="dialogVisible1 = true" style="float: right;font-size: 18px"><i class="el-icon-position"></i>发布</span>
        </div>
      </el-header>
       <el-dialog title="提示:" :visible.sync="dialogVisible1" width="20%">
          <span>确认发布?</span>
          <span slot="footer" class="dialog-footer">
            <el-button type="primary" @click="send">确认</el-button>
            <el-button @click="dialogVisible1 = false">取 消</el-button>
          </span>
        </el-dialog>
      <el-dialog title="温馨提示" :visible.sync="dialogVisible" width="20%">
          <span>离开后网站不会保留您的所有内容</span>
          <span slot="footer" class="dialog-footer">
            <el-button type="primary" @click="exit">离开</el-button>
            <el-button @click="dialogVisible = false">取 消</el-button>
          </span>
        </el-dialog>
      <el-main>
        <el-row type="flex" class="row-bg release" justify="center">
          <el-col :span="12">
            <el-card class="box-card">
               <div class="textarea" contenteditable="true"><br /></div>
            </el-card>
          </el-col>
        </el-row>
      </el-main>
    </el-container>
  </div>
</template>

2.CSS代码:

同样我们来进行美化设计:

<style>
  /* 整体布局 */
  .marktext {
    width: 100%;
    height: 100%;
  }

  /* 头部样式 */
  .head {
    width: 80%;
    height: 100%;
    margin: 0 auto;
  }

  .head span:hover {
    cursor: pointer;
  }

  /* 输入框样式 */
  .el-input {
    width: 70%;
  }

  .el-input__inner {
    border-radius: 30px;
    display: inline-block;
  }

  .el-header {
    background-color: #B3C0D1;
    color: #333;
    text-align: center;
    line-height: 60px;
  }

  .el-main {
    background-color: #E9EEF3;
    color: #333;
    text-align: center;
    line-height: 160px;
  }

  body>.el-container {
    margin-bottom: 40px;
  }

  .el-container:nth-child(5) .el-aside,
  .el-container:nth-child(6) .el-aside {
    line-height: 260px;
  }

  .el-container:nth-child(7) .el-aside {
    line-height: 320px;
  }
  .textarea{
    width: 100%;
    min-height: 20px;
    max-height: 300px;
    _height: 120px;
    margin-left: auto;
    margin-right: auto;
    padding: 3px;
    outline: 0;
    border: 1px solid #a0b3d6;
    font-size: 12px;
    line-height: 24px;
    padding: 2px;
    word-wrap: break-word;
    overflow-x: hidden;
    overflow-y: auto;
    border-color: rgba(82, 168, 236, 0.8);
    box-shadow: inset 0 1px 3px rgba(0, 0, 0, 0.1), 0 0 8px rgba(82, 168, 236, 0.6);
    text-align: left;
}
</style>

3.js操作:

(1).返回按钮(文章管理):

我们可以点击文章管理退回我们的homepage首页,当然也会进行退出提示:

 // 返回homepage页面
    exit () {
      this.$router.push({
        name: 'homepage'
      })
      this.title = ''
      this.text = ''
    }
  },

提示的HTML代码:

 <el-dialog title="温馨提示" :visible.sync="dialogVisible" width="20%">
          <span>离开后网站不会保留您的所有内容</span>
          <span slot="footer" class="dialog-footer">
            <el-button type="primary" @click="exit">离开</el-button>
            <el-button @click="dialogVisible = false">取 消</el-button>
          </span>
        </el-dialog>

效果:
在这里插入图片描述

(2).文章发布:

文章发布也就是我们需要进行数据的提交,那么接口请查看(五.Django接口),具体的操作如下:

// 发送数据
    send () {
      // 文本框的内容
      this.text = document.getElementsByClassName('textarea')[0].innerText
      // 当前时间
      var time = this.timestampToTime(Date.now() / 1000)
      // 参数
      var data = {
        username: sessionStorage.getItem('user'),
        title: this.title,
        text: this.text,
        ctime: time
      }
      // 提交数据
      this.$post('/insert/', data, {headers: {'Content-Type': 'application/x-www-form-urlencoded'}}).then(res => {
        this.$message({
          message: '发布成功',
          type: 'success'
        })
        this.$router.push({
          name: 'homepage'
        })
      })
    },

数据提交成功之后返回我们的homepage首页;

(3).整体js代码:

<script>
export default {
  name: 'editor',
  data () {
    return {
      editor: '',
      title: '', // 标题
      dialogVisible: false,
      dialogVisible1: false,
      text: ''
    }
  },
  methods: {
    // 时间转换以及补零操作
    timestampToTime (timestamp) {
      var date = new Date(timestamp * 1000)
      var Y = date.getFullYear() + '-'
      var M = (date.getMonth() + 1).toString().padStart(2, '0') + '-'
      var D = date.getDate().toString().padStart(2, '0') + ' '
      var h = date.getHours().toString().padStart(2, '0') + ':'
      var m = date.getMinutes().toString().padStart(2, '0') + ':'
      var s = date.getSeconds().toString().padStart(2, '0')
      return Y + M + D + h + m + s
    },
    back () {
      var that = this
      that.dialogVisible = true
    },
    // 发送数据
    send () {
      // 文本框的内容
      this.text = document.getElementsByClassName('textarea')[0].innerText
      // 当前时间
      var time = this.timestampToTime(Date.now() / 1000)
      // 参数
      var data = {
        username: sessionStorage.getItem('user'),
        title: this.title,
        text: this.text,
        ctime: time
      }
      // 提交数据
      this.$post('/insert/', data, {headers: {'Content-Type': 'application/x-www-form-urlencoded'}}).then(res => {
        this.$message({
          message: '发布成功',
          type: 'success'
        })
        this.$router.push({
          name: 'homepage'
        })
      })
    },
    // 返回homepage页面
    exit () {
      this.$router.push({
        name: 'homepage'
      })
      this.title = ''
      this.text = ''
    }
  },
  mounted () {

  }
}

</script>

五.Django接口:

接 (三.homepage)中我们发送请求的接口需要,在我们上一篇博文从零到一搭建一个属于自己的博客系统(弌)views.py文件中书写以下代码,数据库详情下滑查看(六.数据库):

def homepage(request):
    # 获取传来的值
    data=request.GET
    # 打开数据库连接
    # 地址,用户名,密码,数据库名,编码格式
    db = MySQLdb.connect("localhost", "root", "", "bolg", charset='utf8')
    # 使用cursor()方法获取操作游标
    cursor = db.cursor()

    # SQL 查询语句
    sql = "SELECT * FROM text_table WHERE username='%s'"%data['username']
    try:
        # 执行SQL语句
        cursor.execute(sql)
        # 获取所有记录列表
        results = cursor.fetchall()

    except:
        print("Error: unable to fecth data")

    db.close()
    return JsonResponse(results, safe=False)
    
import json
def insert(request):
    # 获取传来的值,将数据转化为json格式
    data = json.loads(request.body, encoding='utf-8')
    # 打开数据库连接
    # 地址,用户名,密码,数据库名,编码格式
    db = MySQLdb.connect("localhost", "root", "", "bolg", charset='utf8')
    # 使用cursor()方法获取操作游标
    cursor = db.cursor()

    # SQL 语句
    sql = "INSERT INTO text_table(username,title,dz,pl,ctime,text) VALUES ('%s','%s','%s','%s','%s','%s')"%(data['username'],data['title'],0,0,data['ctime'],data['text'])
    try:
        # 执行SQL语句
        cursor.execute(sql)
        # 提交到数据库执行
        db.commit()

    except:
        # 如果发生错误则回滚
        db.rollback()
        print("Error: unable to fecth data")

    db.close()
    return JsonResponse(data)

然后我们在urls.py文件中加入下面的代码:

urlpatterns = [
    # 用户登录验证接口
    path('login/',views.login),
    # 数据展示接口
    path('homepage/', views.homepage),
    #插入数据接口
    path('insert/', views.insert),
]

因为我们在查找时候加入了条件WHERE username='%s'"%data['username'],也就是前端传来的数据,当前的用户是谁,就显示谁的数据。


六.数据库:

在 (三.homepage首页) 中我们建立的数据库如下所示,表名为text_table:
在这里插入图片描述
解释:

  1. id:自增型,唯一的标识;
  2. username:用户名,哪一个用户所提交的数据;
  3. title:文章的标题;
  4. text:发布的文章内容;
  5. dz:点赞数;
  6. pl:评论数;
  7. ctime:发布文章的时间;

七.项目演示:

说了那么多了,我们来看看具体的效果:
在这里插入图片描述
成功后数据库的截图:
在这里插入图片描述

路由守护部分:
在这里插入图片描述


八.总结:

当前项目可执行的操作:

  1. 登录的操作;
  2. 首页信息的显示,不同用户不同数据信息;
  3. 文章的书写,数据库中的文章插入;
  4. session中的信息判断用户的登录与否,登录的用户…

– -好了,今天就到这儿了,我要捡瓶子去维持生活了,有人要一起吗?- - -
在这里插入图片描述