vue2+vuex+自定义指令 使用接口实现按钮权限控制设置请求超时

112 阅读3分钟

步骤

  1. 创建vue2项目
  2. 创建utils/directiveArr.js文件
export const checkArr=(key)=>{
    let arr=[1,3,5]
    if (arr.indexOf(key)>-1) {
        return true
    }else{
        return false
    }
}
  1. 创建directives/showBtn.js文件,引入utils/directiveArr文件
import { checkArr } from "@/utils/directiveArr";
export default {
    inserted(el,binding){
        let val=binding.value  //获取自定义指令传来的值
        if(val){/
            let has=checkArr(val)//调用checkArr函数判断是否存在数组里面
            if (!has) {
                el.parentNode&&el.parentNode.removeChild(el)//存在调用el属性到父级删除自己
            }
        }else{
            throw new Error('error')
        }
    }
}
  1. 在页面里使用自定义指令,启动项目之后会发现只有一个按钮显示,这是因为在utils/directiveArr.js文件里面的checkArr函数的arr数组里面没有2这个值,所以就没有显示按钮2 当我们改变按钮2传的值为3时就会显示
<template>
  <div class="home">
    <button v-show-btn='1'>按钮1</button>
    <button v-show-btn='2'>按钮2</button>
  </div>
</template>
<script>
import showBtn from "@/directives/showBtn";//引入设置的自定义指令
export default {
  name: "HomeView",
  components: {},
  directives: {
    showBtn,//注册
  },
};
</script>

配合moack数据+vuex+接口实现自定义指令按钮权限的控制

  1. 安装axios 新建utils/http.js文件进行配置
import axios from "axios";
const https = axios.create({
  baseURL: "https://www.fastmock.site/mock/d8cbb6be1a68921dd115e83e225ccaaf/q",//moack数据的域名地址
  timeout: 1000,
});
// 添加请求拦截器
https.interceptors.request.use(
  function (config) {
    // 在发送请求之前做些什么
    return config;
  },
  function (error) {
    // 对请求错误做些什么
    return Promise.reject(error);
  }
);
// 添加响应拦截器
https.interceptors.response.use(
  function (response) {
    // 对响应数据做点什么
    let {data}=response
    return data;
  },
  function (error) {
    // 对响应错误做点什么
    return Promise.reject(error);
  }
);
export default https;
  1. 新建api/http.js文件
import https from "@/utils/http";
// 按钮权限数组
export const getArr = () => {
  return https({
    method: "get",
    url: "/btnText",
  });
};

3.store/index.js配置

import Vue from "vue";
import Vuex from "vuex";
Vue.use(Vuex);
export default new Vuex.Store({
  state: {
    arr:[1,3] //按钮权限数组
  },
  getters: {
    checkArr: (state) => (key) => {//监听变化
      let arr = state.arr;
      return arr.indexOf(key) != -1 ? true : false;
    },
  },
  mutations: {
    setArr(state,val){//修改按钮权限数组
      state.arr=val
    }
  },
  actions: {
  },
  modules: {},
});
  1. router/index.js里配置
import store from "@/store"; //引入vuex
router.beforeEach((to,from,next)=>{
  store.commit("setArr",[4,5])
  console.log(store,'store');
  next()
})
  1. 修改directives/showBtn.js文件内容,就会发现页面里没有按钮了,因为我们在router.beforeEach里面修改了值,只有传入的值是4和5的情况下才会显示按钮
import store from "@/store";//引入vuex
export default {
    inserted(el,binding){
        let val=binding.value
        let has=store.getters.checkArr(val)//调用vuex中的getters里面的方法
        if(val){
            if (!has) {
                el.parentNode&&el.parentNode.removeChild(el)
            }
        }else{
            throw new Error('error')
        }
    }
}

通过vuex异步请求接口动态修改按钮权限的值

  1. 修改store/index
import Vue from "vue";
import Vuex from "vuex";
import { getArr } from "@/api/index";
Vue.use(Vuex);
export default new Vuex.Store({
  state: {
    arr:[1,3]
  },
  getters: {
    checkArr: (state) => (key) => {
      let arr = state.arr;
      return arr.indexOf(key) != -1 ? true : false;
    },
  },
  mutations: {
    setArr(state,val){
      state.arr=val
    }
  },
  actions: {
    setArrAsync(){
      return new Promise((reslove)=>{
        getArr().then(res=>{
          reslove(res)
        })
      })
    }
  },
  modules: {},
});
  1. 修改router/index.js中的router.beforeEach 就可以实现用自定义指令动态控制按钮权限了
router.beforeEach(async (to, from, next) => {
  let reslove = await store.dispatch("setArrAsync");//调用接口
  let { code, arr } = reslove;
  if (code == 1) {
    store.commit("setArr", arr);//arr[1, 2, 5]
  }
  next();
});

优化+设置请求超时

问题:每次进入页面都会重新请求

  1. 安装element-ui,新建login.vue
  2. 新建utils/promiesUtils文件
//utils/promiesUtils.js
 const retry = (fn, data) => {
  return new Promise((reslove, reject) => {
    Promise.race([fn, timeOut(data)])
      .then((res) => {
        reslove(res);
      })
      .catch((err) => {
        reject("race 内部超时");
      });
  });
};

const timeOut = (dalay) => {
  return new Promise((reslove, reject) => {
    setTimeout(() => {
      reject(false);
    }, dalay);
  });
};

export default {
  retry
};

3.在main.js配置全局element-ui,引入并注册全局方法

import Vue from "vue";
import App from "./App.vue";
import router from "./router";
import store from "./store";

import ElementUI from "element-ui";
import "element-ui/lib/theme-chalk/index.css";
import promiesUtils from "@/utils/promiesUtils";
Vue.prototype.$promiesUtils = promiesUtils;
Vue.use(ElementUI);

Vue.config.productionTip = false;
new Vue({
  router,
  store,
  render: (h) => h(App),
}).$mount("#app");
  1. login.vue配置,配置login.vue路由 使用配置的方法设置请求超时
<template>
  <div>
    <el-button @click="doLogin">登陆</el-button>
  </div>
</template>
<script>
import { mapMutations, mapActions } from "vuex";
export default {
  methods: {
    ...mapMutations(["setArr"]),
    ...mapActions(["setArrAsync"]),
    async doLogin() {
      try {
        let btnArr = await this.$promiesUtils.retry(this.setArrAsync(), 2000);
        let { code, arr } = btnArr;
        console.log(arr);
        code == 1 && this.setArr(arr);
        this.$router.push({ path: "/" });
      } catch (error) {
        console.log(error);
      }
    },
  },
};
</script>

  1. 修改router/index.js
import Vue from "vue";
import VueRouter from "vue-router";
import HomeView from "../views/HomeView.vue";
import store from "@/store";
import  retry  from "@/utils/promiesUtils";
Vue.use(VueRouter);

const routes = [
  {
    path: "/",
    name: "home",
    component: HomeView,
  },
  {
    path: "/about",
    name: "about",
    component: () =>
      import(/* webpackChunkName: "about" */ "../views/AboutView.vue"),
  },
  {
    path: "/login",
    name: "login",
    component: () =>
      import(/* webpackChunkName: "Login" */ "../views/Login.vue"),
  },
];

const router = new VueRouter({
  mode: "history",
  base: process.env.BASE_URL,
  routes,
});
router.beforeEach(async (to, from, next) => {
  if (store.state.arr.length <= 0 && to.path !== "/login") {
    try {
      let reslove = await retry(store.dispatch("setArrAsync"), 2000);
      // let reslove = await store.dispatch("setArrAsync");
      let { code, arr } = reslove;
      console.log(reslove);
      if (code == 1) {
        store.commit("setArr", arr); //arr[1, 2, 5]
      }
    } catch (error) {
      next('/login')
    }
  }
  next();
});
export default router;