当前位置: 首页 > article >正文

vue环境搭建相关介绍

一、路由管理器说明
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冲突,不能同时绑定在一个监听器上

http://www.kler.cn/a/302298.html

相关文章:

  • 实验5:网络设备发现、管理和维护
  • CCI3.0-HQ:用于预训练大型语言模型的高质量大规模中文数据集
  • 微服务day08
  • 量化交易系统开发-实时行情自动化交易-3.4.2.2.Okex交易数据
  • 【数据结构与算法】第12课—数据结构之归并排序
  • 【安全通信】告别信息泄露:搭建你的开源视频聊天系统briefing
  • 在pycharm终端中运行pip命令安装模块时,出现了“你要如何打开这个文件”弹出窗口,是什么状况?
  • Vue基础明晰
  • chatGPT o1 重磅发布!像人类大脑一样思考和推理!
  • 快速入门和简单理解并发编程中的并发、并行、同步、异步,并且简单实现多进程和多线程
  • JS设计模式之代理模式:对象的“虚拟与现实”
  • 基于51单片机的灯盘检测(PCF8591+CD4051 )
  • mp3转文字要怎么处理?使用这4个工具就对了
  • C# 中的矢量化运算:提升性能的艺术
  • OpenHarmony鸿蒙开发( Beta5.0)智能窗帘应该开发实践案例
  • 算法刷题[比较两个字符串的最大公字符串(滑动窗口实现)]
  • 基于Boost库的搜索引擎开发实践
  • OpenFeign原理
  • docker-ce.repo源、kubernetes.repo源
  • 通过AI来创建一个_____html css网页制作成品 例子演示
  • 精准电商营销:基于京东商品详情API返回值的数据分析
  • 探索Python中的链式赋值、系列解包赋值与常量
  • Vue.js中computed的使用方法
  • Minio笔记-Centos搭建Minio
  • pgAdmin 4备份数据库失败,解决
  • 武汉墨家人俱乐部