Springboot + Vueはフロントエンドとバックエンドを分離してブログシステムを実現します(フロントエンドVue記事)

1はじめに

次に、vueblogフロントエンドのいくつかの機能を完了しましょう。使用できるテクノロジーは次のとおりです。

  • 見る
  • element-ui
  • axios
  • mavon-編集者
  • マークダウン-それ
  • github-markdown-css

npm install element-ui、npm installgithub-markdown-cssを直接使用します...

2.環境への備え

1)最初にノードをインストールしてノードアドレスをダウンロードします。

Node.jsの公式インストールパッケージとソースコードのダウンロードアドレス:http//nodejs.org/download/

ノードのインストールが完了したら、バージョン情報を確認します(エラーが表示された場合は、環境変数を構成し、nodejsのパスをパスに追加します)

 

2)vueがインストールされている環境

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

3.新しいプロジェクト

指定されたフォルダーを入力して、次のコマンドを実行します。vueinit webpack vue-blog-front;ここで、vue-blog-frontはプロジェクト名です。

ここでプロジェクトを作成するには、しばらく待つ必要があります。ここで使用するvscodeは、作成したばかりのプロジェクトをインポートします。

1.最初にnpminstallを実行して、プロジェクトに必要な依存関係をダウンロードします。

ディレクトリ構造の一般的な説明

├── 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. npmを使用して、Router、Vuex、element-uiをインストールします

3. srcディレクトリの下のmain.jsで、element-ui依存関係を導入します。

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

// 引入element
Vue.use(Element)

次に、ページのelement-uiコンポーネントを使用できます

4.npmインストールaxios

npm install axios --save

次に、main.jsでaxiosをグローバルに紹介します。

import axios from 'axios'

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

コンポーネントでは、this。$ axios.get()を介してリクエストを開始できます。

5.ページルーティング

ビューフォルダの下にいくつかのページを定義します。

  • BlogDetail.vue(ブログ詳細ページ)
  • BlogEdit.vue(ブログの編集)
  • Blogs.vue(ブログのリスト)
  • Login.vue(ログインページ)

ここではBlogDetail.vue(ブログの詳細ページ)についてのみ説明します。他のページも同様です(もちろん、フロントエンドの知識が必要です)

ページの構造は次のとおりです。

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

共通のコンポーネントがページに導入され、ページのヘッダーコンテンツがコンポーネントに抽出され、ヘッダーコンテンツが必要なページがコンポーネントを直接インポートできます。

次に、ルーティングセンターを構成します。

  • router \ 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

次に、ページの開発に進みます。その中で、meta:requireAuth:trueは、ログイン後にのみアクセスできる制限付きリソースであることを意味します。これは、後でルーティング権限をインターセプトするときに使用されます。

ログインページ

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>

返された結果リクエストヘッダーからトークン情報を取得し、ストアを使用してトークンのステータスとユーザー情報を送信します。操作が完了したら、ブログリストページである/ blogsルートに調整しました。

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

トークンステータスの同期

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: {
  }
})

トークンを保存するには、localStorageを使用してユーザー情報を保存し、sessionStorageを使用します。結局のところ、ユーザー情報を長期間保存する必要はありません。トークン情報が保存されると、いつでもユーザー情報を初期化できます。

グローバルaxiosインターセプターを定義する

ログインボタンをクリックしてログインリクエストを開始します。成功するとデータが返されます。パスワードが間違っている場合は、メッセージプロンプトもポップアップ表示されます。このエラーを発生させるために、ポップアップウィンドウはすべての場所で使用できるため、axiosのポストインターセプターを作成しました。つまり、データを返すときに、結果コードまたはステータスが異常な場合は、ポップに応答します。 -ポップアップウィンドウプロンプト。

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

ルート許可の傍受

permit.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()
  }
})

前にページルーティングを定義するときのメタ情報を通じて、requireAuth:trueを指定し、アクセスするにはログインする必要があるため、ここでは、各ルーティング(router.beforeEach)の前にトークンのステータスを判断し、必要かどうかを検討します。ログインページにジャンプします。

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

次に、permission.jsをmain.jsにインポートします

import './ permission.js' //ルートインターセプト

最後に、プロジェクトテストを開始します。

1.npmインストール

2.npm実行サーブ

正常に開始しました。

それ以来、vueのフロントエンド開発が完了しました。フロントエンドコード

記事参照

おすすめ

転載: blog.csdn.net/qq_33371766/article/details/106871052