Vue2项目练手——通用后台管理项目第七节

news2024/10/1 5:26:45

Vue2项目练手——通用后台管理项目

  • 用户管理
    • 分页
      • 使用的组件
      • Users.vue
      • mock.js
    • 关键字搜索区
      • Users.vue
  • 权限管理
    • 登录页面
      • 样式修改
        • Login.vue
    • 登录权限
      • 使用token对用户鉴,使用cookie对当前信息保存(类似localstorage)
      • Login.vue
      • router/index.js
    • 登录接口逻辑实现
      • 使用的组件
      • permission.js
      • mock.js
      • api/index.js
      • Login.vue
      • CommonHeader.vue

用户管理

分页

使用的组件

在这里插入图片描述

Users.vue

新增的代码:

 <div class="common-table">
      <el-table
          stripe
          height="90%"
          :data="tableData"
          style="width: 100%">
        <el-table-column
            prop="name"
            label="姓名">
        </el-table-column>
        <el-table-column
            prop="age"
            label="年龄">
        </el-table-column>
        <el-table-column
            prop="sex"
            label="性别">
          <!--自定义列,使用插槽的方式,element-ui上面有提供-->
          <template slot-scope="scope">
            <span>{{ scope.row.sex===1?'男':'女' }}</span>
          </template>
        </el-table-column>
        <el-table-column
            prop="birth"
            label="出生日期">
        </el-table-column>
        <el-table-column
            prop="addr"
            label="地址">
        </el-table-column>
        <el-table-column
            prop="action"
            label="操作">
          <!--自定义列,使用插槽的方式,element-ui上面有提供-->
          <template slot-scope="scope">
            <el-button size="mini" @click="handleEdit(scope.row)">编辑</el-button>
            <el-button size="mini" @click="handleDelete(scope.row)" type="danger">删除</el-button>
          </template>
        </el-table-column>
      </el-table>
      <!--    分页-->
      <div class="pager">
        <el-pagination
            layout="prev, pager, next"
            :total="total"
            @current-change="handleChange">
        </el-pagination>
      </div>
    </div>
	  total:0,   //当前的总条数
      pageData:{  //分页的
        page:1,
        limit:10
      }
getList(){
      //获取列表数据
      getUser({params:this.pageData}).then(({data})=>{
        console.log(data);
        this.tableData=data.list
        this.total=data.count||0
      })
    },
//选择页码的回调函数
    handleChange(val){
      console.log(val)
      this.pageData.page=val
      this.getList()
    }
<style scoped lang="less">
.manage{
  height: 90%;
  .common-table{
    position: relative;
    height: calc(100% - 62px);
    .pager{
      position: absolute;
      bottom: 0;
      right: 20px;
    }
  }
}
</style>

mock.js

//若要传递参数,使用正则方式
Mock.mock(/api\/user\/getUser/,user.getUserList)

全部代码:

import Mock from 'mockjs'
import homeApi from "@/api/mockServeData/home";
import user from '@/api/mockServeData/user'
/*//定义请求拦截
Mock.mock('/api/home/getData',function (){
    //拦截到请求后处理的逻辑
    console.log("拦截到了")
})*/
//定义请求拦截
Mock.mock('/api/home/getData',homeApi.getStatisticalData)

//用户列表的数据
Mock.mock('/api/user/add','post',user.createUser)
Mock.mock('/api/user/edit','post',user.updateUser)
Mock.mock('/api/user/del','post',user.deleteUser)
//若要传递参数,使用正则方式
Mock.mock(/api\/user\/getUser/,user.getUserList)

请添加图片描述

关键字搜索区

Users.vue

<el-form :model="userForm" :inline="true">
        <el-form-item>
          <el-input v-model="userForm.name" placeholder="请输入名称" @keyup.enter="onSubmit"></el-input>
        </el-form-item>
        <el-form-item>
          <el-button type="primary" @click="onSubmit">查询</el-button>
        </el-form-item>
      </el-form>
userForm:{
        name:''
      }

//封装获取列表的数据
    getList(){
      //获取列表数据
      getUser({params:{...this.userForm,...this.pageData}}).then(({data})=>{
        console.log(data);
        this.tableData=data.list
        this.total=data.count||0
      })
    }

 //列表的查询
    onSubmit(){
      this.getList()
    }
.manage-header{
    display: flex;
    justify-content: space-between;
    align-items: center;
  }

全部代码:

<template>
  <div class="manage">
    <el-dialog
        title="提示"
        :visible.sync="dialogVisible"
        width="40%"
        :before-close="handleClose">
      <!--      用户的表单信息-->
      <el-form ref="form" :inline="true" :rules="rules" :model="form" label-width="80px">
        <el-form-item label="姓名" prop="name">
          <el-input v-model="form.name" placeholder="请输入姓名"></el-input>
        </el-form-item>
        <el-form-item label="年龄" prop="age">
          <el-input v-model="form.age" placeholder="请输入年龄"></el-input>
        </el-form-item>
        <el-form-item label="性别" prop="sex">
          <el-select v-model="form.sex" placeholder="请选择">
            <el-option label="" :value="1"></el-option>
            <el-option label="" :value="0"></el-option>
          </el-select>
        </el-form-item>
        <el-form-item label="出生日期" prop="birth">
          <el-date-picker
              type="date"
              placeholder="选择日期"
              v-model="form.birth" style="width: 100%;"
              value-format="yyyy-MM-DD">
            <!--              日期格式转变-->
          </el-date-picker>
        </el-form-item>
        <el-form-item label="地址" prop="addr">
          <el-input v-model="form.addr" placeholder="请输入地址"></el-input>
        </el-form-item>
      </el-form>

      <span slot="footer" class="dialog-footer">
        <el-button @click="cancel">取 消</el-button>
        <el-button type="primary" @click="submit">确 定</el-button>
      </span>
    </el-dialog>
    <div class="manage-header">
      <el-button type="primary" @click="handleAdd">+新增</el-button>
<!--      form搜索区-->
      <el-form :model="userForm" :inline="true">
        <el-form-item>
          <el-input v-model="userForm.name" placeholder="请输入名称" @keyup.enter="onSubmit" clearable></el-input>
        </el-form-item>
        <el-form-item>
          <el-button type="primary" @click="onSubmit">查询</el-button>
        </el-form-item>
      </el-form>
    </div>
    <div class="common-table">
      <el-table
          stripe
          height="90%"
          :data="tableData"
          style="width: 100%">
        <el-table-column
            prop="name"
            label="姓名">
        </el-table-column>
        <el-table-column
            prop="age"
            label="年龄">
        </el-table-column>
        <el-table-column
            prop="sex"
            label="性别">
          <!--自定义列,使用插槽的方式,element-ui上面有提供-->
          <template slot-scope="scope">
            <span>{{ scope.row.sex===1?'男':'女' }}</span>
          </template>
        </el-table-column>
        <el-table-column
            prop="birth"
            label="出生日期">
        </el-table-column>
        <el-table-column
            prop="addr"
            label="地址">
        </el-table-column>
        <el-table-column
            prop="action"
            label="操作">
          <!--自定义列,使用插槽的方式,element-ui上面有提供-->
          <template slot-scope="scope">
            <el-button size="mini" @click="handleEdit(scope.row)">编辑</el-button>
            <el-button size="mini" @click="handleDelete(scope.row)" type="danger">删除</el-button>
          </template>
        </el-table-column>
      </el-table>
      <!--    分页-->
      <div class="pager">
        <el-pagination
            layout="prev, pager, next"
            :total="total"
            @current-change="handleChange">
        </el-pagination>
      </div>
    </div>
  </div>

</template>

<script>
import {addUser, getUser,editUser,delUser} from "@/api";

export default {
  name: "Users",
  data(){
    return {
      dialogVisible:false,
      form: {
        name: '',
        age: '',
        sex: '',
        birth: '',
        addr: '',
      },
      rules: {
        name: [{required: true, message: "请输入姓名"}],
        age: [{required: true, message: "请输入年龄"}],
        sex: [{required: true, message: "请选择性别"}],
        birth: [{required: true, message: "请选择出生日期"}],
        addr: [{required: true, message: "请输入地址"}],
      },
      tableData: [],
      modalType:0,  //0表示新增的弹窗,1表示的是编辑
      total:0,   //当前的总条数
      pageData:{  //分页的
        page:1,
        limit:10
      },
      userForm:{
        name:''
      }
    }
  },
  methods:{
    //提交用户表单
    submit(){
      this.$refs.form.validate((valid)=>{
        if(valid){
          //  后续对表单数据的处理
          console.log(this.form)
          if(this.modalType===0){
            //新增
            addUser(this.form).then(()=>{
              //  重新获取列表结果
              this.getList()
            })
          }else{
            //  编辑处理
            editUser(this.form).then(()=>{
              //  重新获取列表结果
              this.getList()
            })
          }
          //清空表单数据
          this.$refs.form.resetFields()
          //关闭弹窗
          this.dialogVisible=false
        }
      })
    },
    //弹窗关闭的时候
    handleClose(){
      //清空表单
      this.$refs.form.resetFields()
      this.dialogVisible=false
    },
    cancel(){
      this.handleClose()
    },
    handleEdit(row){
      console.log("row",row)
      this.modalType=1
      this.dialogVisible=true
      //注意需要对当前行数据进行深拷贝,否则会出错
      this.form=JSON.parse(JSON.stringify(row))
    },
    handleDelete(row){
      this.$confirm('此操作将永久删除该文件, 是否继续?', '提示', {
        confirmButtonText: '确定',
        cancelButtonText: '取消',
        type: 'warning'
      }).then(() => {
        delUser({id:row.id}).then(()=>{
          this.$message({
            type: 'success',
            message: '删除成功!'
          });
          //  重新获取列表结果
          this.getList()
        })

      }).catch(() => {
        this.$message({
          type: 'info',
          message: '已取消删除'
        });
      });
    },
    //封装获取列表的数据
    getList(){
      //获取列表数据
      getUser({params:{...this.userForm,...this.pageData}}).then(({data})=>{
        console.log(data);
        this.tableData=data.list
        this.total=data.count||0
      })
    },
    //新增的功能
    handleAdd(){
      this.modalType=0
      this.dialogVisible=true
    },
    //选择页码的回调函数
    handleChange(val){
      console.log(val)
      this.pageData.page=val
      this.getList()
    },
    //列表的查询
    onSubmit(){
      this.getList()
    }
  },
  mounted() {
    this.getList()
  }
}
</script>

<style scoped lang="less">
.manage{
  height: 90%;
  .manage-header{
    display: flex;
    justify-content: space-between;
    align-items: center;
  }
  .common-table{
    position: relative;
    height: calc(100% - 62px);
    .pager{
      position: absolute;
      bottom: 0;
      right: 20px;
    }
  }
}
</style>

请添加图片描述

权限管理

登录页面

样式修改

Login.vue

<template>
  <div id="app">
    <div class="main-content">
      <div class="title">系统登录</div>
      <div class="content">
        <el-form label-width="70px" :inline="true" :model="form" status-icon :rules="rules" ref="ruleForm" class="demo-ruleForm">
          <el-form-item label="用户名" prop="username">
            <el-input v-model="form.username" placeholder="请输入账号"></el-input>
          </el-form-item>
          <el-form-item label="密码" prop="password">
            <el-input v-model="form.password" type="password" autocomplete="off" placeholder="请输入密码"></el-input>
          </el-form-item>
          <el-form-item>
            <el-button type="primary" @click="submitForm('ruleForm')">登录</el-button></el-col>
          </el-form-item>
        </el-form>
      </div>
    </div>

  </div>

</template>

<script>
export default {
  name: "login",
  data(){
    return{
      form: {
        username: '',
        password:""
      },
      rules: {
        username: [
          {required: true, message: '请输入用户名', trigger: 'blur'},
          {min: 3, max: 5, message: '长度在 3 到 5 个字符', trigger: 'blur'}
        ],
        password: [
          {required:true,message:"请输入密码",trigger:"blur"}
        ]
      }
    }
  },
  methods:{
    submitForm(formName) {
      this.$refs[formName].validate((valid) => {
        if (valid) {
          console.log("ddddd")
          console.log(this.$router)
          // this.$router.push('/home')
        } else {
          console.log('error submit!!');
          return false;
        }
      });
    },
  }
}
</script>

<style lang="less" scoped>
#app {
  display: flex;
  background-color: #333;
  height: 100vh;
  .main-content{
    height: 300px;
    width: 350px;
    //line-height: 100vh;
    background-color: #fff;
    margin: 200px auto;
    border-radius: 15px;
    padding: 35px 35px 15px 35px;
    box-sizing: border-box;
    box-shadow: 5px  5px 10px rgba(0,0,0,0.5),-5px -5px 10px rgba(0,0,0,0.5);
    .title{
      font-size: 20px;
      text-align: center;
      font-weight: 300;
    }
    .content{
      margin-top: 30px;
    }
    .el-input{
      width: 198px;
    }
    .el-button{
      margin-left: 105px;
    }
  }
}
</style>

在这里插入图片描述

登录权限

使用token对用户鉴,使用cookie对当前信息保存(类似localstorage)

安装cookie

npm i js-cookie@3.0.1

Login.vue

//登录
    submitForm(formName) {
      this.$refs[formName].validate((valid) => {
        if (valid) {
          //token信息
          const token=Mock.Random.guid()  //生成随机数
          //token信息存入cookie用于不同页面间的通信
          Cookie.set('token',token)
          //跳转到首页
          this.$router.push('/home')
        } else {
          console.log('error submit!!');
          return false;
        }
      });
    },

全局代码:

<template>
  <div id="app">
    <div class="main-content">
      <div class="title">系统登录</div>
      <div class="content">
        <el-form label-width="70px" :inline="true" :model="form" status-icon :rules="rules" ref="ruleForm" class="demo-ruleForm">
          <el-form-item label="用户名" prop="username">
            <el-input v-model="form.username" placeholder="请输入账号"></el-input>
          </el-form-item>
          <el-form-item label="密码" prop="password">
            <el-input v-model="form.password" type="password" autocomplete="off" placeholder="请输入密码"></el-input>
          </el-form-item>
          <el-form-item>
            <el-button type="primary" @click="submitForm('ruleForm')">登录</el-button></el-col>
          </el-form-item>
        </el-form>
      </div>
    </div>

  </div>

</template>

<script>
import Mock from 'mockjs'
import Cookie from 'js-cookie'
export default {
  name: "login",
  data(){
    return{
      form: {
        username: '',
        password:""
      },
      rules: {
        username: [
          {required: true, message: '请输入用户名', trigger: 'blur'},
          {min: 3, max: 5, message: '长度在 3 到 5 个字符', trigger: 'blur'}
        ],
        password: [
          {required:true,message:"请输入密码",trigger:"blur"}
        ]
      }
    }
  },
  methods:{
    //登录
    submitForm(formName) {
      this.$refs[formName].validate((valid) => {
        if (valid) {
          //token信息
          const token=Mock.Random.guid()  //生成随机数
          //token信息存入cookie用于不同页面间的通信
          Cookie.set('token',token)
          //跳转到首页
          this.$router.push('/home')
        } else {
          console.log('error submit!!');
          return false;
        }
      });
    },
  }
}
</script>

<style lang="less" scoped>
#app {
  display: flex;
  background-color: #333;
  height: 100vh;
  .main-content{
    height: 300px;
    width: 350px;
    //line-height: 100vh;
    background-color: #fff;
    margin: 200px auto;
    border-radius: 15px;
    padding: 35px 35px 15px 35px;
    box-sizing: border-box;
    box-shadow: 5px  5px 10px rgba(0,0,0,0.5),-5px -5px 10px rgba(0,0,0,0.5);
    .title{
      font-size: 20px;
      text-align: center;
      font-weight: 300;
    }
    .content{
      margin-top: 30px;
    }
    .el-input{
      width: 198px;
    }
    .el-button{
      margin-left: 105px;
    }
  }
}
</style>

router/index.js

//添加全局前置导航守卫
router.beforeEach((to,from,next)=>{
    //判断token存不存在
    const token=Cookie.get('token')
    //token不存在,说明当前用户是未登录,应该跳转至登录页
    if(!token&&to.name!=='login'){
        next({name:'login'})
    }else if(token && to.name=="login"){   //token存在,说明用户登录,此时跳转至首页
        next({name:'home'})
    }else{
        next()
    }
})

全部代码:

import VueRouter from "vue-router";
import Login from "@/pages/Login.vue";
import Users from "@/pages/Users.vue";
import Main from '@/pages/Main.vue'
import Home from "@/pages/Home.vue";
import Mall from "@/pages/Mall.vue";
import PageOne from "@/pages/PageOne.vue";
import PageTwo from "@/pages/PageTwo.vue";
import Cookie from "js-cookie";

const router= new VueRouter({
    // 浏览器模式设置,设置为history模式
    // mode:'history',
    routes:[
        {
            name:'login',
            path:"/login",
            component:Login,
            meta:{title:"登录"},
        },
        {
            // 子路由
            name:"main",
            path:'/',
            redirect:"/home",  //重定向 当路径为/,则重定向home
            component:Main,
            children:[
                {
                    name:"user",
                    path:"user",
                    component:Users,
                    meta:{title:"用户管理"}
                },
                {
                    name:"home",
                    path:"home",
                    component:Home,
                    meta:{title:"首页"}
                },
                {
                    name:"mall",
                    path:"mall",
                    component:Mall,
                    meta:{title:"商品管理"}
                },
                {
                    name:"page1",
                    path:"page1",
                    component:PageOne,
                    meta:{title:"页面1"}
                },
                {
                    name:"page2",
                    path:"page2",
                    component:PageTwo,
                    meta:{title:"页面2"}
                }
            ]
        }

    ]
})
//添加全局前置导航守卫
router.beforeEach((to,from,next)=>{
    //判断token存不存在
    const token=Cookie.get('token')
    //token不存在,说明当前用户是未登录,应该跳转至登录页
    if(!token&&to.name!=='login'){
        next({name:'login'})
    }else if(token && to.name=="login"){   //token存在,说明用户登录,此时跳转至首页
        next({name:'home'})
    }else{
        next()
    }
})
// 后置路由守卫
router.afterEach((to,from)=>{
    document.title=to.meta.title||"通用后台管理系统"
})
export default router

请添加图片描述

登录接口逻辑实现

使用的组件

在这里插入图片描述

permission.js

import Mock from 'mockjs'
export default {
    getMenu: config => {
        const { username, password } = JSON.parse(config.body)
        // 先判断用户是否存在
        // 判断账号和密码是否对应
        if (username === 'admin' && password === 'admin') {
            return {
                code: 20000,
                data: {
                    menu: [
                        {
                            path: '/home',
                            name: 'home',
                            label: '首页',
                            icon: 's-home',
                            url: 'Home.vue'
                        },
                        {
                            path: '/mall',
                            name: 'mall',
                            label: '商品管理',
                            icon: 'video-play',
                            url: 'Mall.vue'
                        },
                        {
                            path: '/user',
                            name: 'user',
                            label: '用户管理',
                            icon: 'user',
                            url: 'User.vue'
                        },
                        {
                            label: '其他',
                            icon: 'location',
                            children: [
                                {
                                    path: '/page1',
                                    name: 'page1',
                                    label: '页面1',
                                    icon: 'setting',
                                    url: 'PageOne.vue'
                                },
                                {
                                    path: '/page2',
                                    name: 'page2',
                                    label: '页面2',
                                    icon: 'setting',
                                    url: 'PageTwo.vue'
                                }
                            ]
                        }
                    ],
                    token: Mock.Random.guid(),
                    message: '获取成功'
                }
            }
        } else if (username === 'xiaoxiao' && password === 'xiaoxiao') {
            return {
                code: 20000,
                data: {
                    menu: [
                        {
                            path: '/home',
                            name: 'home',
                            label: '首页',
                            icon: 's-home',
                            url: 'Home.vue'
                        },
                        {
                            path: '/video',
                            name: 'video',
                            label: '商品管理',
                            icon: 'video-play',
                            url: 'Mall.vue'
                        }
                    ],
                    token: Mock.Random.guid(),
                    message: '获取成功'
                }
            }
        } else {
            return {
                code: -999,
                data: {
                    message: '密码错误'
                }
            }
        }

    }
}

mock.js

import permission from "@/api/mockServeData/permission";
//传递数据并且对数据库产生影响的接口,使用post方式
Mock.mock(/api\/permission\/getMenu/,'post',permission.getMenu)

全部代码:

import Mock from 'mockjs'
import homeApi from "@/api/mockServeData/home";
import user from '@/api/mockServeData/user'
import permission from "@/api/mockServeData/permission";
/*//定义请求拦截
Mock.mock('/api/home/getData',function (){
    //拦截到请求后处理的逻辑
    console.log("拦截到了")
})*/
//定义请求拦截
Mock.mock('/api/home/getData',homeApi.getStatisticalData)

//用户列表的数据
Mock.mock('/api/user/add','post',user.createUser)
Mock.mock('/api/user/edit','post',user.updateUser)
Mock.mock('/api/user/del','post',user.deleteUser)
//若要传递参数,使用正则方式
Mock.mock(/api\/user\/getUser/,user.getUserList)
//传递数据并且对数据库产生影响的接口,使用post方式
Mock.mock(/api\/permission\/getMenu/,'post',permission.getMenu)

api/index.js

export const getMenu=(data)=>{
    return http.post('/permission/getMenu',data)
}

全部代码:

import http from "@/utils/request";

//请求首页数据
export const getData=()=>{
    //返回一个promise对象
    return http.get('/home/getData')
}

export const getUser=(params)=>{
    //返回用户列表  axios的get请求是在params中
    return http.get('/user/getUser',params)
}

export const addUser=(data)=>{
    //新增用户  axios的post请求是在data中
    return http.post('/user/add',data)
}

export const editUser=(data)=>{
    //编辑用户  axios的post请求是在data中
    return http.post('/user/edit',data)
}
export const delUser=(data)=>{
    //删除用户  axios的post请求是在data中
    return http.post('/user/del',data)
}
export const getMenu=(data)=>{
    return http.post('/permission/getMenu',data)
}

Login.vue

import {getMenu} from "@/api";

//登录
    submitForm(formName) {
      this.$refs[formName].validate((valid) => {
        if (valid) {
          //token信息
          /*const token=Mock.Random.guid()  //生成随机数
          //token信息存入cookie用于不同页面间的通信
          Cookie.set('token',token)*/
          getMenu(this.form).then(({data})=>{
            console.log(data)
            if(data.code===20000){
              Cookie.set('token',data.data.token)
              //跳转到首页
              this.$router.push('/home')
            }else{
              this.$message.error(data.data.message)
            }
          })

        } else {
          console.log('error submit!!');
          return false;
        }
      });
    },

全部代码:

<template>
  <div id="app">
    <div class="main-content">
      <div class="title">系统登录</div>
      <div class="content">
        <el-form label-width="70px" :inline="true" :model="form" status-icon :rules="rules" ref="ruleForm" class="demo-ruleForm">
          <el-form-item label="用户名" prop="username">
            <el-input v-model="form.username" placeholder="请输入账号"></el-input>
          </el-form-item>
          <el-form-item label="密码" prop="password">
            <el-input v-model="form.password" type="password" autocomplete="off" placeholder="请输入密码"></el-input>
          </el-form-item>
          <el-form-item>
            <el-button type="primary" @click="submitForm('ruleForm')">登录</el-button></el-col>
          </el-form-item>
        </el-form>
      </div>
    </div>

  </div>

</template>

<script>
// import Mock from 'mockjs'
import Cookie from 'js-cookie'
import {getMenu} from "@/api";
export default {
  name: "login",
  data(){
    return{
      form: {
        username: '',
        password:""
      },
      rules: {
        username: [
          {required: true, message: '请输入用户名', trigger: 'blur'},
          {min: 3, max: 5, message: '长度在 3 到 5 个字符', trigger: 'blur'}
        ],
        password: [
          {required:true,message:"请输入密码",trigger:"blur"}
        ]
      }
    }
  },
  methods:{
    //登录
    submitForm(formName) {
      this.$refs[formName].validate((valid) => {
        if (valid) {
          //token信息
          /*const token=Mock.Random.guid()  //生成随机数
          //token信息存入cookie用于不同页面间的通信
          Cookie.set('token',token)*/
          getMenu(this.form).then(({data})=>{
            console.log(data)
            if(data.code===20000){
              Cookie.set('token',data.data.token)
              //跳转到首页
              this.$router.push('/home')
            }else{
              this.$message.error(data.data.message)
            }
          })

        } else {
          console.log('error submit!!');
          return false;
        }
      });
    },
  }
}
</script>

<style lang="less" scoped>
#app {
  display: flex;
  background-color: #333;
  height: 100vh;
  .main-content{
    height: 300px;
    width: 350px;
    //line-height: 100vh;
    background-color: #fff;
    margin: 200px auto;
    border-radius: 15px;
    padding: 35px 35px 15px 35px;
    box-sizing: border-box;
    box-shadow: 5px  5px 10px rgba(0,0,0,0.5),-5px -5px 10px rgba(0,0,0,0.5);
    .title{
      font-size: 20px;
      text-align: center;
      font-weight: 300;
    }
    .content{
      margin-top: 30px;
    }
    .el-input{
      width: 198px;
    }
    .el-button{
      margin-left: 105px;
    }
  }
}
</style>

CommonHeader.vue

<el-dropdown @command="handleClick">
          <span class="el-dropdown-link">
            <img src="@/assets/user.webp" alt="">
          </span>
          <el-dropdown-menu slot="dropdown">
            <el-dropdown-item>个人中心</el-dropdown-item>
            <el-dropdown-item command="cancel">退出</el-dropdown-item>
          </el-dropdown-menu>
      </el-dropdown>
handleClick(command){
      if(command==='cancel'){
        console.log("登出")
        //清除Cookie的token信息
        Cookie.remove('token')
        this.$router.push('/login')
      }

    }

全部代码:

<template>
  <div class="header-container">
    <div class="l-content">
      <el-button style="margin-right: 20px" icon="el-icon-menu" size="mini" @click="handleMenu"></el-button>
      <!--      面包屑-->
<!--      <span class="text">首页</span>-->
      <el-breadcrumb separator="/">
        <el-breadcrumb-item v-for="item in tags" :key="item.path" :to="{ path: item.path }">{{ item.label }}</el-breadcrumb-item>
      </el-breadcrumb>
    </div>
    <div class="r-content">
      <el-dropdown @command="handleClick">
          <span class="el-dropdown-link">
            <img src="@/assets/user.webp" alt="">
          </span>
          <el-dropdown-menu slot="dropdown">
            <el-dropdown-item>个人中心</el-dropdown-item>
            <el-dropdown-item command="cancel">退出</el-dropdown-item>
          </el-dropdown-menu>
      </el-dropdown>
    </div>
  </div>

</template>

<script>
import {mapState} from 'vuex'
import Cookie from 'js-cookie'
export default {
  name: "CommonHeader",
  methods:{
    handleMenu(){
      this.$store.commit('collapseMenu')
    },
    handleClick(command){
      if(command==='cancel'){
        console.log("登出")
        //清除Cookie的token信息
        Cookie.remove('token')
        this.$router.push('/login')
      }

    }
  },
  computed:{
    ...mapState({
      tags: state=>state.tab.tabsList
    })
  }
}
</script>

<style scoped lang="less">
.header-container {
  height: 60px;
  background-color: #333;
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding: 0 20px;

  .text {
    color: #fff;
    font-size: 14px;
    margin-left: 10px;
  }
  .r-content{
    img{
      width: 40px;
      height: 40px;
      border-radius: 50%;
    }
  }
  .l-content{
    display: flex;
    align-items: center;
    /deep/.el-breadcrumb__item{   /*元素没有绑定data-v-5a90ec03这样的编号时候,样式不起作用,使用deep进行穿刺可解决问题*/
      .el-breadcrumb__inner{
        font-weight: normal;
        &.is-link{
          color: #666;
        }
      }
      &:last-child{
        .el-breadcrumb__inner {
          color: #fff;
        }
      }
    }
  }
}
</style>

请添加图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/983764.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

go基础08-map的内部实现

和切片相比&#xff0c;map类型的内部实现要复杂得多。Go运行时使用一张哈希表来实现抽象的map类型。运行时实现了map操作的所有功能&#xff0c;包括查找、插入、删除、遍历等。在编译阶段&#xff0c;Go编译器会将语法层面的map操作重写成运行时对应的函数调用。 下面是大致的…

07-垃圾收集算法详解

上一篇&#xff1a;06-JVM对象内存回收机制深度剖析 1.分代收集理论 当前虚拟机的垃圾收集都采用分代收集算法&#xff0c;这种算法没有什么新的思想&#xff0c;只是根据对象存活周期的不同将内存分为几块。一般将java堆分为新生代和老年代&#xff0c;这样我们就可以根据各…

【LeetCode-中等题】17. 电话号码的字母组合

文章目录 题目方法一&#xff1a;递归回溯 题目 方法一&#xff1a;递归回溯 参考讲解&#xff1a;还得用回溯算法&#xff01;| LeetCode&#xff1a;17.电话号码的字母组合 首先可以画出树图&#xff1a; 先将数字对应的字符集合 加入到一个map集合 这里需要一个index来控…

【vue2第十七章】VueRouter 编程式导航跳转传参(点击按钮跳转路由和如何传递参数)

如何在js进行跳转路由 在一些需求中&#xff0c;我们需要不用点击a标签或者router-link&#xff0c;但是也要实现路由跳转&#xff0c;比如登陆&#xff0c;点击按钮搜索跳转。那么这种情况如何进行跳转呢&#xff1f; 直接再按钮绑定的方法中写this.$router.push(路由路径)即…

软件兼容性测试怎么做?对软件产品起到什么作用?

软件兼容性测试是一项重要的软件测试活动&#xff0c;它可以确保在不同操作系统、硬件配置和软件环境下&#xff0c;软件能够正常运行&#xff0c;并与其他相关软件和系统进行正确的互动。 一、软件兼容性的测试方法 1、操作系统测试&#xff1a;测试软件在不同操作系统上的兼…

linux常用命令及解释大全(二)

目录 前言 一、文件的权限 二、文件的特殊属性 三、打包和压缩文件 四、查看文件内容 五、文本处理 5.1 grep 5.2 sed 5.3 其它 总结 前言 本篇文章接linux常用命令及解释大全&#xff08;一&#xff09;继续介绍了一部分linux常用命令&#xff0c;包括文件的权限&a…

Android签名查看

查看签名文件信息 第一种方法&#xff1a; 1.打开cmd&#xff0c;执行keytool -list -v -keystore xxx.keystore&#xff0c;效果如下图&#xff1a; 第二种方法: 1.打开cmd&#xff0c;执行 keytool -list -v -keystore xxxx.keystore -storepass 签名文件密码&#xff0…

Linux 下 C语言版本的线程池

目录 1. 线程池引入 2. 线程池介绍 3. 线程池的组成 4. 任务队列 5. 线程池定义 6. 头文件声明 7. 函数实现 8. 测试代码 1. 线程池引入 我们使用线程的时候就去创建一个线程&#xff0c;这样实现起来非常简便&#xff0c;但是就会有一个问题&#xff1a;如果并发的线程数…

壁炉在文学和艺术中的代表着什么呢,能给我们带来什么样的影响?

壁炉&#xff0c;不仅仅是家庭温暖的来源&#xff0c;也是文学和艺术中常见的重要元素。它的形象在文学作品、绘画和电影中频繁出现&#xff0c;不仅为故事情节提供了背景&#xff0c;还象征着情感、温馨和安全感。让我们一起深入探讨壁炉在文学和艺术中的形象&#xff0c;以及…

Android相机调用-CameraX【外接摄像头】【USB摄像头】

Android相机调用有原生的Camera和Camera2&#xff0c;我觉得调用代码都太复杂了&#xff0c;CameraX调用代码简洁很多。 说明文档&#xff1a;https://developer.android.com/jetpack/androidx/releases/camera?hlzh-cn 现有查到的调用资料都不够新&#xff0c;对于外接摄像…

RecyclerView的item布局预览显示是一行两块 运行后显示了一行一块,怎么回事

QQ有人问我了&#xff1a; 没有起作用&#xff1f;有 解决问题&#xff1a;在item布局上第一个外层宽度、高度分别为match_parent和wrap_content&#xff0c;第二个外层宽度和高度都为match_parent&#xff0c;运行后可以显示一行两块 其他学习资料&#xff1a; 1、付费专栏…

mybatis 数据库字段加密

目录 1、引入依赖 2、添加配置 3、指定加密字段 4、测试&#xff0c;效果 1、引入依赖 <dependency><groupId>io.github.whitedg</groupId><artifactId>mybatis-crypto-spring-boot-starter</artifactId><version>1.2.3</version>…

C#文件拷贝工具

目录 工具介绍 工具背景 4个文件介绍 CopyTheSpecifiedSuffixFiles.exe.config DataSave.txt 拷贝的存储方式 文件夹介绍 源文件夹 目标文件夹 结果 使用 *.mp4 使用 *.* 重名时坚持拷贝 可能的报错 C#代码如下 Form1.cs Form1.cs设计 APP.config Program.c…

微信小程序踩坑记录

1、原生微信小程序开发&#xff0c;切换版本后一直报错&#xff0c;切回去还是报错&#xff0c;后来排查发现是编辑器未更新的问题 2、本地开发静态时&#xff0c;要把这个勾选&#xff0c;否则每次提交代码都会冲突 持续记录踩坑。。。

果粉崩溃!Icloud又要涨价?我来教你使用群晖生态将本地SSD“上云“!

文章目录 前言本教程解决的问题是&#xff1a;按照本教程方法操作后&#xff0c;达到的效果是想使用群晖生态软件&#xff0c;就必须要在服务端安装群晖系统&#xff0c;具体如何安装群晖虚拟机请参考&#xff1a; 1. 安装并配置synology drive1.1 安装群辉drive套件1.2 在局域…

Android离线文字识别-tesseract4android调用

Android在线文字识别可以调阿里云的接口Android文字识别-阿里云OCR调用__花花的博客-CSDN博客 需要离线文字识别的话&#xff0c;可以调tesseract4android。个人测试效果不是特别理想&#xff0c;但是速度真的很快&#xff0c;VIVO S10后摄照片&#xff0c;80ms内识别完成。现…

手写Spring:第13章-把AOP扩展到Bean的生命周期

文章目录 一、目标&#xff1a;把AOP扩展到Bean的生命周期二、设计&#xff1a;把AOP扩展到Bean的生命周期三、实现&#xff1a;把AOP扩展到Bean的生命周期3.1 工程结构3.2 AOP动态代理融入Bean的生命周期类图3.3 定义Advice拦截器链3.3.1 定义拦截器链接口3.3.2 方法拦截器链接…

算法笔记:堆

【如无特别说明&#xff0c;皆为最小二叉堆】 1 介绍 2 特性 结构性&#xff1a;符合完全二叉树的结构有序性&#xff1a;满足父节点小于子节点&#xff08;最小化堆&#xff09;或父节点大于子节点&#xff08;最大化堆&#xff09; 3 二叉堆的存储 顺序存储 二叉堆的有序…

问道管理:a股交易时间和规则?

A股是指中国境内流通的人民币普通股票&#xff0c;是国内投资者最为熟悉和广泛的投资工具之一。作为投资者&#xff0c;了解A股的买卖时刻和规矩是非常重要的。本文从买卖时刻、买卖规矩、买卖方式等多个视点来分析A股买卖时刻和规矩&#xff0c;期望对读者有所协助。 A股买卖…

C#事件event

事件模型的5个组成部分 事件拥有者&#xff08;event source&#xff09;&#xff08;类对象&#xff09;&#xff08;有些书将其称为事件发布者&#xff09; 事件成员&#xff08;event&#xff09;&#xff08;事件拥有者的成员&#xff09;&#xff08;事件成员就是事件本身…