搭建VUE项目
- 使用 vue-cli 脚手架搭建初始项目
- 删除与项目不相关的文件及图标
- 创建远程仓库,关联仓库地址
- 创建开发中需要的文件夹:
- views:用于存放路由组件,每个路由组件也对应有自己的文件夹
- utils:存放功能性 js 文件
- store:vuex管理文件
- layout:存放菜单文件
- router:路由管理文件
- mixin:管理混入功能 js 文件
- ...
- 如果需要配置 webpack,在根目录下创建 vue.config.js 文件来添加和修改配置
- 引入 axios 封装请求api
- 引入 elementUi 组件库
- 引入 样式预处理语言
- 引入 Vuex,配置基本文件
- 引入 vue-router 配置路由
- 重置公共样式(一些标签组件的默认样式)
vue脚手架配置代理处理跨域问题
- 代理就是在客户端与真实服务器之间,再建立一个中转的服务器,这个服务的访问地址与客户端同源,就不会产生跨域问题,而服务器与服务器之间是不受同源策略影响的
- 在vue.config.js中添加如下配置:
- 方法一:
- 在vue.config.js文件中配置
devServer:{proxy:"http://localhost:5000"}
- 但这种方式只能配置一个代理地址,不够灵活
- 这种代理会先向自身寻找
module.exports = {
pages: {
index: {
entry: 'src/main.js',
},
},
lintOnSave:false,
devServer: {
proxy: {
'/api': {
target: 'http://localhost:5000',
pathRewrite:{'^/api':''},
},
'/demo': {
target: 'http://localhost:5001',
pathRewrite:{'^/demo':''},
}
}
}
}
vue-router 使用
- 路由守卫
- 全局前置路由守卫(beforeEach),在路由跳转前执行的回调,一般可以用来做权限跳转,判定允许跳转后一定要调用 next()
- 全局后置路由守卫(afterEach)————初始化的时候被调用、每次路由切换之后被调用
- 路由独享守卫(beforeEnter)在定义路由规则时配置,用法与全局前置路由守卫一致,没有独享的后置路由
- 组件内的守卫
beforeRouteEnter(to, from, next) { // 在渲染该组件的对应路由被 confirm 前调用 // 不!能!获取组件实例
this // 因为当守卫执行前,组件实例还没被创建 }, beforeRouteUpdate(to, from, next) { // 在当前路由改变,但是该组件被复用时调用 // 举例来说,对于一个带有动态参数的路径 /foo/:id,在 /foo/1 和 /foo/2 之间跳转的时候, // 由于会渲染同样的 Foo 组件,因此组件实例会被复用。而这个钩子就会在这个情况下被调用。 // 可以访问组件实例
this}, beforeRouteLeave(to, from, next) { // 导航离开该组件的对应路由时调用 // 可以访问组件实例
this}
const router = new VueRouter({
mode: 'hash',
routes: [
{
name:'guanyu',
path:'/about',
component: () => import('./About.vue'),
meta:{title: '关于', isAuth: true},
beforeEnter: (to, from, next) => {
}
},
...
],
scrollBehavior (to, from, savedPosition) {
}
})
router.beforeEach((to, from, next) => {
})
router.afterEach((to,from)=>{
console.log('后置路由守卫',to,from)
document.title = to.meta.title || '系统'
})
export default router
路由器的两种工作模式
- 对于一个url来说,什么是hash值?—— #及其后面的内容就是hash值。
- hash值不会包含在 HTTP 请求中,即:hash值不会带给服务器。
- hash模式:
- 地址中永远带着#号,不美观 。
- 若以后将地址通过第三方手机app分享,若app校验严格,则地址会被标记为不合法。
- 兼容性较好。
- history模式:
- 地址干净,美观 。
- 兼容性和hash模式相比略差。
- 应用部署上线时需要后端人员支持,解决刷新页面服务端404的问题。
菜单权限管理 与 按钮权限管理
菜单权限管理
- 首先前端项目中需要有权限管理的菜单和对应的操作组件
- 依据RBAC(role based access control)权限设计的思想
- 首先可以创建和管理员工、角色
- 而所有 权限 由后端返回
- 员工可以赋予多个角色,而根据角色的特点可以分配多个不同的权限
- 根据员工赋予的角色,就可以知道该员工有什么权限,这些都会传给后端保存
- 根据员工登录,可以由后端返回员工所持有的权限
- 根据员工所持有的权限去动态添加路由,vue-router提供了一个叫做addRoutes的API方法,这个方法的含义是动态添加路由规则
- 后端会在返回的员工信息里面返回路由权限的标识,可以将路由模块的根节点
name
属性命名和权限标识一致,这样只要标识能对上,就说明用户拥有了该权限
- 通过筛选的路由再生成静态路由,再去渲染菜单,而路由由 addRoute进行添加
按钮权限管理
- 将每个按钮功能赋予权限标识。
- 后端会保存所有的权限标识,根据登录的员工账号返回拥有的权限
- 前端可以通过 自定义指令 或者 混入 的方式给每个需要权限校验的功能绑定
- 通过绑定的方法传入被绑定的功能的标识,通过返回值的布尔值结果,决定功能是否可以使用
- 可以通过隐藏或者禁用的方式去限制
Element-Ui 按需引入的问题
- 在项目中一般为了让项目内存更小,会在使用UI组件库时,使用按需引入的方式。
- 根据Element官网的配置会出现项目运行不起来
- 第一,会提示各种包未安装,根据提示安装即可
- 第二,将官方的配置文档做一些修改
{
"presets": [
["@babel/preset-env", { "modules": false }]
],
"plugins": [[
"component",
{ "libraryName": "element-ui", "styleLibraryName": "theme-chalk" }
]]
}
项目中一些需要注意的
组件中 props 和 data 权重
- 在一个组件中,如果父组件传入参数对象 props 中的一个属性 和组件本身的 data 返回值中的一个属性重名,这两者之间 props 的属性权重高,页面会渲染由父组件传入的 props 的属性。
- 传入的 props 属性不能在子组件内部直接修改
- 传入子组件的 props 参数属性名不能有关键字,例如:key属性、ref属性
scoped样式
- 作用:让样式在局部生效,防止冲突。
- 写法:
<style scoped>
组件之间传值:自定义事件
- 子组件给父组件传值:通过绑定自定义事件传递
- 父组件使用子组件,在父组件中:
<Demo @atguigu="test"/>
- 子组件内部触发自定义事件:
this.$emit('atguigu',数据)
- 子组件内部解绑自定义事件
this.$off('atguigu')
- this.$off('atguigu') 传入一个字符串,则解除一个自定义事件
- this.$off(['atguigu', 'abc']) 传入一个字符串数组,则解除多个自定义事件
- this.$off() 什么都不传,则解除所有自定义事件
- 在 beforeUnmount 生命周期去解除
- 其他关系组件间传值
- 使用事件总线方式
- 使用消息订阅与发布,需要插件 pubsub,命令:
npm i pubsub-js
自定义组件绑定原生DOM事件
- 自定义组件上也可以绑定原生DOM事件,需要使用
native
修饰符。
<A @click.nativev="函数方法"></A>
native
修饰符就会将 click 当成原生DOM事件,并将这个事件绑定到组件的最外层容器元素上
- 如果没有加
native
修饰,组件上就会将事件以自定义事件处理
nextTick
- 语法:
this.$nextTick(回调函数)
- 作用:在下一次 DOM 更新结束后执行其指定的回调。
- 什么时候用:当改变数据后,要基于更新后的新DOM进行某些操作时,要在nextTick所指定的回调函数中执行。
public 文件夹
- 项目中存在一个文件夹:public,文件夹中有一个 index.html 文件,这个文件就整个应用的界面,也是模板
<!DOCTYPE html>
<html lang="">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width,initial-scale=1.0">
<link rel="icon" href="<%= BASE_URL %>favicon.ico">
<title><%= htmlWebpackPlugin.options.title %></title>
</head>
<body>
// 当浏览器不支持 JavaScript 时就执行 noscript
<noscript>
<strong>We're sorry but <%= htmlWebpackPlugin.options.title %> doesn't work properly without JavaScript enabled. Please enable it to continue.</strong>
</noscript>
<div id="app"></div>
</body>
</html>
混入(mixin)
- 将组件中具有相同处理功能的函数方法提取到一个文件中,通过暴露和引入的方式,去注册混入。达到每个混入的组件都可以实现这个功能。
- 这样就不需要每个组件编写同样的代码,还可以统一管理。
- 混入是通过混入组件中的配置项,相同的配置项会合并。(配置项例如:data,methods,mounted)
- 如果混入的方法或属性与组件内部重复,则会以组件内部为主。
- 混入生命周期配置,而组件内部也有相同的生命周期,则都会执行生命周期里面的代码
- 特别注意混入相同的生命周期,则混入的代码先执行,组件内部的后执行
export const mixin1 = {
methods: {
showName(){
alert(this.name)
}
},
mounted() {
console.log('你好啊!')
},
}
export const mixin2 = {
data() {
return {
name: 'hhh'
}
},
}
import {mixin1, mixin2} from '混入的文件路径'
mixins:[mixin1, mixin2]
import {mixin1, mixin2} from '混入的文件路径'
Vue.mixin(mixin1)
Vue.mixin(mixin2)
webStorage 浏览器储存
- 存储内容大小一般支持5MB左右(不同浏览器可能还不一样)
- 浏览器端通过 Window.sessionStorage 和 Window.localStorage 属性来实现本地存储机制。
- 相关API:
xxxxxStorage.setItem('key', 'value');
该方法接受一个键和值作为参数,会把键值对添加到存储中,如果键名存在,则更新其对应的值。
xxxxxStorage.getItem('person');
该方法接受一个键名作为参数,返回键名对应的值。
xxxxxStorage.removeItem('key');
该方法接受一个键名作为参数,并把该键名从存储中删除。
xxxxxStorage.clear()
该方法会清空存储中的所有数据。
- 备注:
- SessionStorage存储的内容会随着浏览器窗口关闭而消失。
- LocalStorage存储的内容,需要手动清除才会消失。
xxxxxStorage.getItem(xxx)
如果xxx对应的value获取不到,那么getItem的返回值是null。
JSON.parse(null)
的结果依然是null。