vue项目搭建和配置
第一步:创建项目vue create bigscreen第二步:进行项目的的配置,在vue.config.js配置文件中配置module.exports = {outputDir: process.env.VUE_APP_OUTPUTDIR,publicPath: process.env.VUE_APP_PUBLICPATH,css: {loaderOptions: {scss: {
第一步:创建项目
vue create bigscreen
第二步:进行项目的的配置,在vue.config.js配置文件中配置
module.exports = {
outputDir: process.env.VUE_APP_OUTPUTDIR,
publicPath: process.env.VUE_APP_PUBLICPATH,
css: {
loaderOptions: {
scss: {
prependData: `@import "~@/index.scss";`//全局样式
},
}
},
devServer: {
host: '',
port: '80',
disableHostCheck: true,
// proxy: {
// // 统一认证模块API转发
// /* "/paycode/": {
// target: '',
// changeOrigin: true,
// logLevel: 'debug'
// },*/
// },
// setup: function handleAPIRequest(app) {
// },
},
第三步:页面文件夹的创建:
api文件夹,utils文件夹,公共样式style文件夹,router路由文件夹,store公共数据vuex文件夹,iconfont文件夹
第四步:配置项目所需要用到的框架下载:常用到的框架包
dependencies中放置的是我们生产环境中需要的依赖
devDependencies放置的是我们开发时用的依赖项,–save-dev
"axios": "^0.27.2",
"core-js": "^3.6.5",
"echarts": "^5.3.2",
"echarts-liquidfill": "^3.1.0",
"element-ui": "^2.15.8",
"vue": "^2.6.11",
"vue-router": "^3.2.0",
"vue-seamless-scroll": "^1.1.23", //页面滚动包
"vuex": "^3.4.0"
第五步:配置路由
- 在router文件夹下建立index.js文件,并且引入页面进行路由的配置
import Vue from 'vue'
import VueRouter from 'vue-router'
import Home from '../views/Home.vue'
Vue.use(VueRouter)
const routes = [
{
path: '/',
name: 'Home',
component: Home
},
]
const router = new VueRouter({
mode: 'history',
base: process.env.BASE_URL,
routes
})
export default router
- 如果需要对store数据进行模块化,可在store文件夹下建立module文件夹,此文件夹下可以分别建立多个不同的vuex模块分开管理数据,比如建立departments.js
departments.js 文件代码演示
import Layout from '@/layout'
// 员工的路由规则
export default {
path: '/departments', // 路由地址
hidden: true,
name: 'departments', // 给模块的一级路由加一个name属性,后面会用到
component: Layout, // 布局组件
children: [{
// 二级路由的path什么都不写的时候,此时表示是二级路由的默认路由
path: '', // 这里不写的话,表示二级路由的默认路由
component: () => import('@/views/departments'), // 路由懒加载
name: 'departments',
hidden: true,
// 路由信息,meta存储数据的地方,可以放任何内容
meta: {
title: '组织架构', // 左侧导航读取了这里的title
icon: 'tree'
}
}]
}
---------------------------------------------------------------------------------------
router下的index.js的代码演示
import Vue from 'vue'
import Router from 'vue-router'
Vue.use(Router)
/* Layout */
import Layout from '@/layout'
// 引入多个模块的规则
import departmentsRouter from './modules/departments'
import employeesRouter from './modules/employees'
import userRouter from './modules/user'
// 动态路由
export const asyncRoutes = [
departmentsRouter,
employeesRouter,
]
// 静态路由constantRoutes
export const constantRoutes = [
{
path: '/login',
component: () => import('@/views/login/index'),
hidden: true
},
{
path: '/404',
component: () => import('@/views/404'),
hidden: true
},
{
path: '/',
component: Layout,
redirect: '/dashboard',
children: [{
path: 'dashboard',
name: 'dashboard',
component: () => import('@/views/dashboard/index'),
meta: { title: '首页', icon: 'dashboard' }
}]
},
{
path: '/import',
component: Layout, // 以及布局布局组件
hidden: true, // 不显示在左侧菜单中
children: [{
path: '', // 二级路由path什么都不写,表示二级默认路由
component: () => import('@/views/import/index')
}]
},
userRouter
// 404 page must be placed at the end !!!
]
const createRouter = () => new Router({
mode: 'history', // require service support
base: 'rz',
scrollBehavior: () => ({ y: 0 }),
routes: [...constantRoutes] // 临时合并所有的路由
})
const router = createRouter()
// Detail see: https://github.com/vuejs/vue-router/issues/1234#issuecomment-357941465
export function resetRouter () {
const newRouter = createRouter()
router.matcher = newRouter.matcher // reset router
}
export default router
- 在main.js文件中引入router文件,挂载vue实例
import Vue from 'vue'
import App from './App.vue'
import router from './router'
new Vue({
router,
store,
element,
render: h => h(App)
}).$mount('#app')
第六步,配置vuex
- 在store文件夹下建立index.js
index.js代码演示
import Vue from 'vue'
import Vuex from 'vuex' // 引入vuex
Vue.use(Vuex) //vue注册vuex
export default new Vuex.Store({ // 在vuex上挂载store实例配置项
state: {
},
mutations: {
},
actions: {
},
modules: {
}
})
- 如果需要对vuex数据进行模块化,可在store文件夹下建立module文件夹,此文件夹下可以分别建立多个不同的vuex模块分开管理数据,比如建立user.js
user.js代码演示
// 引入封装本地缓存的方法
import { getToken, setToken, removeToken, setTimeStamp } from '../../../utils/auth'
import { login } from '../../api/user'
//数据状态
const state = {
}
// 修改状态的数据
const mutations = {
}
// 异步请求方法
const actions = {
}
// getters计算属性
const getters = {
}
export default {
namespaced: true,
state,
mutations,
actions,
getters
}
----------------------------------------------------------------------------------------
模块化后的store下的index.js代码演示
import Vue from 'vue'
import Vuex from 'vuex'
import user from './modules/user'
Vue.use(Vuex)
export default new Vuex.Store({
state: {
},
mutations: {
},
actions: {
},
modules: {
namespaced: true, // 为了解决不同模块命名冲突的问题
user
}
})
- 在main.js文件中引入store文件,挂载vue实例
import Vue from 'vue'
import App from './App.vue'
import router from './router'
import store from './store'
Vue.config.productionTip = false // 这句代码为false,它会阻止你显示显示生产模式的消息,这句代码为true,它会显示你生产模式的消息。所以,在开发环境下,保持默认设置false即可。
Vue.prototype.$echarts = echarts //定义一个全局的变量$echarts挂载到vue原型链上, 在其他vue文件通过this.$echarts就可以访问到echarts
new Vue({
router,
store,
element,
render: h => h(App)
}).$mount('#app')
第七步:配置网络请求信息axios
- 在utils文件夹下封装axios模块,先建立request.js引入单独的axios模块
代码演示:
import axios from "axios"
import store from '@/store'
import router from '@/router'
const instance = axios.create({
// 反向代理是解决不同环境下跨域的问题,设置基础值地址是统一设置url地址。基础地址的设置会触
发反向代理的跨域配置,所以要先设置好反向代理
baseURL: process.env.VUE_APP_API_BASE_URL,
timeout: 1000 * 60,
headers: { 'content-type': 'application/x-www-form-urlencoded' }
});
// 添加请求拦截器
// instance 以...为例
// interceptors英文翻译拦截机
instance.interceptors.request.use(function (config) {
// 在发送请求之前做些什么
// 在这个位置需要统一的去注入token
if (store.getters.token) {
// 只有在有token的情况下 才有必要去检查时间戳是否超时
if (IsCheckTimeOut()) {
// 如果它为true表示 过期了
// token没用了 因为超时了
store.dispatch('user/logout') // 登出操作
// 跳转到登录页
router.push('/login')
return Promise.reject(new Error('token超时了'))
}
// 如果token存在 注入token
config.headers['Authorization'] = `Bearer ${store.getters.token}`
}
return config // 必须返回配置
}, function (error) {
// 对请求错误做些什么
return Promise.reject(error);
});
// 添加响应拦截器
instance.interceptors.response.use(function (response) {
// 对响应数据做点什么
const { success, message, data } = response.data
if (success) {
return data
} else {
Message.error(message)
return Promise.reject(new Error(message))
}
}, function (error) {
// 对响应错误做点什么
if (error.response && error.response.data && error.response.data.code === 10002) {
// 后端告诉我token超时了,被动处理token
store.dispatch('user/logout') // 登出action 删除token
router.push('/login')
} else {
// 提示错误信息
Message.error(error.message)
}
// 返回执行错误,让当前的执行链跳出来
return Promise.reject(error)
});
export default instance
第八步:在api请求封装模块中,引入axios并且进行请求方法的封装,比如在api下建立user.js
user.js文件模块展示
import request from '@/utils/request'
import qs from 'qs'
/**
* 登录接口封装
*/
export function login (data) {
// 返回一个promise对象
return request({
url: '/sys/login',
method: 'POST',
data:qs.stringify(data)
})
}
===
至此项目搭建配置基本完成!
目录知识扩展:
api:放置接口文件
assets:放置图片的静态资源目录
components:放置公共组件
directives:放置负责管理所有的自定义指令
// 定义第一个自定义指令 v-imagerror export const imagerror = { // 指令对象,钩子函数inserted,会在当前的dom元素插入到节点之后执行 inserted (dom, options) { // dom表示当前指令作用的对象,此时就是作用在图片上 // options 是指令中的变量的解释 // 当图片有地址,但是地址没有加载成功的时候,会报错,会触发图片的一个事件,onerror dom.src = dom.src || options.value // 初始化时有值就赋值,无值使用默认值赋值 dom.onerror = function () { // dom可以注册error事件 // 当图片出现异常的时候,会将指令配置的默认图片设置为该图片的内容 dom.src = options.value // 这里不能写死,活的指令多方调用 } }, // 该函数和inserted一样,也是一个钩子函数 componentUpdated (dom, options) { // 这个函数会在当前指令作用的组件更新数据完毕之后执行 // inserted只会执行一次,组件更新后就不会在执行inserted了 // 组件初始化后一旦更新,就不会在进入inserted函数了,会进入当前这个componentUpdated 函数 dom.src = dom.src || options.value } }
filters:放置过滤的验证的方法都可以
// import parseTime, formatTime and set to filter // 验证手机号 export function checkPhone (rule, value, callback) { if (!value) { return callback(new Error('手机号不能为空')) } else { const reg = /^1[3|4|5|7|8][0-9]\d{8}$/ if (reg.test(value)) { callback() } else { return callback(new Error('请输入正确的手机号')) } } } export function checkPassword (rule, value, callback) { if (!value) { return callback(new Error('密码不能为空')) } else if (value.length < 6) { callback(new Error('请至少输入 6 个字符。请不要使用容易被猜到的密码')) } else { callback() } } // 手机号证验证 export function checkTel (value, callback) { var reg = /^1[3|4|5|7|8][0-9]\d{8}$/ return reg.test(value) } // 身份证验证 export function checkiDNumber (value, callback) { var reg = /\d{17}[\d|x]|\d{15}/ return reg.test(value) } // 身份证验证 export function checkEmails (value, callback) { var reg = /^[A-Za-zd]+([-_.][A-Za-zd]+)*@([A-Za-zd]+[-.])+[A-Za-zd]{2,5}$/ return reg.test(value) } // 邮箱验证 export function checkEmail (rule, value, callback) { if (!value) { return callback(new Error('邮箱不能为空')) } else { var reg = /^[A-Za-zd]+([-_.][A-Za-zd]+)*@([A-Za-zd]+[-.])+[A-Za-zd]{2,5}$/ if (reg.test(value)) { callback() } else { return callback(new Error('请输入正确的邮箱')) } } } // 英文验证 export function checkCode (value, callback) { var reg = /^[A-Za-z]+$/g return reg.test(value) } // qq验证 export function checkQq (value, callback) { var reg = /^[0-9]+$/g return reg.test(value) } // 银行卡号 export function formatBankNo (BankNo, callback) { var strBin = '10,18,30,35,37,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,58,60,62,65,68,69,84,87,88,94,95,98,99' return strBin } export function getStrleng (str, max) { var myLen = 0 for (var i = 0; i < str.length && myLen <= max * 2; i++) { if (str.charCodeAt(i) > 0 && str.charCodeAt(i) < 128) { myLen++ } else myLen += 2 } return myLen } // 上传图片格式控制 export function updatedImg (file, obj, callback, func) { if (file.size < 10100000) { var fileName = file.name var suffix = fileName .substring(fileName.lastIndexOf('.') + 1) .toUpperCase() if ( suffix === 'PDF' || suffix === 'JPG' || suffix === 'JPEG' || suffix === 'PNG' || suffix === 'GIF' ) { return true } else { var tipType = '文件类型不正确,请重新上传' callback(tipType) return false } } else { var tipSize = '文件大小超过5M,请重新上传' callback(tipSize) return false } } // 上传文档格式控制 export function updatedFile (file, obj, callback, func) { if (file.size < 10100000) { var fileName = file.name var suffix = fileName .substring(fileName.lastIndexOf('.') + 1) .toUpperCase() if ( suffix === 'DOC' || suffix === 'DOCX' || suffix === 'XLS' || suffix === 'XLSX' || suffix === 'PDF' || suffix === 'ZIP' || suffix === 'RAR' ) { return true } else { var tipType = '文件类型不正确,请重新上传' callback(tipType) return false } } else { var tipSize = '文件大小超过5M,请重新上传' callback(tipSize) return false } } export function importFile (file, obj, callback, func) { if (file.size < 10100000) { var fileName = file.name var suffix = fileName .substring(fileName.lastIndexOf('.') + 1) .toUpperCase() if ( suffix === 'XLS' || suffix === 'XLSX' ) { return true } else { var tipType = '文件类型不正确,请重新上传' callback(tipType) return false } } else { var tipSize = '文件大小超过10M,请重新上传' callback(tipSize) return false } }
lang:放置语音包
mixin:放置混入对象方法
import store from '@/store' // 做一个混入对象 export default { // 混入对象是组件的选项对象 methods: { // 检查权限,key是要检查的点 checkPermission (key) { // 去用户的信息中的poins中有没有key,有key则认为 有权限,没有就不能点击 // store.state.user.userInfo.roles.poins const { userInfo } = store.state.user if (userInfo.roles && userInfo.roles.points) { return userInfo.roles.points.some(item => item === key) } return false } } }
router:放置路由
store:放置vuex数据
styles:放置公共的样式文件
utils:放置工具文件,放置axios的封装文件request,放置本地存储,cookie存储封装的方法
// auth.js封装存储cookie,获取cookle, 移除cookie的方法 import Cookies from 'js-cookie' const TokenKey = 'hrsaas-ihrm-token' // 设定一个独一无二的key export function getToken () { return Cookies.get(TokenKey) } export function setToken (token) { return Cookies.set(TokenKey, token) } export function removeToken () { return Cookies.remove(TokenKey) } const timeKey = 'hrsaas-timestamp-key' // 设置一个独一无二的key // 获取时间戳 export function getTimeStamp () { return Cookies.get(timeKey) } // 设置时间戳 export function setTimeStamp () { Cookies.set(timeKey, Date.now()) }
permission.js:权限管理文件,路由守卫
// 是控制页面登录权限的文件, 此处的代码没有经历构建过程会很难理解, 所以先将此处的代码进行注释,等我们构建权限功能时,再从0到1进行构建。 // 权限拦截在路由跳转,导航守卫 import router from '@/router' import store from '@/store' // 引入store实例,这个和组件中的this.$store是一回事 import NProgress from 'nprogress' // 引入一份进度条插件 import 'nprogress/nprogress.css' // 引入进度条样式 // 前置守卫 // next是前置是守卫必须执行的钩子,next必须执行,不执行页面就死了 // next()放行 // next(false)跳转终止 // next(地址),跳转到某个地址 // 用户资料有个硬性要求,必须要有token才可以获取,所以可以在确定有token的位置去获取用户资料,跳到主页了,有token不用处理,在else放行时处理 window.rrr = router router.beforeEach(async (to, from, next) => { NProgress.start() if (store.getters.token) { // 如果有token,判断是否是登录页 if (to.path === '/login') { next('/') // 跳转主页 } else { // 只有在放行的时候才去获取资料 // 是每次都获取资料吗,如果当前vuex中有用户的资料的id,表示已经有资料了,不需要在获取了,如果没有id才需要 获取 if (!store.getters.userId) { // async函数return的内容,用await就可以接收到 const { roles } = await store.dispatch('user/getUserInfo') // console.log(roles) // 如果后续需要根据用户资料获取数据的话,这里必须改成头部 // 这里得到的routes就是筛选得到的动态路由 const routes = await store.dispatch('permission/filterRoutes', roles.menus) // 筛选得到当前用户可用的动态路由 console.log(routes) router.addRoutes([...routes], { path: '*', redirect: '/404', hidden: true }) next(to.path) } next() // 有token但不是登录页,就放行 } } else { // 如果没有token const whiteList = ['/login', '/404'] if (whiteList.indexOf(to.path) !== -1) { // 表示要去的地址在白名单 next() } else { next('/login') } } // 手动强制关闭进度条 NProgress.done() }) // 后置守卫 router.afterEach(() => { NProgress.done() })
setting.js:
// settings.js`**则是对于一些项目信息的配置,里面有三个属性 **`title`**(项目名称),**`fixedHeader`**(固定头部),**`sidebarLogo`**(显示左侧菜单logo) // **`settings.js`**中的文件在其他的位置会引用到,所以这里暂时不去对该文件进行变动、 module.exports = { title: '人力资源管理平台', /** * @type {boolean} true | false * @description Whether fix the header */ fixedHeader: false, /** * @type {boolean} true | false * @description Whether show the logo in sidebar */ sidebarLogo: true }
更多推荐
所有评论(0)