[Vue] make a message board interface

Posted by Iasonic on Mon, 10 Feb 2020 13:28:26 +0100

Interface display


  • Highlights:
    The color and length of the card can be changed randomly, and the page length layout can be adaptive. Users can click like.

Get ready

  • MySQL
    A message table:

    Message: message content;
    username: processed by the backend. If the submitted one is empty, set the name to anonymous;
    upTime: submission time;
    likeNum: number of likes, 0 by default.

  • back-end
    Just do some simple addition, deletion, modification and query

    MessageMapper:

    <?xml version="1.0" encoding="UTF-8"?>
    <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
            "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
    <mapper namespace="cn.lzy.blog.Mapper.MessageMapper">
    
        <insert id="addMessage" useGeneratedKeys="true" keyProperty="id">
            insert into message set message = #{message},username=#{username},upTime=now()
        </insert>
        <update id="addLike">
            update message set likeNum = likeNum + 1 where id = #{id}
        </update>
        <delete id="deleteMessage">
            delete from message where id = #{id}
        </delete>
        <select id="selectAllMessage" resultType="cn.lzy.blog.Pojo.Message">
            select * from message order by upTime desc
        </select>
    </mapper>
    

    MessageController:

    @RestController
    @RequestMapping("/message")
    public class MessageController {
    
        @Autowired
        private MessageService messageService;
    
        @PostMapping("/add")
        public Response addMessage(@RequestBody Message message){
            Integer id = messageService.addMessage(message);
            if(id >0){
                return Response.Success("Message successfully!",id);
            }
            return Response.Fail("Message failure");
        }
    
        @DeleteMapping("/del/{id}")
        public Response delMessage(@PathVariable Integer id){
            if(messageService.delMessage(id))
                return Response.Success("Delete message succeeded");
            return Response.Fail("Delete message failed");
        }
    
        @GetMapping("/all")
        public Response selMessage(@RequestParam @DefaultValue(value = "1") Integer pageNo,@RequestParam @DefaultValue(value = "10") Integer pageSize){
            PageInfo<Message> messagePageInfo = messageService.selectMessage(pageNo, pageSize);
            if(messagePageInfo != null){
                return Response.Success(messagePageInfo);
            }
            return Response.Fail("Failed to get message");
        }
    
        @PostMapping("/like")
        public Response addLike(@RequestBody JSONObject object){
            if(messageService.addLike(object.getInteger("id")))
                return Response.Success("success");
            return Response.Fail("fail");
        }
    }
    

    MessageService:

    @Service
    public class MessageService {
    
        @Autowired
        private MessageMapper messageMapper;
    
        public Integer addMessage(Message message){
            if(StringUtils.isEmpty(message.getUsername())){
                message.setUsername("anonymous");
            }
            return messageMapper.addMessage(message);
        }
    
        public boolean delMessage(Integer id){
            if(messageMapper.deleteMessage(id) > 0)
                return true;
            return false;
        }
    
        public PageInfo<Message> selectMessage(Integer pageNo,Integer pageSize){
            PageHelper.startPage(pageNo,pageSize);
            return new PageInfo<>(messageMapper.selectAllMessage());
        }
    
        public boolean addLike(Integer id){
            if(messageMapper.addLike(id) > 0){
                return true;
            }
            return false;
        }
    }
    

Front end

The rendering of message board is mainly the work of the front end. Under the separation of the front end and the back end, the back end only needs to search the returned data in pages, and the front end renders.

  • Card encapsulation
    For each Card, we encapsulate the data provided by the parent component. When it's loaded, we randomly generate its color, so what should we do?
    Set the color list, generate a random number when loading, randomly select a color as the color of this card.
    For each Card, you can set like and click the event of like (submit the post request to make like+1). To prevent multiple clicks, you can set the flag bit and set it to true after clicking to prevent further clicks.

    <!--  -->
    <template>
        <el-card
          :style="'margin:0 10px 15px 0;background-color:' + color"
          shadow="hover"
        >
          <div>
            <h2 style="font-size: 100%;font-weight: normal;">{{messageData.upTime|dateFormat}}</h2>
          </div>
          <div>
            <p style="font-size: large;">{{messageData.message}}</p>
          </div>
          <div>
            <h3 class="username">Come from:{{messageData.username}}</h3>
          </div>
          <div @click="like" style="float: right;">
            <el-link type="primary" :underline="false">
              <i class="el-icon-thumb"></i>
              ({{messageData.likeNum}})
            </el-link>
          </div>
        </el-card>
    </template>
    
    <script>
    import { dateFormat2 } from "@/utils/dateFormat";
    import {post} from '@/utils/http'
    export default {
      data() {
        return {
          colorList: ["#97cae6", "#cfc", "#FAC8C8", "#ffc", "#FAC8C8", "#ccf","#c9c","6cc","ff3","#9f6"],
          color: "",
          isLike: false,
        };
      },
      props: ["messageData"],
      mounted() {
        this.color = this.colorList[Math.floor(Math.random() * 10)];
      },
      methods: {
        like() {
          if (!this.isLike) {
            post("/message/like", { id: this.messageData.id }).then(res => {
              if (res.code == 200) {
                this.messageData.likeNum += 1;
                this.isLike = true;
              }
            });
          }
        },
        
      },
      filters: {
        dateFormat(val) {
          return dateFormat2(val);
        }
      }
    };
    </script>
    <style>
    .username {
      font-family: "Eater", cursive;
      color: rgba(33, 33, 33, 0.7);
    }
    </style>
    
  • Parent component call
    When loading, get the Card data from the back end, and randomly generate the width of each Card [i] according to the number of pages found.
    After that, v-for loop is used to set the generation of each card, and message is passed to the sub components.

    <div style="display: flex;justify-content: space-around;flex-wrap: wrap">
          <div
            v-for="(message,index) in messageData"
            :key="index"
            :style="'width:' + width[index] + '%'"
          >
            <Card :messageData="message"></Card>
          </div>
        </div>
    
  • Load codes for all cards on this page:

    <!--  -->
    <template>
      <div>
        <Add></Add>
        <div style="display: flex;justify-content: space-around;flex-wrap: wrap">
          <div
            v-for="(message,index) in messageData"
            :key="index"
            :style="'width:' + width[index] + '%'"
          >
            <Card :messageData="message"></Card>
          </div>
        </div>
        <div style="float:right">
          <el-pagination
            background
            layout="prev, pager, next"
            :total="total"
            @current-change="handleCurrentChange"
          ></el-pagination>
        </div>
      </div>
    </template>
    
    <script>
    import Add from "@/components/message/Add";
    import Card from "@/components/message/Card";
    import { get, post } from "@/utils/http";
    
    export default {
      data() {
        return {
          messageData: [],
          loading: false,
          total: 0,
          pageNo: 1,
          num: 0,
          width: []
        };
      },
      components: {
        Add,
        Card
      },
      mounted() {
        this.loadMessage();
      },
      methods: {
        loadMessage() {
          get("/message/all", {
            pageNo: this.pageNo,
            pageSize: 10
          }).then(res => {
            if (res.code == 200) {
              this.total = res.result.total;
              this.messageData = res.result.list;
              this.num = res.result.size;
              for (var i = 0; i < this.num; i++) {
                this.width[i] = this.randomNum(20, 50); //The width of each card is between 20% and 50%
              }
              this.loading = false;
              window.scrollTo(0, 0);
            } else {
              this.$message.error(res.msg);
              this.loading = false;
            }
          });
        },
    
        handleCurrentChange(val) {
          this.pageNo = val;
          this.loadMessage();
        },
        randomNum(minNum, maxNum) { //Generate a random number between minNum and maxNum
          switch (arguments.length) {
            case 1:
              return parseInt(Math.random() * minNum + 1, 10);
              break;
            case 2:
              return parseInt(Math.random() * (maxNum - minNum + 1) + minNum, 10);
              break;
            default:
              return 0;
              break;
          }
        }
      }
    };
    </script>
    <style>
    </style>
    
  • Add message component package

    <!--  -->
    <template>
      <div>
        <el-input
          type="textarea"
          :autosize="{ minRows: 4, maxRows: 10}"
          placeholder="Leave your comments or suggestions on the website"
          v-model="message"
          style="width:60%;margin:18px 20% 0 20%"
        ></el-input>
        <div>
          <el-row :gutter="20">
            <el-col :span="12" :offset="5">
              <el-input
                placeholder="You can choose to leave your nickname"
                v-model="username"
              ></el-input>
            </el-col>
            <el-col :span="7">
              <el-button @click="submit" type="primary" v-loading="loading" style="margin-bottom:18px">Leaving a message.</el-button>
            </el-col>
          </el-row>
        </div>
      </div>
    </template>
    
    <script>
    import { post } from "@/utils/http";
    export default {
      data() {
        return {
          message: "",
          username: "",
          loading: false
        };
      },
      inject: ["reload"], //Encapsulate reload to refresh the page
      methods: {
        submit() {
          this.loading = true;
          if (this.message == "") {
            this.$message.error("You don't seem to have any message");
            this.loading = false;
            return;
          }
          var params = {
            username: this.username,
            message: this.message
          };
          post("/message/add", params).then(res => {
            if (res.code == 200) {
              this.$message({ type: "success", message: res.msg });
              this.reload();
            } else {
              this.$message.error(res.msg);
              this.username = "";
              this.message = "";
              this.loading = false;
            }
          });
        }
      }
    };
    </script>
    <style>
    </style>
    

epilogue

Welcome to leave a message on my website.

Published 5 original articles, won praise 0, visited 10
Private letter follow

Topics: Mybatis MySQL xml encoding