Vue项目实战(布局、子组件、数据绑定、动态路由)[5]

603 阅读6分钟

权限管理

  • 权限管理是后台管理系统的核⼼功能,要给不同⼯作岗位的⽤户分配不同的操作权限,就需要进⾏权限管理。
  • 权限管理内部⼜划分为以下⼏个部分:菜单权限、资源权限、⻆⾊。

菜单权限

控制登录到后台的用户能访问到哪些后台菜单页面,如负责课程的人员只能看到课程管理,负责广告的人员只能看到广告管理,就需要进行不同的菜单权限分配。

资源权限

  • 资源对应的就是接口,资源权限用于控制用户能操作哪些接口功能,例如分配资源权限时没有🈲用用户权限,指的是没有操作这个接口的权限。
  • 资源权限与菜单权限不冲突,例如有的用户能看到用户管理页面,也可以添加用户(有权限操作新增用户接口),但无法进行禁用用户操作(无禁用用户的接口权限)

角色

  • 代表了菜单权限和资源权限的一种组合方式,例如设置多个用户需要相同的菜单权限与资源权限,就可以将这些权限组合起来,设置为:角色,再将角色分配给用户以简化操作。
  • 所以在项目中,不会直接对某个用户进行菜单权限和资源权限的分配,而是提前根据岗位清空设定不同的角色,再将角色分配给用户。

功能关系

  • 用户需要分配角色,角色需要分配菜单权限和资源权限。
  • 由于功能之间存在依赖,因此先从菜单权限与资源权限功能开始制作,后面再依次完成角色与用户功能。

添加菜单布局与数据绑定

  • 使用form表单,进行布局
  • Postman测试接口,数据传递成功后,复制到项目中进行运行
  • 注意
<!-- 此处的 :label 的值,会随着用户的选择动态的传递给form.shown -->
<el-form-item label="是否显示">
  <el-radio-group v-model="form.shown">
    <el-radio :label="true"></el-radio>
    <el-radio :label="false"></el-radio>
  </el-radio-group>
</el-form-item>
  • 提交表单(先验证数据,再提交表单
    • 封装请求在serives/menu.js文件中
    • utils/request.js是全局都可以使用的请求文件

上级菜单处理

  • 上级菜单需要请求真实的数据
  • 分析:上级菜单数据需要请求接口得到,并渲染在模板中
  • 用于获取菜单的接口有两个,获取所有菜单和获取编辑菜单页面信息。观察功能示例发现菜单只有一级和二级。而二级菜单无法作为“上一级菜单”使用,所以这里使用第二个接口进行操作。
  • 注解
// parentId=-1 表示当前为一级菜单,没有上级菜单
// parentId = 1 表示当前为二级菜单,上级菜单为一级菜单

添加菜单中的显示上级菜单功能

  • 主要看

权限管理-添加菜单中的上级菜单请求.png

  • 因此这里新增菜单功能中的id可以传入-1,重要的不是获取新增菜单本身的信息,而是在于获取所有上一级菜单页面信息parentMenuList
  • parentMenuList字段信息,内部的每个元素均为⼀级菜单,元素如具有subMenuList 则说明存在⼦菜单(⼆级菜单)。

编辑菜单中的显示上级菜单功能

  • 主要看

权限管理-编辑菜单中的上级菜单请求.png

  • 因此这里需要注重的是查看当前编辑菜单的信息,在menuInfo中获取其上级菜单id,再进行显示。

展示菜单列表

  • 区别开:菜单整体用的是card卡片组件,而下方用的是table表格组件
  • 注意:每次接收请求后,都要判断“处理结果code”是否正确,再将数据进行赋值

菜单删除

  • 无法删除默认的菜单
  • 功能分析:记录当前内容的id,在后台数据库中删除,需要请求接口
  • 注意两种参数书写方式

菜单管理-地址问题.png

编辑菜单

  • 通过观察发现,添加菜单和编辑菜单的组件结构几乎相同,可以封装为create-or-edit.vue组件进行使用
    • 1.引入子组件import CreateOrEdit from './components/create-or-edit'
    • 2.注册子组件
      export default {
        name: 'MenuEdit',
        components: {
          // 2.注册子组件
          CreateOrEdit
        }
      }
      
    • 3.使用子组件
      <template>
        <div class="menu-edit">
            <!-- 3.使用子组件 -->
            <create-or-edit></create-or-edit>
        </div>
      </template>
      

布局处理(新思路)

  • 创建 menu/components/create-or-edit.vue组件,将 menu/create.vue 内容复制到 create-or-edit.vue 中
    • 通过不同页面的引入,更改标题name('添加菜单'or'编辑菜单')
    <span>{{ isEdit ? '编辑菜单' : '添加菜单' }}</span>
    
    • create-or-edit 组件通过 prop 接收⽗组件数据isEdit 来判断要展示哪种结构
    // 接收⽗组件传值,判断是添加还是编辑功能
    props: {
      isEdit: {
      // 要求类型为布尔,默认值 false
        type: Boolean,
        default: false
      }
    }
    
  • 将菜单编辑添加到路由表中。由于编辑为某个菜单的编辑,应设置动态路由展示菜单项idpath: '/menu/:id/edit'

逻辑处理(重要)

  • 编辑功能中,create-or-edit 的表单不需要重置按钮,通过v-if 判断。
  • 编辑时,将要编辑的菜单项信息展示在表单中。
    • 之前操作中分析过,getEditMenuInfo 接⼝在编辑功能时可以获取到菜单信息,添加时为空。
    • 这⾥需要将动态路由参数传⼊,并给添加功能设置默认值-1。将响应数据中的 menuInfo 赋值给 data 中的 data.form 即可(属性名是对应的)。
    async loadMenuInfo () {
      // 因为添加了编辑功能,所以需要合并
      const id = this.$route.params.id || -1
      // 通过请求数据获取到上级菜单信息
      const { data } = await getEditMenuInfo(id)
      if (data.code === '000000') {
        // 分情况,编辑 显示当前id的菜单内容 || 添加不显示
        if (data.data.menuInfo) {
          //  编辑菜单
          this.form = data.data.menuInfo
        }
        this.parentMenuList = data.data.parentMenuList
      }
    }
    
  • 由于添加与编辑是同⼀个接⼝,区别在于编辑时多了参数 id ,由于提交时传⼊的为 form 数据,编辑提交时就会⾃动包含id,所以提交操作⽆需处理,编辑功能完成。

回顾 动态路由

回顾 模板字符串

回顾slot组件插槽

  • 应用:父组件便捷的给子组件内部插入数据
  • 组件两标签内部是不能书写内容的,会被忽略

单个插槽

  • 当在子组件内部添加<slot></slot>,就可以在组件的内部书写内容,而且可以每次的内容不同

  • 子组件的数据是无法在父组件中展示的。

    • 父组件视图模板,只能加载父组件的数据。(全部加载完成后,在传给子组件)

      权限管理-子组件插槽.png

  • 后备内容:当父组件没有传值时,就可以展示默认内容

    权限管理-单个插槽的后备内容.png

具名插槽

  • 没有名字的slot标签,默认为default
  • template只是一个占位符,标记某一块区域做统一处理
<!-- 父组件 -->
<div class="container">
  <header>
    <slot name="header"></slot>
  </header>
</div>

<!-- 子组件 -->
<!-- v-slot只能在template中使用 -->
<com-a>
  <template v-slot:header>
    <h1>组件头部内容</h1>
  </template>
</com-a>

<!-- 简写 -->
<com-a>
  <template #header >
    <h1>组件头部内容</h1>
  </template>
</com-a>

作用域插槽

  • 解决:使用插槽时,父组件视图模板,不能加载子组件的数据问题。
  • 如果只存在默认插槽,同时又需要接收数据,可以进行简写
<!-- 简写,唯一一种将v-slot写在不是template之上,只适用于有一个插槽的情况 -->
<div id="app">
  <com-a v-slot:default="dataObj">
    {{ dataObj.value }}
  </com-a>
</div>

<!-- 最终简化 -->
<div id="app">
  <com-a v-slot="dataObj">
    {{ dataObj.value }}
  </com-a>
</div>

<!-- 根据ES6解构还可以进行简写 -->
<div id="app">
  <com-a v-slot="{ value, num }">
    {{ value }}
    {{ num }}
  </com-a>
</div>