この一連の記事はステップバイステップのチュートリアルではなく、主にコアのアイデアを紹介し、コアのコードを説明します。GitHub で完全なコードにスターを付けて複製することができます。さらに、当初はプロジェクトを実行して友人が閲覧できるようにオンラインに公開する予定でしたが、サーバーを購入する前に費用を節約するために、メモリが 512M しかなく、2 つのアプリケーションを実行できませんでした (すでに V Tribe が存在します)。オープン ソース プロジェクトが実行されているため、以下のスクリーンショットを参照することしかできません。GitHub にデプロイメント チュートリアルがあり、ローカルにデプロイして完全な効果を確認することもできます。
プロジェクトアドレス: https://github.com/lenve/vhr
これまでの記事で、基本的にサーバー側の問題を解決し、フロントエンドリクエストをカプセル化しました。主にログインとコンポーネントの動的読み込みについて説明します。
この記事はこのシリーズの 5 番目です。この記事をよりよく理解するには、最初に以前の記事を読むことをお勧めします。
1. SpringBoot+Vue はフロントエンドとバックエンドを分離し、Spring Security を使用します。パーミッションの問題を完全に処理する (1)
2.SpringBoot+Vue は、SpringSecurity を使用してフロントエンドとバックエンドを分離し、パーミッションの問題を完全に処理する (2)
3. SpringSecurity でのパスワードソルティングと SpringBoot での統合例外処理
4.axios リクエストのカプセル化統合された例外処理
ユーザーが正常にログインした後、現在のユーザーのログイン情報を後で使用できるようにローカルに保存する必要があります。具体的な実装は次のとおりです。
ログイン操作が正常に実行された後、データはコミット操作を通じてストアに送信されます。 コア コードは次のとおりです。
<span style="font-size: 14px;">this.postRequest('/login', {<br> username: this.loginForm.username,<br> password: this.loginForm.password<br>}).then(resp=> {<br> if (resp && resp.status == 200) {<br> var data = resp.data;<br> _this.$store.commit('login', data.msg);<br> var path = _this.$route.query.redirect;<br> _this.$router.replace({path: path == '/' || path == undefined ? '/home' : path});<br> }<br>});<br></span>
ストアの中核 コードは次のとおりです:
<span style="font-size: 14px;">export default new Vuex.Store({<br> state: {<br> user: {<br> name: window.localStorage.getItem('user' || '[]') == null ? '未登录' : JSON.parse(window.localStorage.getItem('user' || '[]')).name,<br> userface: window.localStorage.getItem('user' || '[]') == null ? '' : JSON.parse(window.localStorage.getItem('user' || '[]')).userface<br> }<br> },<br> mutations: {<br> login(state, user){<br> state.user = user;<br> window.localStorage.setItem('user', JSON.stringify(user));<br> },<br> logout(state){<br> window.localStorage.removeItem('user');<br> }<br> }<br>});<br></span>
トラブルを軽減するため、ユーザーがログインに成功した後のデータはlocalStorageに保存されます(ユーザーがログインした後のデータの損失を防ぐため) F5 を押して更新します)、文字列の形式で保存され、取得時に json に変換されます。ユーザーがログアウトすると、localStorage 内のデータが消去されます。
権限管理モジュールでは、これはフロントエンドのコアとみなされます。
ユーザーが正常にログインした後、ホームページに入る前に、現在のメニュー情報とコンポーネント情報を取得するリクエストをサーバーに送信します。対応するリソースは、次のような json 文字列を返します。 format:
<span style="font-size: 14px;">[<br> {<br> "id": 2,<br> "path": "/home",<br> "component": "Home",<br> "name": "员工资料",<br> "iconCls": "fa fa-user-circle-o",<br> "children": [<br> {<br> "id": null,<br> "path": "/emp/basic",<br> "component": "EmpBasic",<br> "name": "基本资料",<br> "iconCls": null,<br> "children": [],<br> "meta": {<br> "keepAlive": false,<br> "requireAuth": true<br> }<br> },<br> {<br> "id": null,<br> "path": "/emp/adv",<br> "component": "EmpAdv",<br> "name": "高级资料",<br> "iconCls": null,<br> "children": [],<br> "meta": {<br> "keepAlive": false,<br> "requireAuth": true<br> }<br> }<br> ],<br> "meta": {<br> "keepAlive": false,<br> "requireAuth": true<br> }<br> }<br>]<br></span>
この文字列を取得した後、フロントエンドは次の 2 つのことを行います: 1. json を現在のルートに動的に追加します。 2. データをストアに保存し、各ページがそのデータに基づいてメニューをレンダリングします。店舗。
中心となるアイデアは難しくありません。実装手順を見てみましょう。
これは非常に重要です。
友達の中には、なぜこれがそんなに難しいのかと尋ねるかもしれませんが、ログインに成功した後にリクエストすることはできないでしょうか?はい、ログインに成功した後にメニュー リソースをリクエストすることは可能です。リクエストを受信すると、次回使用するためにストアに保存されますが、ユーザーが成功後に特定のサブ子をクリックすると、別の問題が発生します。ログインし、ページに入り、サブページに入り、F5 を押して更新します。この時点では、F5 を更新するとストア内のデータが失われ、ログイン時にメニュー リソースを 1 回要求しただけであるため、GG です。この問題を解決するには、次の 2 つの方法があります。 1. メニュー リソースをストアに保存せず、localStorage に保存して、F5 キーを更新した後でもデータが残るようにします。 2. マウントされたメソッドに直接保存します。各ページで、「メニュー リソースの読み込み」を 1 回実行します。
メニューリソースは非常に機密性が高いため、ローカルに保存しないことが最善であるため、オプション1は放棄されましたが、オプション2は少し重い作業であるため、私が採用した方法は次のとおりです。ルートでナビゲーション ガードを使用します。
私の具体的な実装は次のとおりです。まず、ストア内に空の配列であるルート配列を作成し、次のようにルート グローバル ガードを有効にします。ここのコード 非常に短いので簡単に説明します: 1. 行きたいページがログインページの場合は、何も言うことはありません。直接アクセスしてください。
2.如果不是登录页面的话,我先从store中获取当前的登录状态,如果未登录,则通过路由中meta属性的requireAuth属性判断要去的页面是否需要登录,如果需要登录,则跳回登录页面,同时将要去的页面的path作为参数传给登录页面,以便在登录成功之后跳转到目标页面,如果不需要登录,则直接过(事实上,本项目中只有Login页面不需要登录);如果已经登录了,则先初始化菜单,再跳转。
初始化菜单的操作如下:
<span style="font-size: 14px;">export const initMenu = (router, store)=> {<br> if (store.state.routes.length > 0) {<br> return;<br> }<br> getRequest("/config/sysmenu").then(resp=> {<br> if (resp && resp.status == 200) {<br> var fmtRoutes = formatRoutes(resp.data);<br> router.addRoutes(fmtRoutes);<br> store.commit('initMenu', fmtRoutes);<br> }<br> })<br>}<br>export const formatRoutes = (routes)=> {<br> let fmRoutes = [];<br> routes.forEach(router=> {<br> let {<br> path,<br> component,<br> name,<br> meta,<br> iconCls,<br> children<br> } = router;<br> if (children && children instanceof Array) {<br> children = formatRoutes(children);<br> }<br> let fmRouter = {<br> path: path,<br> component(resolve){<br> if (component.startsWith("Home")) {<br> require(['../components/' + component + '.vue'], resolve)<br> } else if (component.startsWith("Emp")) {<br> require(['../components/emp/' + component + '.vue'], resolve)<br> } else if (component.startsWith("Per")) {<br> require(['../components/personnel/' + component + '.vue'], resolve)<br> } else if (component.startsWith("Sal")) {<br> require(['../components/salary/' + component + '.vue'], resolve)<br> } else if (component.startsWith("Sta")) {<br> require(['../components/statistics/' + component + '.vue'], resolve)<br> } else if (component.startsWith("Sys")) {<br> require(['../components/system/' + component + '.vue'], resolve)<br> }<br> },<br> name: name,<br> iconCls: iconCls,<br> meta: meta,<br> children: children<br> };<br> fmRoutes.push(fmRouter);<br> })<br> return fmRoutes;<br>}<br></span>
在初始化菜单中,首先判断store中的数据是否存在,如果存在,说明这次跳转是正常的跳转,而不是用户按F5或者直接在地址栏输入某个地址进入的。否则就去加载菜单。拿到菜单之后,首先通过formatRoutes方法将服务器返回的json转为router需要的格式,这里主要是转component,因为服务端返回的component是一个字符串,而router中需要的却是一个组件,因此我们在formatRoutes方法中动态的加载需要的组件即可。数据格式准备成功之后,一方面将数据存到store中,另一方面利用路由中的addRoutes方法将之动态添加到路由中。
最后,在Home页中,从store中获取菜单json,渲染成菜单即可,相关代码可以在<span style="font-size: 14px;">Home.vue</span>
中查看,不赘述。
OK,如此之后,不同用户登录成功之后就可以看到不同的菜单了。
相关推荐:
以上が権限管理モジュールでの Vue コンポーネント インスタンスの動的ロードの詳細な説明の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。