vue-element-admin源码分析(一)

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qq_29729735/article/details/82853556

这两天看花裤衩大大的手摸手系列,使用vue+element+vuex+axios实现了一个后台模板(项目地址),在阅读源码的过程中收益匪浅,以下做一些笔记。(由于是学习大大项目的思想,所以略去了很多大大的代码)。
这里只是做一个登陆页面,然后能提交数据给后台并能接收数据,暂时没有做路由守卫同跳转。

首先配置并安装好好所需要的main.js

import Vue from 'vue'
import App from './App'
import router from './router'     //路由
import './assets/styles/reset.css'//初始化css样式
Vue.config.productionTip = false
import Element from 'element-ui'  //引入element-ui
import 'element-ui/lib/theme-chalk/index.css'
Vue.use(Element)
import store from '@/store/index'  //vuex
/* eslint-disable no-new */
new Vue({
  el: '#app',
  router,
  store,
  components: { App },
  template: '<App/>'
})

配置路由router/index.js

import Vue from 'vue'
import Router from 'vue-router'

Vue.use(Router)

export default new Router({
  routes: [
    {
	    path: '/',
	    component: () => import('@/views/login/index'),
	    hidden: true
	},
  ]
})

登陆页面:views/login/index.vue

1、这里自定义校验规则,在el-form里定义:rules并传入约定的验证规则,并将 Form-Item 的 prop 属性设置为需校验的字段名,然后在data里声明规则,这里定义表单都是必须填写,当鼠标失去焦点,即鼠标点了其他地方会触发,校验器为自定义行数,自定义函数最后调用callback()。如:

data(){
	const validateUsername = (rule,value,callback)=>{..some code... callback();}
	const validatePassword= (rule,value,callback)=>{..some code... callback();}//自定义校验规则,传入3个参数value表示要校验的数据。
	return {
		loginRules:{
					username: [{required:true,trigger:'blur',validator:validateUsername}],//这里表示必填表单,失去焦点时触发,检验器为:validateUsername
					password: [{required:true,trigger:'blur',validator:validatePassword}]
				},
	}
}

2、当点击按钮是做两个工作,一是判断表单是否已经完成校验,二是发送请求。这里为了方便存储并调用用户信息,使用vuex管理用户状态,使用this.$store.dispatch(这里现在main.js配置好store)方法传给vuex的actions。

在methods里通过 this.$refs.loginForm.validate(valid=>{})校验表单是否验证正确,若 验证正确valid=true,若验证失败valid=false
代码如下:

<template>
	<div class="login-container">
		<el-form :model="loginForm" :rules="loginRules" ref="loginForm" class="login-form" auto-complate="on">
			<div class="title-container">
				<h3 class="title">后台登录</h3>
			</div>
			<el-form-item prop="username">
				 <el-input
		          v-model="loginForm.username"
		          placeholder="用户名"
		          name="username"
		          type="text"
		          auto-complete="on"
		        />
			</el-form-item>
			<el-form-item prop="password">
				 <el-input
		          v-model="loginForm.password"
		          placeholder="密码"
		          name="password"
		          type="text"
		          auto-complete="on"
		        />
			</el-form-item>
			<el-form-item>
				<el-button type="primary" style="width:100%;margin-bottom:30px;" @click.native.prevent="handleLogin">登录</el-button>
			</el-form-item>
		</el-form>
	</div>

</template>
<script>
	export default {
		data(){
			const validateUsername = (rule,value,callback) => {
				const usernamemap = ['admin','editor'];
				if(!usernamemap.indexOf(value.trim()) >= 0){
					callback(new Error ('please input the correct username'))
				}else{
					callback()
				}
			}
			const validatePassword = (rule,value,callback) => {
				if(value.length<6){
					callback(new Error ('The password can not be less then 6 digits'))
				}else{
					callback()
				}
			}
			return {
				loginForm:{
					username:'admin',
					password:'111111'
				},
				loginRules:{
					username: [{required:true,trigger:'blur',validator:validateUsername}],
					password: [{required:true,trigger:'blur',validator:validatePassword}]
				},
				loading:false,
			}
		},
		methods:{
			handleLogin(){
				this.$refs.loginForm.validate(valid => {
					if(valid){//检验通过
						this.loading=true;
						//this.$store.dispatch('LoginByUsername',this.loginForm)
						this.$store.dispatch('LoginByUsername',this.loginForm).then(()=>{this.loading=false;console.log('success')}).catch(()=>{console.log('err')})
					}
				})
			}
		},
	}
</script>
<style rel="stylesheet/scss" lang="scss" scoped>
$bg:#2d3a4b;
$dark_gray:#889aa4;
$light_gray:#eee;
	.login-container{
		position:fixed;
		width:100%;
		height:100%;
		background-color:$bg;
		.login-form{
			position:absolute;
			left:0;
			right:0;
			width:520px;
			max-width:100%;
			margin:120px auto;
		}
	}
	.title-container{
		postion:relative;
		.title{
			font-size:26px;
			color:$light_gray;
			margin: 0px auto 40px auto;
			text-align:center;
			font-weight:bold;
		}
	}
</style>

传输数据与存储数据

请求拦截器的封装
这里使用axios发送与接受请求,为了做权限认证这里在每次发送请求header都会携带上一个X-Token,所以封装了一个axios的拦截器。设置发送请求的前缀为http://localhost/vue/(这是我自己定义的)
utils/request.js

import axios from 'axios'
import { Message } from 'element-ui'
import store from '@/store'
import { getToken } from '@/utils/auth'

// create an axios instance
const service = axios.create({
  baseURL: 'http://localhost/vue/', // api 的 base_url
  timeout: 5000 // request timeout
})

// request interceptor
service.interceptors.request.use(
  config => {
    // Do something before request is sent
    if (store.getters.token) {
      // 让每个请求携带token-- ['X-Token']为自定义key 请根据实际情况自行修改
      config.headers['X-Token'] = getToken()
    }
    return config
  },
  error => {
    // Do something with request error
    console.log(error) // for debug
    Promise.reject(error)
  }
)

// response interceptor
service.interceptors.response.use(
  response => response,

  error => {
    console.log('err' + error) // for debug
    Message({
      message: error.message,
      type: 'error',
      duration: 5 * 1000
    })
    return Promise.reject(error)
  }
)

export default service

发送请求 api/login.js
使用php的同学需要用qs.stringify对传输的数据转换一下格式。这里的loginByUsername返回的是一个axios实例,方便后边vuex进行then或catch操作

import request from '@/utils/request' //引入拦截器
import axios from 'axios'
import qs from 'qs'
export function loginByUsername(username, password) {
  const data = {
    username,
    password
  }
  return request({
    url: 'login.php',
    method: 'post',
    data:qs.stringify(data)   //这里对数据进行了转换(原文是没有转换的,但我用的是php)
  })
}

login.php
该文件与先项目存在同源策略问题,故需要配置一下header,让非同源请求可以请求并受到相应的数据,注意需要设置可以X-Token。为了做出一个效果,这里随便简单地写一个逻辑。

<?php
<?php
header('Access-Control-Allow-Origin:*');  // 响应类型 
header('Access-Control-Allow-Methods:*');   // 响应头设置 
header('Access-Control-Allow-Headers:x-requested-with,content-type,X-Token');   //设置可以接受X-Token头
if(isset($_POST['username'])&&isset($_POST['password'])){
	if($_POST['username']=='admin'&&$_POST['password']=='111111'){
		$res['login'] = md5(true);
	}else{
		$res['login'] = md5(false);
	}
	//$res['login'] = true;
	echo json_encode($res);	
}

?>

Vuex
这里的actions.LoginByUsername返回一个Promise对象,方便login页面作进一步then或catch操作

import Vue from 'vue'
import Vuex from 'vuex'
import { loginByUsername } from '@/api/login'
import { setToken,getToken } from '@/utils/auth'
Vue.use(Vuex);

const store = new Vuex.Store({
	state:{
		token:getToken() || ''
	},
	mutations:{
		LoginByUsername(state,data){
			state.token = setToken(data.login)
		}
	},
	actions:{
		LoginByUsername(ctx,userInfo){
			return new Promise((resolve,reject)=>{
				loginByUsername(userInfo.username, userInfo.password).then(response=>{
					ctx.commit('LoginByUsername',response.data);
					resolve();
				}).catch(error => {reject(error)})
			})
			
		}
	}
})

export default store

总结:
运行流程:
login页面进行表单验证,然后验证成功点击按钮,将数据发送到vuex,有actions的方法发送请求LoginByUsername,发送请求时会进行一个请求拦截,会在请求头header里加入X-Token,php返回token以及其他数据如权限等并存储在vuex和cookie,LoginByUsername会返回一个Promise对象,方便login页面调用then或catch操作。

猜你喜欢

转载自blog.csdn.net/qq_29729735/article/details/82853556