vue-element-admin 开发日志

vue-element-admin

非常推荐使用集成方案。

虽然官网推荐使用基础模板,从集成方案中按需添加功能。因为集成方案有些功能用不上,会形成冗余代码。

但是,使用基础模板,真的是非常基础,好多功能都没有,比如标签页的导航,基础模板只有面包屑导航,这时候如果想添加标签页的功能,像我这种不熟悉源码的人,真找不着该复制些什么内容过来。

所以,集成方案,冗余就冗余吧,删代码总比复制代码简单些。

之前的工作,都是站在巨人的肩膀上,框架按业务需求,都是行内大佬改造的好好的,直接拿过来用,基本上只用操心业务代码。所以,虽然没有用过这个框架,开发起来也没有难度。

现在,新的项目,从头开始,又要用这个框架,真是从github下载框架源码开始开发,所以,好多细节需要总结记录一下。

正文

登录:除用户名、密码外登录需要的参数,如验证码code

src/store/modules/user.js

login({ commit }, userInfo) {

        const { username, password, code, codeId } = userInfo

        return new Promise((resolve, reject) => {

            login({ username: username.trim(), password: password, code: code.trim(), codeId: codeId }).then(response => {

                const { data } = response

                commit('SET_TOKEN', data.token)

                setToken(data.token)

                    // commit('SET_TOKEN', data.token)

                    // setToken(data.token)

                resolve()

            }).catch(error => {

                reject(error)

            })

        })

    },

修改token

src/utils/request.js

if (store.getters.token) {

        // let each request carry token

        // ['X-Token'] is a custom headers key

        // please modify it according to the actual situation

        //config.headers['X-Token'] = getToken()

        config.headers['auth-token'] = 'userToken:' + getToken() // 让每个请求携带自定义token 请根据实际情况自行修改

 }

请求超时修改

src/utils/request.js

timeout: 10000

修改路由:路由如果不需要重定向,如登录页的忘记密码。

src/permission.js

const whiteList = ['/login', '/auth-redirect', '/forgetPwd'] // no redirect whitelist

权限路由:参考权限相关页面 permission

src/router/index.js

export const asyncRoutes = [{}];

路由在导航菜单中隐藏:hidden: true

src/router/index.js

{

        path: '/forgetPwd',

        name: 'ForgetPwd',

        component: () =>

            import ('@/views/user/forgetPwd'),

        hidden: true

    },

设置:设置默认打开菜单上方的logo显示

src/store/modules/settings.js

src/setting.js

/**

   * @type {boolean} true | false

   * @description Whether need tagsView

   */

  tagsView: true,

Property visible must be accessed with $ or _ are not proxied in the Vue instance

src/permission.js 中修改 Message.error(error) 为 Message.error(error.message)

catch (error) {

            // remove token and go to login page to re-login

            await store.dispatch('user/resetToken')

            Message.error(error.message)

            next(`/login?redirect=${to.path}`)

            NProgress.done()

}

关于权限控制,框架支持页面级别和按钮级别的权限控制。

路由中的权限控制是页面级别的。

src/router/index.js

{

    path: '/permission',

    component: Layout,

    redirect: '/permission/page',

    alwaysShow: true, // will always show the root menu

    name: 'Permission',

    meta: {

      title: 'Permission',

      icon: 'lock',

      roles: ['admin', 'editor'] // you can set roles in root nav

    },

    children: [

      {

        path: 'page',

        component: () => import('@/views/permission/page'),

        name: 'PagePermission',

        meta: {

          title: 'Page Permission',

          roles: ['admin'] // or you can only set roles in sub nav

        }

      },

      {

        path: 'directive',

        component: () => import('@/views/permission/directive'),

        name: 'DirectivePermission',

        meta: {

          title: 'Directive Permission'

          // if do not set roles, means: this page does not require permission

        }

      },

      {

        path: 'role',

        component: () => import('@/views/permission/role'),

        name: 'RolePermission',

        meta: {

          title: 'Role Permission',

          roles: ['admin']

        }

      }

    ]

  },

页面中的权限控制,是按钮级别的。

关键方法

v-if="checkPermission(['admin','editor'])"

v-permission="['admin','editor']"

前后端传参交互:关于响应码和响应消息

后端要求获取header中的status code 和 x-api-message 作为响应码和错误消息。

解码消息(base64)

decodeURIComponent(window.atob('dG9rZW4lRTQlQjglOEQlRTglODMlQkQlRTQlQjglQkElRTclQTklQkElRUYlQkMlODE='))

请求拦截器

src/utils/request.js

如下写法的问题在于,当Status Code为403或404时,使用res.status无法获取。需要在错误处理函数中,使用 error.response.status 获取。

// response interceptor

service.interceptors.response.use(

    /**

     * If you want to get http information such as headers or status

     * Please return  response => response

     */

    /**

     * Determine the request status by custom code

     * Here is just an example

     * You can also judge the status by HTTP Status Code

     */

    response => {

        //const res = response.data

        const res = response

        // if the custom code is not 200, it is judged as an error.

        // 获取响应状态Status Code信息

        if (res.status != 200) {

            Message({

                message: res.msg || '请求失败',

                type: 'error',

                duration: 5 * 1000

            })

            if (res.status == 401) {

                // to re-login

                MessageBox.confirm('登录失败,请重新登录!', '确定', {

                    confirmButtonText: '重新登录',

                    cancelButtonText: '取消',

                    type: 'warning'

                }).then(() => {

                    store.dispatch('user/resetToken').then(() => {

                        location.reload()

                    })

                })

            }

            return Promise.reject(new Error(res.msg || '请求失败'))

        } else {

            return res

        }

    },

    error => {

        Message({

            message: error.message,

            type: 'error',

            duration: 5 * 1000

        })

        return Promise.reject(error)

    }

)

拓展学习:http://www.axios-js.com/zh-cn/docs/#%E9%94%99%E8%AF%AF%E5%A4%84%E7%90%86

错误处理

axios.get('/user/12345')
  .catch(function (error) {
    if (error.response) {
      // The request was made and the server responded with a status code
      // that falls out of the range of 2xx
      console.log(error.response.data);
      console.log(error.response.status);
      console.log(error.response.headers);
    } else if (error.request) {
      // The request was made but no response was received
      // `error.request` is an instance of XMLHttpRequest in the browser and an instance of
      // http.ClientRequest in node.js
      console.log(error.request);
    } else {
      // Something happened in setting up the request that triggered an Error
      console.log('Error', error.message);
    }
    console.log(error.config);
  });

总结:还是使用常规的传参交互吧,整那些幺蛾子干啥。后来咨询了其他人,上述写法还存在功能性问题,当使用其他协议传输,有的协议没有头部消息。另外,后端返回值整体加密,消息和状态码,还是和其他返回值写一起比较方便。

{

 "code": "200",

 "msg": "成功",

 "data": [{...},{...}]

}

设置的路由,跳出框架显示。

原因是没有设置 component: Layout

src/router/index.js

{

        path: '/user',

        component: Layout,

        children: [{

            path: 'center',

            name: 'Center',

            component: () =>

                import ('@/views/user/center/index'),

                hidden: true,

            meta: { title: '个人中心' }

        }]

}

elementUI 表单重置 Cannot read property 'form' of undefined"

排除了 

表单需要有ref,formName的名字记得一致。

需要完整 el-form及 form-item 组件中 且 配置 prop,不配置的执行此方法,该输入框值不会重置。

错误原因:注意是refs,不是ref。

resetForm(formName){

      this.$refs[formName].resetFields();

}

分页组件英文显示切换为中文

最开始没意识到是语言问题,全文检索都找不到 Go to。

后来才知道是语言问题。

src/main.js

在默认设置里,采用的是英文。

直接注释,因为默认是中文。注意下面 Vue.use Element 也要注释。

//import enLang from 'element-ui/lib/locale/lang/en'// 如果使用中文语言包请默认支持,无需额外引入,请删除该依赖

Vue.use(Element, {

  size: Cookies.get('size') || 'medium', // set element-ui default size

  //locale: enLang // 如果使用中文,无需设置,请删除

})

关闭当前页

this.$store.dispatch('tagsView/delView', this.$route)

写了不生效,可能是写错了地方。比如如下示例,关闭方法错误写在了文章组件(article)中。

应用举例

文章管理列表页面(index)==(点击新增,跳转到)==》文章新增页面(add)==(子组件)==》文章组件(article)==填入内容后点击提交==》新增成功,触发父组件(add)关闭当前页并返回列表页的事件。

文章管理列表页面(index)==(点击编辑,通过路由携带文章id,跳转到)==》文章编辑页面(edit)==(子组件)==》文章组件(article)==填入内容后点击提交==》编辑成功,触发父组件(edit)关闭当前页并返回列表页的事件。

备注:

1、停留在编辑页(edit),直接点击浏览器的刷新,刷新会丢失文章id。刷新时会自动关闭其他页面,仅保留当前页。

2、新增和编辑,主要是新增,返回列表页后,列表页需要重新获取数据。列表页将页面初始化的方法写在 activated 中即可。

      activated() {

          this.getTableData()

      }

文章新增页

<template>

  <article-detail :is-edit="false" @close="closeSelectedTag" />

</template>

<script>

import ArticleDetail from './components/ArticleDetail'

export default {

  name: 'ManageModuleNewsAdd',

  components: { ArticleDetail },

  methods: {

    closeSelectedTag() {

      // 关闭当前页面

      this.$store.dispatch('tagsView/delView', this.$route)

      this.$router.push({

        name: 'ManageModuleNews'

      })

    }

  }

}

</script>

文章编辑页

<template>

  <article-detail :is-edit="true" @close="closeSelectedTag" />

</template>

<script>

import ArticleDetail from './components/ArticleDetail'

export default {

  name: 'ManageModuleNewsEdit',

  components: { ArticleDetail },

  methods: {

    closeSelectedTag() {

      // 关闭当前页面

      this.$store.dispatch('tagsView/delView', this.$route)

      this.$router.push({

        name: 'ManageModuleNews'

      })

    }

  }

}

</script>

文章组件

created() {

    if (this.isEdit) { // 编辑 isEdit=true

      const id = this.$route.params.id

      if (!id) {

        // 刷新会丢失id。刷新时会自动关闭其他页面,仅保留当前页。

        this.$message({

          message: '资讯id丢失,请关闭本页面重新进入!',

          type: 'warning'

        })

      } else {

        // 根据id查询文章详情

        this.fetchData(id)

      }

    } else {

      // 新增

      this.newsForm = this.defaultNews

      this.fileObj.fileUrl = ''

    }

  },

 methods: {

   handleSubmit() {

      if (this.isEdit) {

        this.updateNews(this.newsForm)

      } else {

        this.addNews(this.newsForm)

      }

    },

    async addNews(row) {

      const res = await addNews(row)

      if (res.code === 200) {

        this.$message({

          message: '新增成功!',

          type: 'success'

        })

        // 触发父组件 关闭当前页面 跳转列表页

        this.$emit('close')

      }

    },

    async updateNews(row) {

      const res = await updateNews(row)

      if (res.code === 200) {

        this.$message({

          message: '保存成功!',

          type: 'success'

        })

        // 触发父组件 关闭当前页面 跳转列表页

        this.$emit('close')

      }

    },

}

======

未完待续吧

猜你喜欢

转载自blog.csdn.net/Irene1991/article/details/110957592
今日推荐