【Vue.js + Element UI】实现树形控件、分页显示与动态加载菜单

树形控件:

<!--
        显示菜单数据
        树形控件
        data 要显示的数据
        show-checkbox  是否显示checkbox框数据
        node-key: node的key 对应的菜单数据的编号
        props 节点配置 {children(下级节点): '菜单数据中对应的下级名称', label(节点显示的名称): '菜单数据中的标题'}
        default-expand-all 是否展开所有的节点
      -->
      <el-tree
        ref="tree"
        :data="menuList"
        node-key="id"
        show-checkbox
        default-expand-all
        :props="{children: 'children', label: 'title'}"
      >
添加表单自定义验证
data () {
    const checkMenus = (rule, value, callback) => {
      // 获取树形控件的选择的节点
      // this.$refs.tree.getCheckedKeys() 获取选中的节点的key
      // this.$refs.tree.getHalfCheckedKeys() 获取半选中的节点的key
      const selectMenus = [...this.$refs.tree.getCheckedKeys(), ...this.$refs.tree.getHalfCheckedKeys()]
      if (selectMenus.length === 0) {
        this.form.menus = '' // 还原表单数据中的菜单
        // 没有选择任何的菜单
        callback(new Error('请选择权限'))
      } else {
        this.form.menus = selectMenus // 把选择的权限赋值给表单数据
        callback()
      }
    }
    return {
      title: '', // 对话框的标题
      dialogFormVisible: true, // 是否显示对话框
      form: {...defaultData}, // 复制一份默认数据
      rules: {
        rolename: [
          { required: true, message: '请输入角色名称', trigger: 'blur' }
        ],
        menus: [
          { validator: checkMenus, trigger: 'change' }
        ]
      }
    }
  },

角色管理:

编写页面布局->写添加页面的界面(选择对话框组件和合适的表单组件,处理表单的验证)->编写接口文件(添加功能)->编写对应的vuex模块(获取数据)->编写接口文件(获取数据)->显示数据(使用合适的表格组件)->编写修改的功能(界面和添加一样)->编辑接口文件(修改功能)->做删除->编辑接口文件(删除功能)

编辑时给表单赋值:
// 修改的时候设置表单数据
    setFormData (data) {
      this.form = {...data}
      // 给树形控件赋值
      // data.menus '1,2,3'
      const keys = data.menus.split(',')
      this.checkStrictly = true // 在渲染树形组件之前关闭父子节点的联动选择
      this.$nextTick(() => {
        // 将回调延迟到下次 DOM 更新循环之后执行。在本次dom完全渲染之后触发
        this.$refs.tree.setCheckedKeys(keys) // 参数必须是数组
        this.checkStrictly = false // 在赋值之后开启父子节点的联动选择
      })
    }
角色的接口文件
// /api/role.js
import http from './http'

// 添加角色
export const addRole = (data) => {
  return http.post('/roleadd', data)
}

// 修改角色
export const updateRole = (data) => {
  // 判断data中是否包含id属性且大于0
  if (!Reflect.has(data, 'id') || data.id <= 0) {
    return Promise.reject(new Error('缺少ID参数或id参数错误'))
  }
  return http.post('/roleedit', data)
}

// 获取角色列表
export const getRoleList = () => {
  return http.get('/rolelist')
}

// 删除菜单
export const deleteRole = (id) => {
  return http.post('/roledelete', { id })
}

管理员管理

表单验证
data () {
    // 自定义验证规则
    // value就是要验证的表单项的值
    // callback: function 输出验证的信息
    //   验证通过调用callback() 验证没有通过调用callback(Error对象)
    const checkRole = (rule, value, callback) => {
      // 如果值不为0代表通过
      // 是菜单的时候链接就必填
      if (value === 0) {
        callback(new Error('请选择角色'))
      } else {
        callback()
      }
    }
    const checkPassword = (rule, value, callback) => {
      // 添加时必填,修改时可以不填
      if (this.form.id > 0) {
        callback()
      } else {
        if (value === '') {
          callback(new Error('请输入密码'))
        } else {
          callback()
        }
      }
    }
    return {
      dialogFormVisible: false,
      title: '', // 对话框的标题
      form: {...defaultData}, // 复制一份默认数据
      rules: {
        // 0也代表已填
        // 如果没有使用自定义验证,那规则的属性就必须在表单的数据中存在
        roleid: [
          { validator: checkRole, trigger: 'change' }
        ],
        username: [
          { required: true, message: '请输入账号', trigger: 'blur' }
        ],
        password: [
          { validator: checkPassword, trigger: 'blur' }
        ]
      }
    }
  },
分页显示管理员
管理员的数据接口
import http from './http'

// 登录
export const login = (username, password) => {
  if (!username || !password) {
    return Promise.reject(new Error('账号或密码为空'))
  }

  return http.post('/userlogin', {
    username,
    password
  })
}

// 添加管理员
export const addUser = (data) => {
  return http.post('/useradd', data)
}

// 删除管理员
export const deleteUser = (uid) => {
  return http.post('/userdelete', { uid })
}

// 修改管理员
export const updateUser = (data) => {
  // 判断data中是否包含id属性且大于0
  if (!Reflect.has(data, 'id') || data.id <= 0) {
    return Promise.reject(new Error('缺少ID参数或id参数错误'))
  }
  return http.post('/useredit', data)
}

/*
  @ 分页获取管理员数据
  @param page number 当前的页码
  @param size number 每页获取的数量
  @return Promise
*/
export const getPageUser = (page = 1, size = 10) => {
  return http.get('/userlist', {
    params: {
      page,
      size
    }
  })
}

// 获取管理员总数量
export const getUserTotal = () => {
  return http.get('/usercount')
}

vuex的管理员模块
// 导入会员的接口文件(分页获取)
import { getPageUser, getUserTotal } from '@/api/user'
export default {
  namespaced: true,
  state: {
    list: [],
    page: 1, // 当前的页码
    size: 10, // 每页获取的数据
    total: 0 // 管理员总数量
  },
  mutations: {
    SET_LIST (state, list) {
      state.list = list
    },
    SET_TOTAL (state, total) {
      state.total = total
    },
    SET_PAGE (state, page) {
      state.page = page
    }
  },
  actions: {
    getUserList ({ commit, state }) {
      getPageUser(state.page, state.size).then(res => {
        commit('SET_LIST', res)
      })
    },
    getUserTotal ({ commit }) {
      getUserTotal().then(res => {
        commit('SET_TOTAL', res[0].total || 0)
      })
    }
  }
}
分页组件
<!--
  分页组件
  layout 组件布局,子组件名用逗号分隔 sizes, prev, pager, next, jumper, ->, total, slot
  total: 总数量
  page-size: 每页的数量
  @current-change 当前页码发生改变时触发

  至少有2页时才显示分页组件
-->
<el-pagination
  @current-change="onCurrentChange"
  class="page-container"
  :page-size="size"
  background
  layout="prev, pager, next"
  :total="total"
  v-if="total > size"
>
</el-pagination>
删除时修改页码
this.$message.success({
    message: '删除成功',
    onClose: () => {
        // 重新获取总数量
        this.$store.dispatch('user/getUserTotal')
        // 如果当前页的数据已经全部删除,就修改page
        // 刷新列表数据之前,要删除的数据还没有变化
        if (this.list.length === 1) {
            let page = 0
            if (this.page === 1) {
                page = 1
            } else {
                page = this.page - 1
            }
            this.$store.commit('user/SET_PAGE', page)
        }
        // 刷新列表数据
        this.$store.dispatch('user/getUserList')
    }
})
菜单生成

在主页面的Menu组件中获取登录用户的菜单并生成菜单html

<template>
<el-menu
  router
  :default-active="$route.path"
  background-color="#545c64"
  text-color="#fff"
  active-text-color="#ffd04b">
  <!--没有下级菜单的菜单项-->
  <el-menu-item index="/statistics">
    <i class="el-icon-s-home"></i>
    <span slot="title">首页</span>
  </el-menu-item>
  <template v-for="(menu,index) of menuList">
    <!--有下级菜单-->
    <el-submenu :index="'1' + index" :key="menu.id"  v-if="menu.children && menu.children.length > 0">
      <!--一级菜单的名称-->
      <template slot="title">
        <i v-if="menu.icon !== ''" :class="menu.icon"></i>
        <span>{{menu.title}}</span>
      </template>
      <!--二级菜单项-->
      <el-menu-item-group>
        <el-menu-item v-for="item of menu.children" :key="item.id" :index="item.url">
          <i v-if="item.icon !== ''" :class="item.icon"></i>
          <span slot="title">{{item.title}}</span>
        </el-menu-item>
      </el-menu-item-group>
    </el-submenu>
    <el-menu-item :index="menu.url" v-else :key="menu.id">
      <i class="el-icon-s-home"></i>
      <span slot="title">首页</span>
    </el-menu-item>
  </template>
</el-menu>
</template>

<script>
export default {
  data () {
    return {
      menuList: []
    }
  },
  mounted () {
    const userInfo = JSON.parse(sessionStorage.getItem('user'))
    this.menuList = userInfo.menus || []
    console.log(userInfo)
  }
}
</script>
添加导航守卫阻止用户访问没有权限的页面
// 拦截
router.beforeEach((to, from, next) => {
  // 设置页面标题
  document.title = to.meta.title || '小U商城后台管理系统'

  // 如果要跳转的页面不是登录页面,就必要要登录成功之后才能访问
  if (to.path === '/login') {
    // 要跳转就是登录页面,不做拦截
    next()
  } else {
    // 要跳转不是登录页面,就必要要登录成功之后才能访问
    let userInfo = sessionStorage.getItem('user')
    if (!userInfo) {
      // 没有登录
      next('/login')
    } else {
      // 判断登录用户是否拥有对应的权限
      userInfo = JSON.parse(userInfo)
      // 首页是所有的用户都能访问
      userInfo.menus_url.push('/', '/statistics')
      if (userInfo.menus_url.includes(to.path)) { // userInfo.menus_url就是当前登录用户能够访问路由的path数组
        next()
      } else {
        // 没有权限访问就自动跳转到首页
        next('/')
      }
    }
  }
})
  • 2
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值