个人自学前端39-Vue16-后台管理系统,登录、权限的业务逻辑,修改UI框架样式

目录

后台管理系统

后台管理系统涉及的常见功能:

1:ui框架使用。快速布局。

2:图表的使用。echarts。

3:登录功能的处理。token。

4:权限处理。异步路由。

5:国际化处理。插件。

一 UI框架

Vue的ui框架可以分为两类:

1:PC端ui框架 => element-ui,iView。

2:移动端ui框架 => Vant,Vux,mint,ant-design-vue。

一个ui框架的使用涉及的问题:

1:安装。(看官网)

2:引入。a:完全引入,b:按需引入。

​ element-ui是Vue的插件,因此引入时,需要使用use处理一次。

​ 完全引入会导致打包后体积比较大。

​ 按需引入的体积没有那么大。(按需引入好一点)

3:主题修改。

4:布局样式layout布局。

5:组件使用。(最重要)

6:图标和颜色。

​ 如何使用图标,直接class换图标名字即可。

​ 所有ui框架的图标都是字体图标。文字的体积比图片的小。

​ 不同的颜色对应不同的关键字。例如element的蓝色是primary。(所有ui通用)

二 如何看别人的项目

不是说全部代码都知道是怎么回事才可以改。

永远只关心跟自己修改功能相关的代码。不要看根自己修改功能无关的模块。

如何找到哪些模块文件是自己需要修改的?

1:先找到页面对应的标签。(内容找不到,找标签,标签找不到,找父元素) (目的是找到需要修改的组件是哪个)

2:找到标签后,通过全局查找,找到标签所在的组件。

3:找到这个组件的绑定的数据。如果数据是静态的很好处理,如果是动态的,需要顺腾摸瓜慢慢找相关模块。

找表格 => userList组件 => tableData数组 => getUserList方法 => userList.js文件 => 找到接口。

如何找到我们需要修改的页面对应的组件?

1:利用正项目中查找类名。

2:如果找路由组件,路径名就是组件名。如果找一般组件,标签的类名就是组件名。(不一定)

如何找到请求数据的逻?

先找到数据对应的组件,再去组件内顺腾摸瓜找到数据的来源。

三 登录的业务逻辑

1:什么是token

token是一个字符串。它携带了用户的相关信息。例如权限信息,账号密码等等。

token是用来实现用户验证的。

什么是用户验证?

http协议是一种无状态的协议。无状态 => 无记忆.

前端后端通信结束之后,如果发起新的请求,后端是无法知道当前的客户端是不是之前通信过的客户端。

如果不做额外的处理,我们是无法实现保留登录状态的功能的。

用户验证就是为了让后端记住前端。用什么记住?用token字符串进行记忆。

token如何获取?

登录成功后,后端会发生token给前端。

如何保存token?

token需要通过本地存储或者cookie存储到浏览器中。方便随时获取发送给服务器。

token需要每次请求时都要发送给后端。如何发送?

一般会把token写在header内(请求头),因为head内的信息会默认每次都发送给服务器。

在header内配置一个 Authorizaion:token 20603038ce66e6abfd1182d3a68307929f7fdb40。

如何判断token是不是过期了?

通过后端返回的数据判断,例如:code是100表示过期了。是0表示没过期。

如果token过期了,需要请求特定接口获取新的token再存起来。

2:项目的登录逻辑需要做的事情

a:发起登录成功之后,把token存储到cookie或者本地存储。(在哪里写存储的代码不固定)

b:路由守卫中判断是否登录成功过。(判断cookie或者本地存储内有没有token)

c:需要随时保证token是最新的。要在响应拦截里判断token是否过期了。(通过服务器返回的字段判断)

d:需要把登录成功之后获取的用户数据,存储到vuex中。

  <script>
  // 如何通过token判断用户是不是已经登录过?
  // 首先判断本地存储或者cookie中是不是已经有了对应token.
  // 如果有token,继续判断token是不是过期了.

  // 请求拦截 => 所有的请求发生之前,都会触发use的回调.
  // use的回调的参数config是axios请求的配置项.
  // 通过config,可以在所有请求发生前,修改config.
  // 一定记得return config,否则请求默认会失败.
  axios.interceptors.request.use(function (config) {
    // 给所有的请求都添加token字段.
    config.headers.Authorizaion = localStorage.getItem('token');
    // 在发送请求之前做些什么
    return config;
  }, function (error) {
    // 对请求错误做些什么
    return Promise.reject(error);
  });

  // 响应拦截.每次数据请求拿到数据之前都会触发响应拦截
  // res参数就是服务器返回的结果.
  // 需要把res return出去.否则then接收不到服务器返回的结果.
  axios.interceptors.response.use(function (res) {
    // console.log('res', res);
    res.data.msg = '修改哟哟哟哟成功了';
    // 在拿到数据之前做些什么
    return res;
  }, function (error) {
    // 对请求错误做些什么
    return Promise.reject(error);
  });

    const Login = {
      template: `
        <div>
          <input type='text' />
          <button @click='toPage'>登录</button>
        </div>
      `,
      props: ['name'],
      methods: {
        toPage() {
          axios.get('data.json').then(res => {
            if (res.data.code === 0) {
              // 获取token并且存储到本地。
              localStorage.setItem('token', res.data.token);
              // 跳转到指定路由.
              this.$router.push({ name: this.name });
            }
          });
        }
      }
    }
    const Home = {
      template: `
        <div>
          <slot />
          <h3>首页</h3>
        </div>
      `,
    }
    const News = {
      template: `
        <div>
          <slot />
          <h3>新闻</h3>
          <button @click='fn'>修改用户信息</button>
        </div>
      `,
      methods: {
        fn() {
          axios({
            url: 'editor.json',
            methods: "GET",
            data: "新修改的用户名",
            // 每次请求,都手动发送token.
            // headers: { Authorizaion: localStorage.getItem('token') },
          }).then(res => {
            console.log(res);
          })
        }
      }
    }
    const Sport = {
      template: `
        <div>
          <slot />
          <h3>体育</h3>
          <button @click='fn'>修改用户头像</button>
        </div>
      `,
      methods: {
        fn() {
          axios({
            url: '头像接口',
            methods: "POST",
            data: "新修改的头像",
            // 每次请求,都手动发送token.
            headers: { Authorizaion: localStorage.getItem('token') },
          }).then(res => {
            console.log(res);
          })
        }
      }
    }
    // 实例化路由
    const router = new VueRouter({
      // 路由组件和路由路径的对应关系 => 路由选项
      routes: [
        {
          path: '/home',
          component: Home,
          name: 'home',
          meta: {
            // 不需要登录
            authLogin: false
          }
        }, {
          path: '/news',
          component: News,
          name: 'news',
          meta: {
            authLogin: true
          }
        }, {
          path: '/sport',
          component: Sport,
          name: 'sport',
          meta: {
            authLogin: true
          }
        }, {
          path: '/login',
          component: Login,
          name: 'login',
          meta: {
            authLogin: false
          },
          props: true
        },{
          path: '/',
          redirect: '/home'
        }
      ]
    });
    // 全局守卫处理 登录逻辑
    router.beforeEach((to, from, next) => {
      if (to.meta.authLogin) {
        const token = localStorage.getItem('token');
        if (token === null) {
          // 重定向,并且传递目标路由的name
          next({ name: 'login', params: { name: to.name } })
        } else {
          // if (token过期了) {
          //    next({ name: 'login', params: { name: to.name } })
          // } else {
          //    next()
          // }
          next();
        }
      } else {
        next()
      }
    });
    const App = {
      template: `
        <div>
          <router-view>
            <router-link to='/home'>首页</router-link>
            <router-link to='/news'>新闻</router-link>
            <router-link to='/sport'>体育</router-link>
          </router-view>
        </div>
      `
    };
    new Vue({
      render: h => h(App),
      // 挂载路由
      router
    }).$mount('#app');
  </script>

四 权限

权限 => 页面的权限(需要异步路由),按钮的权限(v-if或者自定义指令实现),请求数据的权限(请求拦截内实现)。

代码内,权限是存储在用户信息内的一个数组. => 怎么知道登录之后的账号权限? => 用户的登录信息内获取.

=> 根据用户登录的权限信息,动态配置不同的routes数组到路由实例内。

=> 如何动态设置不同页面的路由?=> router.addRoutes

一般需要权限的项目,配置路由时,路由选项需要分成两个部分。

一个部分是不需要权限的路由,例如登录路由和404路由。

另一个部分是需要权限的路由。

在登录成功后,获取到的用户的权限列表,再通过权限列表从需要权限的路由内筛选出需要的路由。

最后把不需要权限的路由和经过筛选的路由合并,再通过addRoutes动态配置。

  <script>
    const Login = {
      template: `
        <div>
          <input type='text' />
          <button @click='toPage'>登录</button>
        </div>
      `,
      props: ['name'],
      methods: {
        toPage() {
          axios.get('userData.json').then(res => {
            // 权限角色
            let role = res.data.role;
            // 根据权限过滤路由。
            asyncRoutes = asyncRoutes.filter(item => item.meta.roles.includes(role));
            // 过滤后配置动态路由.
            router.addRoutes(asyncRoutes);
            // 跳转到首页.
            this.$router.push('/home');
          });
        }
      }
    }
    const Home = {
      template: `
        <div>
          <slot />
          <h3>首页</h3>
        </div>
      `,
    }
    const News = {
      template: `
        <div>
          <slot />
          <h3>新闻</h3>
        </div>
      `
    }
    const Sport = {
      template: `
        <div>
          <slot />
          <h3>体育</h3>
        </div>
      `,
    }
    const NotFound = {
      template: `
        <div>
          <h3>404页面,你要访问的页面不存在</h3>
        </div>
      `,
    }
    // 不需要权限的路由选项.
    const staticRoutes = [
      {
        path: '/login',
        component: Login,
        name: 'login'
      }, {
        path: '/notFound',
        component: NotFound
      }, {
        path: '/',
        redirect: '/login'
      }
    ];
    // 需要权限的路由选项.
    let asyncRoutes = [
      {
        path: '/home',
        component: Home,
        name: 'home',
        meta: {
          roles: ['editor', 'admin']
        }
      }, {
        path: '/news',
        component: News,
        name: 'news',
        meta: {
          roles: ['admin']
        }
      }, {
        path: '/sport',
        component: Sport,
        name: 'sport',
        meta: {
          roles: ['editor']
        }
      },
    ];
    // 实例化路由,只配置不要权限的路由。
    // 其他页面的路由选项,需要在登录之后,根据不同的用户角色来动态配置.
    const router = new VueRouter({ routes: staticRoutes });
    const App = {
      template: `
        <div>
          <router-view>
            <router-link to='/home'>首页</router-link>
            <router-link to='/news'>新闻</router-link>
            <router-link to='/sport'>体育</router-link>
          </router-view>
        </div>
      `
    };
    new Vue({
      render: h => h(App),
      // 挂载路由
      router
    }).$mount('#app');
  </script>

五 模拟数据

1:最简单最笨的就是写json文件,自己请求。(简单情况可以这样做)

2:使用mock模拟数据。mock是一个插件。

六 修改UI框架的样式

如果ui框架的样式需要修改,有以下几种方式。

一,通过浏览器检查,找到要修改的标签的类名,然后再组件中写一个优先级更高的选择器个覆盖ui的默认样式。

二,通过组件style的scoped来覆盖修改。添加了scoped之后,还希望父组件的样式影响子组件,还需要使用样式穿透。

样式穿透的三种写法:

1. /deep/
2. >>>
3. ::v-deep

三,永远的全部修改,只能改源码。也可以使用定制主题的方式修改,源文件不会被修改。

不管是修改源码还是定制主题的方式,会对整个项目的组件都生效。

修改主题时,建议less-loader的版本是5.0.0.

上一篇:剑指 Offer 39. 数组中出现次数超过一半的数字


下一篇:网络子系统15_arp邻居项初始化