Springboot + Vue separa los extremos frontal y posterior para realizar el sistema de blog (artículos de Vue front-end)

1. Introducción

A continuación, completemos algunas de las funciones de la interfaz de vueblog. Las tecnologías que se pueden utilizar son las siguientes:

  • vista
  • elemento-ui
  • axios
  • mavon-editor
  • rebajarlo
  • github-markdown-css

Utilice npm install element-ui, npm install github-markdown-css directamente ...

2. Preparación ambiental

1) Primero instale el nodo y descargue la dirección del nodo:

Paquete de instalación oficial de Node.js y dirección de descarga del código fuente: http://nodejs.org/download/

Una vez completada la instalación de node, verifique la información de la versión (si se le solicita un error, configure las variables de entorno y agregue la ruta de nodejs a la ruta)

 

2) El entorno donde está instalado vue

# 安装淘宝npm
npm install -g cnpm --registry=https://registry.npm.taobao.org
# vue-cli 安装依赖包
cnpm install --g vue-cli

3. Nuevo proyecto

Ingrese la carpeta especificada y ejecute: vue init webpack vue-blog-front; donde vue-blog-front es el nombre del proyecto.

Para crear el proyecto aquí, debe esperar un tiempo 0.0, el vscode que uso aquí, importar el proyecto recién creado

1. Ejecute npm install primero para descargar las dependencias requeridas por el proyecto.

Explicación general de la estructura de directorios

├── README.md            项目介绍
├── index.html           入口页面
├── build              构建脚本目录
│  ├── build-server.js         运行本地构建服务器,可以访问构建后的页面
│  ├── build.js            生产环境构建脚本
│  ├── dev-client.js          开发服务器热重载脚本,主要用来实现开发阶段的页面自动刷新
│  ├── dev-server.js          运行本地开发服务器
│  ├── utils.js            构建相关工具方法
│  ├── webpack.base.conf.js      wabpack基础配置
│  ├── webpack.dev.conf.js       wabpack开发环境配置
│  └── webpack.prod.conf.js      wabpack生产环境配置
├── config             项目配置
│  ├── dev.env.js           开发环境变量
│  ├── index.js            项目配置文件
│  ├── prod.env.js           生产环境变量
│  └── test.env.js           测试环境变量
├── mock              mock数据目录
│  └── hello.js
├── package.json          npm包配置文件,里面定义了项目的npm脚本,依赖包等信息
├── src               源码目录 
│  ├── main.js             入口js文件
│  ├── app.vue             根组件
│  ├── components           公共组件目录
│  │  └── title.vue
│  ├── assets             资源目录,这里的资源会被wabpack构建
│  │  └── images
│  │    └── logo.png
│  ├── routes             前端路由
│  │  └── index.js
│  ├── store              应用级数据(state)状态管理
│  │  └── index.js
│  └── views              页面目录
│    ├── hello.vue
│    └── notfound.vue
├── static             纯静态资源,不会被wabpack构建。
└── test              测试文件目录(unit&e2e)
  └── unit              单元测试
    ├── index.js            入口脚本
    ├── karma.conf.js          karma配置文件
    └── specs              单测case目录
      └── Hello.spec.js

2. Utilice npm para instalar Router, Vuex, element-ui

3. En main.js en el directorio src, introduzca la dependencia element-ui.

import Element from 'element-ui'
import "element-ui/lib/theme-chalk/index.css"

// 引入element
Vue.use(Element)

Luego, puede usar el componente element-ui en la página .

4.npm instalar axios

npm install axios --save

Luego, también presentamos axios globalmente en main.js.

import axios from 'axios'

// 全局引用axios
Vue.prototype.$axios = axios 

En el componente, podemos iniciar nuestra solicitud a través de este. $ Axios.get ().

5. Enrutamiento de página

Definimos varias páginas en la carpeta de vistas:

  • BlogDetail.vue (página de detalles del blog)
  • BlogEdit.vue (Editar blog)
  • Blogs.vue (lista de blogs)
  • Login.vue (página de inicio de sesión)

Aquí solo explica BlogDetail.vue (página de detalles del blog), otras páginas son similares (por supuesto, debes tener algunos conocimientos de front-end)

La estructura de la página es:

<template>

   <div>

           这里就是实现页面的内容

   </div>

</template>

<script>

       这里面就是js了,一些定义的变量,引入的js、模块、一些访问后端的方法

</script>

<style scoped>

      /* scoped 代表该css只在该页面有效 */

       这里放该页面的样式css

</style>
<template>
  <div>
    <Header></Header>

    <div class="mblog">
      <h2> {
   
   { blog.title }}</h2>
      <el-link icon="el-icon-edit" v-if="ownBlog">
        <router-link :to="{name: 'BlogEdit', params: {blogId: blog.id}}" >
        编辑
        </router-link>
      </el-link>
      <el-divider></el-divider>
      <div class="markdown-body" v-html="blog.content"></div>

    </div>

  </div>
</template>

<script>
  import 'github-markdown-css'
  import Header from "../components/Header";

  export default {
    name: "BlogDetail.vue",
    components: {Header},
    data() {
      return {
        blog: {
          id: "",
          title: "",
          content: ""
        },
        ownBlog: false
      }
    },
    created() {
      const blogId = this.$route.params.blogId
      console.log(blogId)
      const _this = this
      this.$axios.get('/blog/' + blogId).then(res => {
        const blog = res.data.data
        _this.blog.id = blog.id
        _this.blog.title = blog.title

        var MardownIt = require("markdown-it")
        var md = new MardownIt()

        var result = md.render(blog.content)
        _this.blog.content = result
        _this.ownBlog = (blog.userId === _this.$store.getters.getUser.id)

      })
    }
  }
</script>

<style scoped>
  .mblog {
    box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1);
    width: 100%;
    min-height: 700px;
    padding: 20px 15px;
  }

</style>

Se introduce un componente común en la página, el contenido del encabezado de la página se extrae en un componente y la página que necesita el contenido del encabezado puede importar directamente el componente.

Luego configure el centro de enrutamiento:

  • enrutador \ index.js
import Vue from 'vue'
import VueRouter from 'vue-router'
import Login from '../views/Login.vue'
import Blogs from '../views/Blogs.vue'
import BlogEdit from '../views/BlogEdit.vue'
import BlogDetail from '../views/BlogDetail.vue'

Vue.use(VueRouter)

const routes = [
  {
    path: '/',
    name: 'Index',
    redirect: {name: "Blogs"}
  },
  {
    path: '/blogs',
    name: 'Blogs',
    component: Blogs
  },
  {
    path: '/login',
    name: 'Login',
    component: Login
  },
  {
    path: '/blog/add',
    name: 'BlogAdd',
    component: BlogEdit,
    meta: {
      requireAuth: true
    }
  },
  {
    path: '/blog/:blogId',
    name: 'BlogDetail',
    component: BlogDetail
  },
  {
    path: '/blog/:blogId/edit',
    name: 'BlogEdit',
    component: BlogEdit,
    meta: {
      requireAuth: true
    }
  }
]

const router = new VueRouter({
  mode: 'history',
  base: process.env.BASE_URL,
  routes
})

export default router

A continuación vamos a desarrollar nuestra página. Entre ellos, con meta: requireAuth: true significa que es un recurso restringido al que solo se puede acceder después de iniciar sesión, que se utilizará más adelante cuando interceptemos los permisos de enrutamiento.

página de inicio de sesión

Login.vue

<template>
  <div>

    <el-container>
      <el-header>
        <img class="mlogo" src="https://www.markerhub.com/dist/images/logo/markerhub-logo.png" alt="">
      </el-header>
      <el-main>
        <el-form :model="ruleForm" :rules="rules" ref="ruleForm" label-width="100px" class="demo-ruleForm">
          <el-form-item label="用户名" prop="username">
            <el-input v-model="ruleForm.username"></el-input>
          </el-form-item>
          <el-form-item label="密码" prop="password">
            <el-input type="password" v-model="ruleForm.password"></el-input>
          </el-form-item>

          <el-form-item>
            <el-button type="primary" @click="submitForm('ruleForm')">立即创建</el-button>
            <el-button @click="resetForm('ruleForm')">重置</el-button>
          </el-form-item>
        </el-form>

      </el-main>
    </el-container>

  </div>
</template>

<script>
  export default {
    name: "Login",
    data() {
      return {
        ruleForm: {
          username: 'frank',
          password: '111111'
        },
        rules: {
          username: [
            { required: true, message: '请输入用户名', trigger: 'blur' },
            { min: 3, max: 15, message: '长度在 3 到 15 个字符', trigger: 'blur' }
          ],
          password: [
            { required: true, message: '请选择密码', trigger: 'change' }
          ]
        }
      };
    },
    methods: {
      submitForm(formName) {
        this.$refs[formName].validate((valid) => {
          if (valid) {
            const _this = this
            this.$axios.post('/login', this.ruleForm).then(res => {

              console.log(res.data)
              const jwt = res.headers['authorization']
              const userInfo = res.data.data

              // 把数据共享出去
              _this.$store.commit("SET_TOKEN", jwt)
              _this.$store.commit("SET_USERINFO", userInfo)

              // 获取
              console.log(_this.$store.getters.getUser)

              _this.$router.push("/blogs")
            })

          } else {
            console.log('error submit!!');
            return false;
          }
        });
      },
      resetForm(formName) {
        this.$refs[formName].resetFields();
      }
    }
  }
</script>

<style scoped>
  .el-header, .el-footer {
    background-color: #B3C0D1;
    color: #333;
    text-align: center;
    line-height: 60px;
  }

  .el-aside {
    background-color: #D3DCE6;
    color: #333;
    text-align: center;
    line-height: 200px;
  }

  .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;
  }

  .mlogo {
    height: 60%;
    margin-top: 10px;
  }

  .demo-ruleForm {
    max-width: 500px;
    margin: 0 auto;
  }

</style>

Obtenga la información del token del encabezado de la solicitud de resultado devuelto y luego use la tienda para enviar el estado del token y la información del usuario. Una vez finalizada la operación, nos ajustamos a la ruta / blogs, que es la página de la lista de blogs.

const token = res.headers['authorization']
_this.$store.commit('SET_TOKEN', token)
_this.$store.commit('SET_USERINFO', res.data.data)
_this.$router.push("/blogs")

Sincronización del estado del token

store / index.js

import Vue from 'vue'
import Vuex from 'vuex'

Vue.use(Vuex)

export default new Vuex.Store({
  state: {
    token: '',
    userInfo: JSON.parse(sessionStorage.getItem("userInfo"))
  },
  mutations: {
    // set
    SET_TOKEN: (state, token) => {
      state.token = token
      localStorage.setItem("token", token)
    },
    SET_USERINFO: (state, userInfo) => {
      state.userInfo = userInfo
      sessionStorage.setItem("userInfo", JSON.stringify(userInfo))
    },
    REMOVE_INFO: (state) => {
      state.token = ''
      state.userInfo = {}
      localStorage.setItem("token", '')
      sessionStorage.setItem("userInfo", JSON.stringify(''))
    }

  },
  getters: {
    // get
    getUser: state => {
      return state.userInfo
    }

  },
  actions: {
  },
  modules: {
  }
})

Para almacenar tokens, usamos localStorage para almacenar información del usuario y usamos sessionStorage. Después de todo, no necesitamos guardar la información del usuario durante mucho tiempo. Una vez que se guarda la información del token, podemos inicializar la información del usuario en cualquier momento.

Definir el interceptor global de axios

Haga clic en el botón de inicio de sesión para iniciar una solicitud de inicio de sesión. Cuando se realiza correctamente, se devuelven los datos. Si la contraseña es incorrecta, también debería aparecer un mensaje emergente. Para hacer que esta ventana emergente de error se pueda usar en todos los lugares, hice un interceptor posterior para axios, es decir, al devolver datos, si el código de resultado o el estado es anormal, responderé a la ventana emergente -up ventana emergente.

import axios from 'axios'
import Element from 'element-ui'
import router from './router'
import store from './store'


axios.defaults.baseURL = "http://localhost:8088"

// 前置拦截
axios.interceptors.request.use(config => {
  return config
})

axios.interceptors.response.use(response => {
    let res = response.data;

    console.log("=================")
    console.log(res)
    console.log("=================")

    if (res.code === 200) {
      return response
    } else {

      Element.Message.error('错了哦,这是一条错误消息', {duration: 3 * 1000})

      return Promise.reject(response.data.msg)
    }
  },
  error => {
    console.log(error)
    if(error.response.data) {
      error.message = error.response.data.msg
    }

    if(error.response.status === 401) {
      store.commit("REMOVE_INFO")
      router.push("/login")
    }

    Element.Message.error(error.message, {duration: 3 * 1000})
    return Promise.reject(error)
  }
)

Interceptación de permisos de ruta

permiso.js

import router from "./router";

// 路由判断登录 根据路由配置文件的参数
router.beforeEach((to, from, next) => {

  if (to.matched.some(record => record.meta.requireAuth)) { // 判断该路由是否需要登录权限

    const token = localStorage.getItem("token")
    console.log("------------" + token)

    if (token) { // 判断当前的token是否存在 ; 登录存入的token
      if (to.path === '/login') {

      } else {
        next()
      }
    } else {
      next({
        path: '/login'
      })
    }
  } else {
    next()
  }
})

A través de la metainformación cuando definimos el enrutamiento de la página antes, especifique requireAuth: true, y necesitamos iniciar sesión para acceder, por lo que aquí juzgamos el estado del token antes de cada enrutamiento (router.beforeEach), y pensamos si es necesario ir a la página de inicio de sesión.

{
  path: '/blog/add', // 注意放在 path: '/blog/:blogId'之前
  name: 'BlogAdd',
  meta: {
    requireAuth: true
  },
  component: BlogEdit
}

Luego importamos nuestro permiso.js en main.js

import './ allow.js' // interceptación de ruta

Finalmente inicie la prueba del proyecto:

1.npm instalar

2.npm ejecutar servir

Comenzó exitosamente.

Desde entonces, se ha completado el desarrollo front-end de vue. Código de front-end

Referencia del artículo

Supongo que te gusta

Origin blog.csdn.net/qq_33371766/article/details/106871052
Recomendado
Clasificación