马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。
您需要 登录 才可以下载或查看,没有账号?立即注册
×
一、路由管理器阐明
- 1.route:译为路由,可以理解为单个路由或者某一个路由。
- 2.routes:路由集合,可以理解为多个route的集合。
- 3.router:路由器,可以理解为路由集合的管理者。例如,当我们在页面上点击某个按钮之后,router就会去routes中查找route,即路由管理者会去路由集合中寻找路由。
复制代码 二、路由依靠
- 在package.json文件中添加路由依赖
- "dependencies": {
- "axios": "^0.18.0",
- "vue": "^2.5.2",
- "vue-router": "^3.0.1",
- "element-ui": "^2.3.7",
- "js-cookie": "^2.2.0",
- "nprogress": "^0.2.0",
- "vuex": "^3.0.1",
- "echarts": "^4.2.0-rc.2",
- "normalize.css": "^8.0.0",
- "v-charts": "^1.19.0",
- "v-distpicker": "^1.0.20"
- },
复制代码 三、路由引入
- 在main.js中引入路由
- import Vue from 'vue'
- import App from './App'
- import router from './router'
- new Vue({
- el: '#app',
- router,
- store,
- components: { App },
- template: '<App/>'
- })
复制代码 四、注册全局组件方式
- 如果需要把某一js文件注册为全局使用,则可以通过如下方式
- import tools from '@/utils/tools' // 在main.js中引入文件
- Vue.prototype.$tools=tools; //注册为全局变量
- this.$tools.openNewWindowOut(this.backLink);
复制代码 五、监听某个变量的厘革
- 示例:在我们通过ajax获取某个url请求地址,通过该url打开弹出式窗口或被拦截,原因:
- 当时用window.open()打开新浏览器窗口,如果这个url是通过ajax从后台获取,则会被浏览器拦截,因为浏览器监测到非用户行为打开新的浏览器窗口,认为这可能是广告或者不安全的操作;
- 怎么避免浏览器的这种拦截行为?
- 已说明这种拦截的情况是因为非用户操作产生的,因为可通过确认框由用户确认后打开,基于这种方式,我们可事先在vue页面绑定某个变量,当用户触发操作之后,把通过ajax获取的url变量赋给绑定的变量,在监测这个事先绑定的变量值的变化,具体实现如下:
- data(){
- backUrl:'',
- backLink:'',
- },
- methods:{
- // 用户点击按钮
- backClick(){
- if(this.backUrl){
- this.backLink = this.backUrl;
- }else{
- this.$message("请稍后,正在上架中....");
- }
- },
- },
- watch:{
- // 方法名和变量名相同
- backLink(){
- this.$tools.openNewWindowOut(this.backLink);
- this.backLink = null; //置空的原因:允许打开多个
- }
- }
复制代码 六、路由守卫
- import router from './router'
- // 顶部进度条
- import NProgress from 'nprogress'
- // token文件导入
- import {getToken} from '@/utils/auth'
- import store from './store'
- import { Message } from 'element-ui'
- // 不授权就可以访问的页面
- const whitePageList = ['/login']
- /**
- * 路由守卫
- * 在路由守卫中,只有next()是放行,其它的如:next('/login'),next(to),next({...to,replace:true})都不是放行,而是中断当前导航,执行新的导航
- * next('/login')说明:
- * 此含义并不是直接去/login路由,而是中断(中断指的是:不会执行router.afterEach(()=>{})),而是又进入一层路由守卫,这是to.path已经是新的路由,
- * 才执行next()放行。
- * 重点:在addRoutes()动态添加路由之后第一次访问被添加的路由,会出现白屏?
- * 这是因为刚刚addRoutes()完就立即访问,此时addRoutes()还没有执行结束,从而找不到刚添加的路由导致白屏,此时需要重新访问路由才可以。
- * 如何解决这种问题:
- * 使用next({..to,replace:true})来确保addRoutes()动态添加的路由已经完全被加载结束,
- * replace:true 告诉Vue,本次操作之后,不能通过浏览器后退按钮,返回前一个路由,
- * 因此也可以直接写为:next(...to),作用为:如果参数to不能找到对应的路由之后,就再执行router.beforeEach(),直到能够找到对应的路由为止;这就意外着,
- * 如果能够找到对应的路由,那么addRoutes()就执行结束了,接下来会执行一次正确的路由,因此需要合适的设置next(),否则会进入死循环。
- */
- router.beforeEach((to,from,next)=>{
- NProgress.start(); // 开始NProgress
- // 获取token
- if(getToken()){
- if(to.path === '/login'){
- next({path:'/'});
- NProgress.done(); // 结束NProgress
- }else{
- // 如果用户角色列表长度为0,则获取用户信息,动态生成路由列表
- if(store.getters.roles.length === 0){
- store.dispatch('GetInfo').then(res=>{
- let menus = res.data.menus;
- let username = res.data.username;
- store.dispatch('GenerateRoutes',{menus,username}).then(()=>{
- router.addRoutes(store.getters.addRouters); // 动态添加可访问路由表
- next({ ...to, replace: true })
- })
- }).catch(error=>{
- // 如果拉取用户信息出错,则登出重新登录
- store.dispatch('FedLogOut').then(res=>{
- Message.error(err || 'Verification failed, please login again');
- next('/');
- });
- })
- }else{
- next();
- }
- }
- }else{
- // 如果没有登录,又不在白名单则直接放开
- if(whitePageList.indexOf(to.path) != -1){
- next();
- }else{
- next('/login');
- NProgress.done(); // 结束NProgress
- }
- }
- })
- // 路由之后
- router.afterEach(()=>{
- NProgress.done(); // 结束NProgress
- })
复制代码 七、拦截哀求和相应axios
- import axios from 'axios'
- import {Message,MessageBox } from 'element-ui'
- import store from "../store";
- import {getToken} from "./auth";
- /**
- * axios介绍:
- * 简单的讲,就是发送get和set请求的
- * 拦截请求和响应
- * 转换请求和响应数据
- * 自动转换json等
- */
- //创建axios实例
- const service = axios.create({
- baseURL:process.env.BASE_API,
- timeout:15000 // 请求超时时间
- })
- // request请求拦截器
- service.interceptors.request.use(config=>{
- // 在发送请求之前,判断token是否存在,如果存在,则把token添加到请求头header中
- if(store.getters.token){
- config.headers.Authorization = getToken();
- }
- return config;
- },error=>{
- console.log(error);
- /**
- * Promise:异步操作对象序列化
- * Promise是一个对象,用于表示异步操作的成功或失败的结果,一般有三种状态:
- * pending:初始状态,既不代表成功,也不代表失败,
- * fulfilled:意外着操作成功完成,也可以称为resolved状态
- * rejected:意外着操作失败
- * pending状态的Peomise对象,可能触发fulfilled状态,并传递一个值给相应的状态处理方法;也有可能触发rejected状态并给相应的状态处理方法传递失败的值,
- * 当出现上述任意一种状态时,Promise对象的then方法绑定的事件处理方法(handler)就会被调用(then方法的参数有两个:onfulfilled和onrejected,
- * 并且都为Function类型,事件处理方法会根据不同的状态调用不同的方法)。
- *
- */
- Promise.reject(error);
- })
- // response拦截器
- service.interceptors.response.use(response=>{
- const res = response.data;
- /**
- * 判断返回值状态,如果为200-正常响应,401-未登录异常,否则为错误或异常响应
- */
- if(res.code !== 200){
- Message({
- message:res.message, // 错误响应的信息
- type:"error", // 提示信息类型
- duration:3 * 1000 //错误信息展示时间,单位为毫秒
- });
- if (res.code === 401 ){
- MessageBox.confirm('你已被登出,可以取消继续留在该页面,或者重新登录',
- '确定登出',
- {
- confirmButtonText:'重新登录',
- cancelButtonClass:'取消',
- type:"error"
- }).then(()=>{ // then作用:当then之前的语句被执行之后,再异步执行then内部的程序,可防止数据初始化失败造成的页面无法加载. 可多个连续使用
- // 发送登出请求,重新载入当前页面
- location.reload();
- })
- }
- return Promise.reject('error');
- }else{
- return res;
- }
- },error=>{
- console.log('err'+error);
- Message({
- message:error.message, // 错误响应的信息
- type:"error", // 提示信息类型
- duration:3 * 1000 //错误信息展示时间,单位为毫秒
- });
- })
- export default service
复制代码 八、多个组件共享某个状态Vuex
- import Vue from 'vue'
- import Vuex from 'vuex'
- import getters from './getters'
- import user from "./modules/user"
- import permission from "./modules/permission";
- /**
- * Vuex介绍:
- * 重点:多个组件共享某个状态
- * Vuex是专门为vue.js开发的状态管理模式,它将集中存储管理应用中组件的状态,并用一定的规则保证状态朝着可预测的方向变化。
- * store :仓库 state:状态
- * VUE组件从store中读取状态,如果store中的状态发生变化,则相关的组件的状态将高效的更新。
- * 不能直接改变store中的state(状态),改变的方式只能是显式的提交(commit),方便跟踪某个状态的变化
- * 触发状态变更方式:store.commit('increment')
- *
- *
- * this.$store.dispatch('isLogin', true):异步操作,数据提交至 actions ,可用于向后台提交数据
- * this.$store.commit('loginStatus', 1):同步操作,数据提交至 mutations ,可用于登录成功后读取用户信息写到缓存里
- * 虽然提交的方式不同,但都是传值个vuex的mutation,进而改变state
- */
- Vue.use(Vuex);
- const store = new Vuex.Store({
- modules: {user,permission},
- getters
- })
- export default store
复制代码- /**
- * Vuex中Getters的说明:
- * store(容器)中的state派生状态的管理
- * Getters可以认为是store的计算属性,其返回值会根据依赖缓存,并且只有依赖值发生变化后才会重新计算
- * 对外暴露的公共接口为:store.getter
- */
- const getters = {
- sideBar: state => state.app.sideBar,
- // 设备
- device:state => state.app.device,
- // 客户端缓存的用户名
- token:state => state.user.token,
- // 用户头像
- avatar: state => state.user.avatar,
- // 用户名
- name: state => state.user.name,
- // 登录用户所属角色
- roles: state => state.user.roles,
- // 动态路由设置
- addRouters: state => state.permission.addRouters,
- routers: state => state.permission.routers
- }
- export default getters
复制代码- import {getToken,setToken,removeToken} from "../../utils/auth"
- import {login,loginOut,getInfo} from "../../api/login";
- /**
- * Vuex中各参数说明
- * state:
- * 单一状态树,此状态树包含整个应用层级会话的状态,
- * mutations:
- * 更改store容器中的状态的唯一方式就是提交mutation(突变),每一个mutation都有一个type(类型)和handler(回调函数),这个handler就是我们
- * 实际进行state更改的地方,并且会接收state作为第一个参数,特别注意的是,每个mutation必须是同步函数,其原理为:在回调函数中进行的状态更新是不了追踪的。
- * actions:
- * 前面说明,为了所有的应用层级别的会话状态的更新都是可追踪的,所以引入了只能进行同步操作的mutations,但是在vuex中,也引入了能进行一步操作的actions,
- * Actions包含任何的异步操作,虽然提交的是Mutation,但却不是直接更改状态。
- *
- */
- const user = {
- state:{
- // 本地token
- token:getToken(),
- // 用户名
- name:'',
- // 头像
- avatar:'',
- // 所属角色组
- roles:[]
- },
- mutations:{
- SET_TOKEN:(state,token)=>{
- state.token = token;
- },
- SET_NAME:(state,name)=>{
- state.name = name;
- },
- SET_AVATAR:(state,avatar)=>{
- state.avatar = avatar;
- },
- SET_ROLES:(state,roles)=>{
- state.roles = roles;
- }
- },
- actions:{
- // 登录
- Login({commit},userInfo){
- const userName = userInfo.userName.trim();
- return new Promise((resolve,reject)=>{
- login(userName, userInfo.passWord).then(response=>{
- const data = response.data;
- const tokenHeader = data.tokenHead + data.token;
- setToken(tokenHeader);
- // 提交突变状态
- commit('SET_TOKEN',tokenHeader);
- resolve();
- }).catch(error=>{
- reject(error);
- })
- })
- },
- // 获取用户信息
- GetInfo({commit},state){
- return new Promise((resolve,reject)=>{
- getInfo().then(response=>{
- const data = response.data;
- if(data.roles && data.roles.length > 0){
- commit('SET_ROLES',data.roles);
- }else{
- reject('getInfo: roles must be a non-null array !');
- }
- commit('SET_NAME',data.username);
- commit('SET_AVATAR',data.icon);
- resolve(response)
- }).catch(error=>{
- reject(error);
- })
- });
- },
- // 后台登出
- LogOut({commit},state){
- return new Promise((resolve, reject) => {
- loginOut().then(response=>{
- const data = response.data;
- // 突变会话级别的变量
- commit('SET_TOKEN','');
- commit('SET_ROLES',[]);
- // 删除本地token
- removeToken();
- // 成功响应
- resolve();
- }).catch(error=>{
- reject(error)
- })
- });
- },
- // 前端登出
- FedLogOut({commit},state){
- return new Promise((resolve, reject) => {
- commit('SET_TOKEN', '')
- removeToken()
- resolve()
- });
- }
- }
- }
- export default user
复制代码 九、vue中svg的组件
- import Vue from 'vue'
- import SvgIcon from '@/components/SvgIcon'// svg组件
- // 全局注册
- Vue.component('svg-icon', SvgIcon)
- const requireAll = requireContext => requireContext.keys().map(requireContext)
- /* require.context("./test", false, /.test.js$/);
- 这行代码就会去 test 文件夹(不包含子目录) 下面的找所有文件名以 .test.js 结尾的文件能被 require 的文件。
- 更直白的说就是 我们可以通过正则匹配引入相应的文件模块。
- require.context有三个参数:
- directory:说明需要检索的目录
- useSubdirectories:是否检索子目录
- regExp: 匹配文件的正则表达式
- */
- const req = require.context('./svg', false, /\.svg$/)
- requireAll(req)
复制代码- <template>
- <svg :class="svgClass" aria-hidden="true">
- <use :xlink:href="iconName"></use>
- </svg>
- </template>
- <script>
- export default {
- name: 'svg-icon',
- props: {
- iconClass: {
- type: String,
- required: true
- },
- className: {
- type: String
- }
- },
- computed: {
- iconName() {
- return `#icon-${this.iconClass}`
- },
- svgClass() {
- if (this.className) {
- return 'svg-icon ' + this.className
- } else {
- return 'svg-icon'
- }
- }
- }
- }
- </script>
- <style scoped>
- .svg-icon {
- width: 1.2em;
- height: 1.2em;
- vertical-align: -0.18em;
- fill: currentColor;
- overflow: hidden;
- }
- </style>
复制代码 十、passive和prevent区别
- W3C规定,当一个from元素中只有一个输入框时,在该输入框中按下回车键该表单应该提交,如果希望阻止这一默认的行为,
- 则需要在<el-from>标签上加上@submit.native.prevent.
- native:把一个vue组件转化为一个普通的HTML标签,并且该修饰符对普通HTML标签是没有任何作用的。
- prevent:阻止某些标签默认拥有的事件,如a[href="#"],button[type="submit"],这类标签会在冒泡结束后自动执行默认事件,
- passive:通俗点说就是每次事件产生,浏览器都会去查询一下是否有preventDefault阻止该次事件的默认动作。我们加上passive就是为了告诉浏览器,
- 不用查询了,我们没用preventDefault阻止默认动作。
- ** passive和prevent冲突,不能同时绑定在一个监听器上
复制代码 |