[前端开发]

搭建环境

node.js搭建

  • node.js官网(https://nodejs.org/zh-cn/),下载最新的长期版本,直接运行安装完成之后,即具备node和npm的环境
  • 下载完成后,在cmd 输入 node -v npm -v
    在这里插入图片描述

安装vue

在node.js的安装盘符

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

分别安装了淘宝npm,cnpm是为了提高我们安装依赖的速度

vue ui

  • vue ui是@vue/cli3.0增加一个可视化项目管理工具,可以运行项目、打包项目,检查等操作

  • 在IDEA项目的部署目录(需要建立vue项目的地方)中,打开powerShell(按住shift再右击目录会显示在此打开power shell 或者在文件夹左上角点击文件,然后有以管理员身份运行powershell)

  • 注意在上一步下载的vue,在打开的powershell中执行 vue ui 无法打开可视化界面

    • vue -V发现为2.9.6版本,需要3X以上版本可以使用vue ui命令
    • npm uninstall vue-cli -g 删除现在已有的vue,再用 npm install -g @vue/cli 重新下载,
    • 再重新执行 vue ui 即可
  • 运行时依然报错如下,解决方法时再系统环境变量上添加发现是:用户变量的path没有配置C:\Windows\System32,添加即可
    在这里插入图片描述

在这里插入图片描述

  • 运行后依然报错,找不到应用程序
    -在这里插入图片描述

解决方法是重新安装Chrome谷歌浏览器,然后重新vue ui(可能是本地的浏览器不支持vue ui打开界面,重新安装chrome后,会弹出浏览器选择框,选择新安装的chrome浏览器即可)

新建项目

成功执行vue ui后 如下图所示
在这里插入图片描述

  • 创建—>再此创建新项目—>填写必要信息后—>下一步
    在这里插入图片描述
    选择手动配置项目
    在这里插入图片描述
    勾选上Router Vuex(可以选择去掉Linter/Formatter) 下一步
    在这里插入图片描述
    选择使用历史路由—>创建项目—>创建项目,不保存预设
    在这里插入图片描述

  • 创建项目后,为了方便开发,可以使用webstorm,vscode,也可以使用IDEA 只是需要给IDEA集成一个Vue.js插件(然后再重启IDEA),此处采用IDEA来进行开发

  • 项目创建完成后如下所示

  • 在这里插入图片描述

项目导入IDEA

在IDEA中 File导入该项目即可(已经集成插件的基础上)

  • /src/components 公共组件
  • /sec/router 前端路由
  • /src/views 路由跳转的view,页面目录
  • /src/store 组件可以监视store中的数据
  • App.vue

集成element-ui

  • 直接在IDEA中对项目进行布置

  • 引入element-ui组件(https://element.eleme.cn)可以获得好看的vue组件用以渲染数据,开发好看的博客界面

  • 注意安装命令均在IDEA的控制台Terminal执行

      # 切换到项目根目录
      cd vueblog-vue# 安装element-ui
      # 安装element-ui
      cnpm install element-ui --save
    
  • 在main.js中引入elenment-ui

      打开项目src目录下的main.js,引入element-ui依赖
      	import Element from 'element-ui'
      	import "element-ui/lib/theme-chalk/index.css"
      	Vue.use(Element)  //全局进行使用element-ui组件
    
  • 至此可以在官网上选择组件复制代码到我们项目中直接使用

  • 测试element-ui组件时,启动项目 ,发现组件成功渲染在页面时,即成功

    • 在控制台执行: npm run serve
    • 在Run/Debug Configurations 配置

安装axios

  • 基于promise的HTTP库,这个这个工具可以再前后端对接时大大提高开发效率

  • IDEA的控制台Terminal执

      cnpm install axios --save
    
  • main.js引入axios依赖

      打开项目src目录下的main.js,在main.js中全局引入axios
      
      import axios from 'axios'
      Vue.prototype.$axios = axios
    
  • 至此在组件中可以通过this.$axios.get()来发起请求

页面路由

定义页面

本项目由于页面较少,可以先定义好路由页面,在需要链接的地方就可以直接使用

  • 在views文件夹下定义几个页面(new component)
    • BlogDetail.vue(博客详情页)
    • BlogEdit.vue(编辑博客)
    • Blogs.vue(博客列表)
    • Login.vue(登录页面)
    • 删除掉原生的Home.vue

页面简单定义

  • .vue下template标签内只能放一个标签(入放一个< div>)

路由中心配置

  • 注意要先把上一步定义的几个.vue导入进index.js

router\index.js

	import Vue from 'vue'
	import VueRouter from 'vue-router'
	import Login from '../views/Login.vue'
	import BlogDetail from '../views/BlogDetail.vue'
	import BlogEdit from '../views/BlogEdit.vue'
	Vue.use(VueRouter)
	const routes = [
	  {   
	   path: '/',    
	   name: 'Blogs',   
	   redirect: { name: 'Blogs' }//主页面,重定向
	  },
	  {    
	   path: '/login',    
	   name: 'Login',   
	   component: Login 
	  }, 
	  {   
	    path: '/blogs', 
	    name: 'Blogs',   
	     // 懒加载   
	    component: () => import('../views/Blogs.vue')  
	   }, 
	 {   
	   path: '/blog/add', // 注意放在 path: '/blog/:blogId'之前 
            name: 'BlogAdd', 
            meta: {     
            requireAuth: true 
            },  
            component: BlogEdit  
         },
         { 
          path: '/blog/:blogId',  
          name: 'BlogDetail',  //显示某篇博客详情,需要id  
          component: BlogDetail 
         }, 
         { 
          path: '/blog/:blogId/edit',  //需要制定修改哪一个blog故需要传递id 
          name: 'BlogEdit',   
          meta: {    
	         requireAuth: true 
	       }, 
          component: BlogEdit
     	 }
   ];

   const router = new VueRouter(
   	  {
	     mode: 'history', 
	     base: process.env.BASE_URL,  
	     routes
	  }
	)
   export default router
  • 带有meta:requireAuth: true说明是需要登录字后才能访问的受限资源
  • 注意路由的顺序严格要求,例如把path: '/blog/:blogId’这个路由放在path: '/blog/add’之前,则访问blog/add可能路由到/blog/:blogId,则不会进入add

登录页面开发

布局

  • 在element-ui中 Container(布局容器),有许多布局样式
  • 选择常见的三项布局,将其代码放入login.vue的< template>标签中,(将附带的一些样式拷进< script> 中)
  • 在element-ui找到布局表单Form控件,找到一个有表单校验规则控件,修改一下,只留下两个输入框和一个提交按钮(注意同时修改校验规则)

views/Login.vue

  • 表单校验(固定写法)

  • 登录按钮的点击登录事件

      < template>
        < div>
    
      <el-container>
      //el-header是el-container的头部区域
        <el-header>
          <img class="mlogo" src="xxxxx" 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>

<  script>
  export default {
    name: "Login",
    data() {
      return {
        ruleForm: {
          username: 'markerhub',
          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

              // 把数据共享出去,存入/strore/index.js
              _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>

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

发起请求

  • 将表单的数据提交给后端,由后端进行校验返回jwt(token)
  • 以前通过ajax发起异步请求,在Vue中采用基于promise的axios

views/Login.vue的提交表单方法

	submitForm(formName) { 
		  
	     	  this.$ refs[formName].validate((valid) => {  
	        if (valid) { 
	        const _this = this//发起axios请求后,后面的this代表的是该请求的this,想要调用index.js中定义的全局参数必须先预存该代表整个vue项目的this
	       // 提交逻辑            
	       //注意,此处的post请求括号内指令前的URL在axios中定义了,此处会自动加上,避免硬编码
	    	this.$axios.post(‘/login', this.ruleForm).then((res)=>{             
	      const token = res.headers['authorization']   
	      	//发起请求后的结果需要赋给
	      	//登陆成功还会返回用户信息通过res.data.data获取
	        //传统项目token是放在cookie中的,vue项目一般会放在localstorage中  
	     	//Vue项目时单页面项目SPA(改变路由时不会刷新整个页面,而是刷新App.vue中<router-view/>中的内容)
	     	//因此多组件的SPA保证都能获取如Jwt,则需要配置到全局参数

		//获取参数
	     	_this.$store.commit('SET_TOKEN', token)       
	      _this.$store.commit('SET_USERINFO', res.data.data)        
	      //跳转页面    
	      _this.$router.push("/blogs")     
	             })      
	    } else {        
	        console.log('error submit!!');          
	        return false;    
            }    
	 });  
    },

配置全局参数

  • 进行token等数据状态同步,存储token,用localStorage;存储用户信息用sessionStorage
  • localStorage,sessionStoraage在页面上

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: {    //类似于java bean的setter方法
	//第一个参数上面定义,第二个为传入的值
		SET_TOKEN: (state, token) => {    
	  		state.token = token     
	  //赋值后存到localStorage,浏览器关闭后仍保存一段时间
           		localStorage.setItem("token", token) 
       		},
		SET_USERINFO: (state, userInfo) => {      
			state.userInfo = userInfo  
			//sessionStorage不能存储对象,只能存字符串之类的值
        			sessionStorage.setItem("userInfo", JSON.stringify(userInfo))  
          	},
         		 //调用remove方法删除掉localStorage,sessionStorage中的数据
		REMOVE_INFO: (state) => {    	
	  		localStorage.setItem("token", '')      		 
	  		sessionStorage.setItem("userInfo", JSON.stringify(''))      	state.userInfo = {}   
	   	}
	 },
	//初始化时直接从sessionStorage中获取(拿到的是序列化的字符串,需要反序列化)
    getters: { 
  			 getUser: state => {      return state.userInfo    } 
   },
}
actions: {},
 modules: {}
})
  • 完成上述配置后,输入用户名密码正确时会跳转到博客界面,但是输入错误时却不会由弹窗提示
  • 此时需要一个全局处理登录异常,可以弹窗提示
  • 做一个全局axios拦截对登陆错误的结果进行弹窗处理

全局axios拦截

  • 对axios做了个后置拦截器,就是返回数据时候,如果结果的code或者status不正常,由对应弹窗提示

  • src目录下创建一个文件axios.js(与main.js同级),定义axios的拦截,需要在main.js 导入

       import axios from 'axios'
       import Element from "element-ui";
       import store from "./store";
       import router from "./router";
       //将域名:端口定义成常量,避免硬编码,
       axios.defaults.baseURL='http://localhost:8081'
       //前置拦截,
       axios.interceptors.request.use(config => {
    
      console.log("前置拦截")
      // 可以统一设置请求头 
       return config
       })
       //后置拦截
       axios.interceptors.response.use(response => {    
       	const res = response.data;   
              console.log("后置拦截")
              //注意这里是采用了http的状态码  
          // 当结果的code是否为200的情况  
          if (res.code === 200) {    
          		return response  
              } else {
      	// 弹窗异常信息   
      	//element-ui的一个组件,要在上方先导入依赖
      	   Element.Message({
      	   	 //弹窗信息
      	         message: response.data.msg,  
      	         type: 'error',
      	         //弹窗过期时间   
      	         duration: 2 * 1000    
      	  })
      	  // 直接拒绝往下面返回结果信息 (不再执行login.vue中后续的逻辑)   
      		  return Promise.reject(response.data.msg)  
       }
      },
      error => {    
      		console.log('err' + error)// for debug  
                 	if(error.response.data) {     
                    error.message = error.response.data.msg 
            }
           // 根据请求状态觉得是否登录或者提示其他
           
           	if(error.response.status= =401 ){
      		store.commit('REMOVE_INFO');
      		//跳转到登陆页面
      		router.push({      
      			  path: '/login'   
      	   });
      	error.message = '请重新登录';
      	}
    
      if (error.response.status = = 403) {     
      	 error.message = '权限不足,无法访问';
          }
           Element.Message({    
          	   message: error.message,
          	   type: 'error',
          	  duration: 3 * 1000
      })
    
      return Promise.reject(error)
      })
    
  • 编写完axios.js,再往main.js中导入axios.js

博客列表

公共组件Header

  • 登录完成之后直接进入博客列表页面,然后加载博客列表的数据渲染出来
  • 同时页面头部我们需要把用户的信息展示出来,很多地方都用到这个模块,把页面头部的用户信息单独抽取出来作为一个组件

构建Header组件

首先在/src新建一个目录components,新建一个Header.vue

头部用户信息

头部的用户信息,应该包含三部分信息:id,头像、用户名,而这些信息在登录之后就已经存在了sessionStorage。可以通过store的getters获取到用户信息

Header代码

  • created()中初始化用户的信息

  • 通过hasLogin的状态来控制登录和退出按钮的切换,以及发表文章链接的disabled,这样用户的信息就能展示出来了(发表文章这个控件绑定了url指向/blog/add)

  • 退出按钮,在methods中有个logout()方法,直接访问/logout(因为之前axios.js中已经设置axios请求的baseURL,不再需要链接的前缀),清除掉srore中的数据,并跳转到登陆页面

    -为什么退出仍然要 this.$axios.get(‘http://localhost:8081/logout’?在AccountController中的logout要将当前角色退出shiro

  • 登录之后才能访问的受限资源,所以在header中带上了Authorization。返回结果清除store中的用户信息和token信息,跳转到登录页面
    在这里插入图片描述
    < template>

      <template>
        <div class="m-content">
          <h3>欢迎来到MarkerHub的博客</h3>
          <div class="block">
          //el的头像组件
            <el-avatar :size="50" :src="user.avatar"></el-avatar>
            <div>{{ user.username }}</div>
          </div>
      
          <div class="maction">
          // el-link标签
            <span><el-link href="/blogs">主页</el-link></span>
            <el-divider direction="vertical"></el-divider>
            <span><el-link type="success" href="/blog/add">发表博客</el-link></span>
      
            <el-divider direction="vertical"></el-divider>
            <span v-show="!hasLogin"><el-link type="primary" href="/login">登录</el-link></span>
      
            <span v-show="hasLogin"><el-link type="danger" @click="logout">退出</el-link></span>
          </div>
      
        </div>
      </template>
    

< script>

		<script>
		  export default {
		    name: "Header",
		    data() {
		      return {
		        user: {
		          username: '请先登录',
		          avatar: 'https://cube.elemecdn.com/3/7c/3ea6beec64369c2642b92c6726f1epng.png'
		        },
		        hasLogin: false
		      }
		    },
		    methods: {
		      logout() {
		        const _this = this
		        _this.$axios.get("/logout", {
		          headers: {
		            "Authorization": localStorage.getItem("token")
		          }
		        }).then(res => {
		          _this.$store.commit("REMOVE_INFO")
		          _this.$router.push("/login")
		
		        })
		      }
		    },
		    created() {
		      if(this.$store.getters.getUser.username) {
		        this.user.username = this.$store.getters.getUser.username
		        this.user.avatar = this.$store.getters.getUser.avatar
		
		        this.hasLogin = true
		      }
		
		    }
		  }
		</script>

< syle>

	<style scoped>
	
	  .m-content {
	    max-width: 960px;
	    margin: 0 auto;
	    text-align: center;
	  }
	  .maction {
	    margin: 10px 0;
	  }
	
	</style>

集成Header组件

import Header from "@/components/Header";
data() {
 components: {Header}}
}
# 然后模板中调用组件
<Header></Header>

博客分页

  • 列表页面,需要做分页,列表我们在element-ui中直接使用时间线组件来作为我们列表样式和分页组件
  • 需要几部分信息
    • 分页信息
    • 博客列表内容,包括id、标题、摘要、创建时间

views\Blogs.vue

  • data()中直接定义博客列表blogs、以及一些分页信息
  • methods()中定义分页的调用接口page(currentPage),参数是需要调整的页码currentPage,得到结果之后直接赋值即可
  • 初始化时候,直接在mounted()方法中调用第一页this.page(1)
  • 注意标题这里我们添加了链接,使用的是标签
  • < el-card>展示了每个标签的内容会展示博客名字,同时有个超链接指向具体的博客详情(需要传递参数blog的id)

< template>

	<template>
	  <div class="mcontaner">
	    <Header></Header>
	
	    <div class="block">
	      <el-timeline>
	
	        <el-timeline-item :timestamp="blog.created" placement="top" v-for="blog in blogs">
	        //卡片组建用于展示分页上的博客信息,如下用标题形式展示了博客的id等
	          <el-card>
	            <h4>
	              <router-link :to="{name: 'BlogDetail', params: {blogId: blog.id}}">
	                {{blog.title}}
	              </router-link>
	            </h4>
	            <p>{{blog.description}}</p>
	          </el-card>
	        </el-timeline-item>
	
	      </el-timeline>
	
	      <el-pagination class="mpage"
	                     background
	                     layout="prev, pager, next"
	                     :current-page="currentPage"
	                     :page-size="pageSize"
	                     :total="total"
	                     @current-change=page>
	      </el-pagination>
	
	    </div>
	
	  </div>
	</template>

< script>

	<script>
	  import Header from "../components/Header";
	
	  export default {
	    name: "Blogs.vue",
	    components: {Header},
	    data() {
	      return {
	        blogs: {},
	        //传给pagination分页插件的参数
	        currentPage: 1,
	        total: 0,
	        pageSize: 5
	      }
	    },
	    methods: {
	      page(currentPage) {
	        const _this = this
	        _this.$axios.get("/blogs?currentPage=" + currentPage).then(res => {
	          console.log(res)
	          _this.blogs = res.data.data.records
	          _this.currentPage = res.data.data.current
	          _this.total = res.data.data.total
	          _this.pageSize = res.data.data.size
	
	        })
	      }
	    },
	    created() {
	      this.page(1)
	    }
	  }
	</script>

< style>

	< style scoped>
	
	  .mpage {
	    margin: 0 auto;
	    text-align: center;
	  }
	
	</style>

博客编辑(发表)

  • 在博客(展示页面)页面,点击header上的发表文章(页面路由)跳转到博客编辑页面
  • 点击击发表博客链接调整到/blog/add页面,需要用到一个markdown编辑器,在vue组件中,比较好用的是mavon-editor,先来安装mavon-editor相关组件

安装mavon-editor

  • 基于Vue的markdown编辑器mavon-editor

      cnpm install mavon-editor --save
    
  • 在main.js中全局注册

      // 全局注册
      import Vue from 'vue'
      import mavonEditor from 'mavon-editor'
      import 'mavon-editor/dist/css/index.css'
      // use
      Vue.use(mavonEditor)
    

view\BlogEdit.vue

  • 校验表单,然后点击按钮提交表单,注意头部加上Authorization信息,返回结果弹窗提示操作成功,然后跳转到博客列表页面

  • 编辑和添加是同一个页面,所以有了create()(在内容开始渲染时就开始)方法,比如从编辑连接/blog/7/edit中获取blogId为7的这个id。然后回显博客信息。获取方式是const blogId = this.$route.params.blogId

  • mavon-editor因为已经全局注册,所以我们直接使用组件即可

      <mavon-editor v-model="editForm.content">
    

在这里插入图片描述
< template>

		< template>
		  <div>
		    <Header></Header>
		
		    <div class="m-content">
		
		      <el-form :model="ruleForm" :rules="rules" ref="ruleForm" label-width="100px" class="demo-ruleForm">
		        <el-form-item label="标题" prop="title">
		          <el-input v-model="ruleForm.title"></el-input>
		        </el-form-item>
		
		        <el-form-item label="摘要" prop="description">
		          <el-input type="textarea" v-model="ruleForm.description"></el-input>
		        </el-form-item>
		
		        <el-form-item label="内容" prop="content">
		          <mavon-editor v-model="ruleForm.content"></mavon-editor>
		        </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>
		
		    </div>
		
		
		
		  </div>
		</template>

< script>

		<script>
		  import Header from "../components/Header";
		  export default {
		    name: "BlogEdit.vue",
		    components: {Header},
		    data() {
		      return {
		      //做每一个输入框的数据验证
		        ruleForm: {
		          id: '',
		          title: '',
		          description: '',
		          content: ''
		        },
		        rules: {
		          title: [
		          //做每一个输入框的输入提示
		            { required: true, message: '请输入标题', trigger: 'blur' },
		            { min: 3, max: 25, message: '长度在 3 到 25 个字符', trigger: 'blur' }
		          ],
		          description: [
		            { required: true, message: '请输入摘要', trigger: 'blur' }
		          ],
		          content: [
		            { trequired: true, message: '请输入内容', trigger: 'blur' }
		          ]
		        }
		      };
		    },
		    methods: {
		      submitForm(formName) {
		        this.$refs[formName].validate((valid) => {
		          if (valid) {
		
		            const _this = this
		            this.$axios.post('/blog/edit', this.ruleForm, {
		              headers: {
		                "Authorization": localStorage.getItem("token")
		              }
		            }).then(res => {
		              console.log(res)
		              _this.$alert('操作成功', '提示', {
		                confirmButtonText: '确定',
		                callback: action => {
		                  _this.$router.push("/blogs")
		                }
		              });
		
		            })
		
		          } else {
		            console.log('error submit!!');
		            return false;
		          }
		        });
		      },
		      resetForm(formName) {
		        this.$refs[formName].resetFields();
		      }
		    },
		    created() {
		    //拿到blog id
		      const blogId = this.$route.params.blogId
		      console.log(blogId)
		      const _this = this
		      if(blogId) {
		      //发送ajax请求,获得进行查询拿到blodid对于的blog内容,	    //生命周期函数在加载后拿到id发送ajax请求将得到的博客内容展示在页面上行
		        this.$axios.get('/blog/' + blogId).then(res => {
		          const blog = res.data.data
		          _this.ruleForm.id = blog.id
		          _this.ruleForm.title = blog.title
		          _this.ruleForm.description = blog.description
		          _this.ruleForm.content = blog.content
		        })
		      }
		
		    }
		  }
		</script>

< Script>

博客详情

  • 博客详情中需要回显博客信息,
  • 后端传过来的是博客内容是markdown格式的内容,需要进行渲染然后显示出来,使用一个插件markdown-it,用于解析md文档,然后导入github-markdown-c,所谓md的样式

安装插件

  • 用于解析md文档
    • cnpm install markdown-it --save
  • md样式
    • cnpm install github-markdown-css

然后就可以在需要渲染的地方使用

views\BlogDetail.vue

  • 初始化create()方法中调用getBlog()方法,请求博客详情接口
  • 返回的博客详情content通过markdown-it工具进行渲染
  • 导入样式 import ‘github-markdown.css’
  • 在content的div中添加class为markdown-body
  • 另外标题下添加了个小小的编辑按钮,通过ownBlog (判断博文作者与登录用户是否同一人)来判断按钮是否显示出来

在这里插入图片描述
< template>

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

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

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

路由权限拦截

  • 页面已经开发完毕之后,控制一下哪些页面是需要登录之后才能跳转的

  • 如果未登录访问就直接重定向到登录页面

  • 在src目录下定义一个js文件:src\permission.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()  
       }
    })
      在定义页面路由时候的meta信息,指定requireAuth: true,需要登录才能访问
      在每次路由之前(router.beforeEach)判断token的状态,觉得是否需要跳转到登录页面
    
  • 再在main.js中import我们的permission.js

    • import ‘./permission.js’ // 路由拦截
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值