個人自學前端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.


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM