>웹 프론트엔드 >JS 튜토리얼 >권한 관리 모듈에서 Vue 구성 요소 인스턴스를 동적으로 로드하는 방법에 대한 자세한 설명

권한 관리 모듈에서 Vue 구성 요소 인스턴스를 동적으로 로드하는 방법에 대한 자세한 설명

小云云
小云云원래의
2018-01-16 17:09:312093검색

이 시리즈 기사는 단계별 튜토리얼이 아닙니다. 주로 핵심 아이디어를 소개하고 핵심 코드를 설명합니다. 친구들은 GitHub에서 전체 코드를 별표 표시하고 복제하여 공부할 수 있습니다. 그리고 원래는 프로젝트를 실행해서 친구들이 볼 수 있도록 온라인에 올릴 생각이었는데, 서버를 사기 전에 돈을 아끼기 위해 메모리가 512M에 불과했고, 두 개의 애플리케이션을 실행할 수 없었습니다(이미 V Tribe가 있습니다). 오픈 소스 프로젝트 실행 중)이므로 아래 스크린샷만 볼 수 있습니다. GitHub에 배포 튜토리얼이 있으므로 전체 효과를 확인할 수도 있습니다.


프로젝트 주소: https://github.com/lenve/vhr

이전 글에서는 기본적으로 서버 측 문제를 해결하고 프런트 엔드 요청을 캡슐화했습니다. 주로 로그인과 구성 요소의 동적 로딩에 대해 설명합니다.

이 기사는 이 시리즈의 다섯 번째 기사입니다. 이 기사를 더 잘 이해하려면 이전 기사를 먼저 읽어 보는 것이 좋습니다.

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>

store

스토어의 핵심 코드는 다음과 같습니다.

<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 문자열을 반환합니다. 다음 형식:

<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>

이 문자열을 얻은 후 프런트 엔드는 두 가지 작업을 수행합니다. 1. 현재 경로에 json을 동적으로 추가합니다. 2. 데이터를 스토어에 저장한 다음 각 페이지는 데이터를 기반으로 메뉴를 렌더링합니다. 가게에서.

핵심 아이디어는 어렵지 않습니다. 구현 단계를 살펴보겠습니다.

데이터 요청 타이밍

이것은 매우 중요합니다.

왜 이렇게 어려운지 물어보는 친구들도 있는데, 로그인 성공 후 바로 요청하면 안되나요? 예, 로그인 성공 후 메뉴 리소스를 요청할 수 있습니다. 요청을 받은 후 다음 번 사용을 위해 스토어에 저장하지만, 사용자가 성공한 후 특정 하위 항목을 클릭하면 또 다른 문제가 발생합니다. 로그인 후 페이지에 진입 후 F5를 눌러 새로고침을 하면 이때는 GG인데, F5를 새로고침하면 스토어의 데이터가 사라지고, 로그인시 메뉴 리소스를 한 번만 요청했기 때문입니다. 이 문제를 해결하기 위한 두 가지 아이디어가 있습니다. 1. 메뉴 리소스를 저장소에 저장하지 말고, F5를 새로 고친 후에도 데이터가 그대로 유지되도록 localStorage에 저장합니다. 2. 마운트된 메서드에서 직접; 각 페이지에서 메뉴 리소스 로드로 이동하세요.

메뉴 리소스는 매우 민감하기 때문에 로컬에 저장하지 않는 것이 가장 좋기 때문에 옵션 1은 포기하지만, 옵션 2는 작업량이 좀 많아서 단순화하는 방법을 채택했습니다. 경로에 내비게이션 가드를 사용하는 것입니다.

Route Navigation Guard

내 구체적인 구현은 다음과 같습니다. 먼저 저장소에 빈 배열인 경로 배열을 만든 다음 다음과 같이 경로 전역 가드를 켭니다.

<span style="font-size: 14px;">router.beforeEach((to, from, next)=> {<br>    if (to.name == 'Login') {<br>      next();<br>      return;<br>    }<br>    var name = store.state.user.name;<br>    if (name == '未登录') {<br>      if (to.meta.requireAuth || to.name == null) {<br>        next({path: '/', query: {redirect: to.path}})<br>      } else {<br>        next();<br>      }<br>    } else {<br>      initMenu(router, store);<br>      next();<br>    }<br>  }<br>)<br></span>

여기 코드는 매우 짧습니다. 간단히 설명하겠습니다.
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组件之Alert详解

jquery加载单文件vue组件方法分享

实例详解vue组件父子间通信之聊天室


위 내용은 권한 관리 모듈에서 Vue 구성 요소 인스턴스를 동적으로 로드하는 방법에 대한 자세한 설명의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

성명:
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.