vue后台管理系统(记录)

1. vue动态路由导航栏菜单

后台管理系统中,根据不同的权限显示不同的导航栏菜单
基本流程:首先获取数据--->动态拼接路由信息--->动态添加路由信息

# router/index.js
import store from '@/store'
const routes = [
  {
    path:'/',
    redirect:'/login'
  },
  {
    path: '/login',
    name: 'Login',
    component: () => import('../views/Login.vue')
  },
  {
    path: '/main',
    name: 'Main',
    component: () => import('../views/Main.vue'),
    redirect:'/welcome',  // 重定向到 /welcome
    children:[{
      path:'/welcome',
      name:'Welcome',
      component: () => import('../views/Welcome.vue')
    }]
  }
]
// 获取数据,为了减少请求的发送我们可以把数据存储到vuex
function add() {
  let arr = []
  // store.state.menus存储在vuex里面的数据
  store.state.menus.forEach(item=>{
    item.children.forEach(v=>{
      arr.push({
        path: '/' + v.path,
        name: v.path,
        component: () => import('../views/' + v.path + '/' + v.path + '.vue')    
      })
    })
  })
  return arr
}

添加动态路由(addRoute)
router.addRoute()				 // 添加顶级路由对象
router.addRoute('Main',...add()) // 添加二级路由对象

在Vue Router里面有动态添加路由addRoute方法

设置NotFound页面

对于那些没有匹配到的路由,我们通常会匹配到固定的某个页面,进行报错提醒。

可以编写一个动态路由用于匹配所有的页面
  {
    path:'/:pathMatch(.*)',
    component:()=>import('../views/NotFound.vue')
  }
NotFound.vue页面
<div class='not'>
    <h2>Page Not Found</h2>
    <p>你打开的页面不存在</p>
    你输入的是:{{$route.params.pathMatch}}
</div>

在这里插入图片描述
在这里插入图片描述
这里还有另一种写法:

注意:只是在/:pathMatch(.*)后面加了*

  {
    path:'/:pathMatch(.*)*',
    component:()=>import('../views/not.vue')
  }

这两种写法的区别在于是否解析/
在这里插入图片描述
在这里插入图片描述

2. 改变element-ui中MessageBox弹框(确认消息)

官网给我们代码:

this.$confirm('此操作将永久删除该文件, 是否继续?', '提示', {
  confirmButtonText: '确定',
  cancelButtonText: '取消',
  type: 'warning'
}).then(() => {
  this.$message({
    type: 'success',
    message: '删除成功!'
  });
}).catch(() => {
  this.$message({
    type: 'info',
    message: '已取消删除'
  });          
});

为了解决回调地狱,我们将其改编成async/await形式:
注意:await只接受then()语句的返回,所以catch不能去掉

const confirmReturn = await this.$confirm('此操作将永久删除该文件, 是否继续?', '提示', {
    confirmButtonText: '确定',
    cancelButtonText: '取消',
    type: 'warning'
}).catch(err=>err)
// 点击确定 返回值:confirm
// 点击取消 返回值:cancel
if(confirmReturn != 'confirm') return this.$message.info('已取消删除')

3. 树形表格(table_tree)

1. 下载插件

cnpm i vue-table-with-tree-grid -S

2. 全局注册树形表格

import TreeTable from 'vue-table-with-tree-grid'
Vue.component('tree-table',TreeTable)

3. 使用

data:绑定一个数组(具有树形结构)
columns:[{label:‘分类名称’,prop:‘cat_name’},{label:‘是否有效’,type:‘template’,template:‘isok’}]自定义模板
selection-type:是否显示勾选框
expand-type:是否显示展开
show-index:显示index 和 index-text="#" 一起使用
show-row-hover:鼠标滑过有高亮显示
border:纵向边框

<tree-table 
:data="catelist" 
:columns="columns"
:selection-type="false"
:expand-type="false" 
show-index 
index-text="索引"
:show-row-hover="false"
border
>
    <!-- 是否有效 -->
    <template slot="isOk" slot-scope="scope">
        <i v-if="!scope.row.cat_deleted" class="el-icon-success" style="color:lightgreen"></i>
        <i v-else class="el-icon-error" style="color:red"></i>
    </template>
    <!-- 排序 -->
    <template slot="sort" slot-scope="scope">
        <el-tag v-if="scope.row.cat_level === 0" size="mini">一级</el-tag>
        <el-tag v-if="scope.row.cat_level === 1" size="mini" type="success">二级</el-tag>
        <el-tag v-if="scope.row.cat_level === 2" size="mini" type="warning">三级</el-tag>
    </template>
</tree-table>

对于columns的配置:
columns:[{
    label:'分类名称',
    prop:'cat_name'
},{
    label:'是否有效',
    type:'template',
    template:'isOk'
},{
    label:'排序',
    type:'template',
    template:'sort'
}]

4. vue跳转路由 加载进度条

1. 下载插件

npm install --save nprogress

2. main.js引入:导入NProgress, 包对应的JS和CSS

import NProgress from 'nprogress';
import 'nprogress/nprogress.css';

3. 使用

和路由守卫一起使用:

//在页面跳转使用
router.beforeEach((to,from,next) => {
	//开始进度条
	NProgress.start();
	// 继续路由
	next();
});
router.afterEach((to,from,next) => {
	//结束进度条
	NProgress.done();
});

也可以写在axios拦截器里面:

axios.interceptors.request.use(config => {
  //当进入request拦截器,表示发送了请求,我们就开启进度条
  NProgress.start()
  return config
})
//在response拦截器中,隐藏进度条
axios.interceptors.response.use(res=>{
  //当进入response拦截器,表示请求已经结束,我们就结束进度条
  NProgress.done()
  return res
})

4. 修改进度条样式

#nprogress .bar {
	background: red !important;
}

5. 利用element-ui组件(Upload)上传图片

注意:图片上传不会走我们封装的axios,它是一个独立的系统,所以我们要自己定义请求路径和请求头信息

action:上传的地址
headers:设置上传的请求头部
on-preview:点击文件列表已上传的文件时钩子,进行图片预览
on-remove:文件列表移除文件时的钩子
on-success:文件上传成功时的钩子
list-type:文件列表的类型

<el-upload
class="upload-demo"
action="http://127.0.0.1:8888/api/private/v1/upload"
:headers="headersObj"
:on-preview="handlePreview"
:on-remove="handleRemove"
list-type="picture"
:on-success="handlerSuccess">
<el-button size="small" type="primary">点击上传</el-button>
</el-upload>

<!-- 图片预览弹出框 -->
<el-dialog
title="图片预览"
:visible.sync="dialogVisible"
width="50%">
    <img :src="previewSrc" alt="" class="previewimg">
</el-dialog>

<script>
export default {
	data() {
		return {
            headersObj:{
                Authorization:sessionStorage.getItem('token')
            },
            dialogVisible:false,
            previewSrc:'',
            pics:[]
		}
	},
	methods: {
        // 图片预览
        handlePreview(file) {
            this.previewSrc = file.response.data.url
            this.dialogVisible = true
        },
        // 图片移除
        handleRemove(file) {
            const filePath = file.response.data.tmp_path
            const i = this.pics.findIndex(x => x.pic == filePath)
            this.pics.splice(i,1)
        },
        // 图片上传成功
        handlerSuccess(response) {
        	// tmp_path图片在服务器的路径
            const picInfo = { pic: response.data.tmp_path }
            this.pics.push(picInfo)
        }	
	}
}
</script>

<style lang='scss' scoped>
    .previewimg {
        width: 100%;
    }
</style>

可通过设置limiton-exceed来限制上传文件的个数和定义超出限制时的行为

multiple 可以一次选择多个图片上传

<el-upload
  multiple
  :limit="3"
  :on-exceed="handleExceed">
  <el-button size="small" type="primary">点击上传</el-button>
</el-upload>

methods:{
      handleExceed(files, fileList) {
        this.$message.warning(`当前限制选择 3 个文件,本次选择了 ${files.length} 个文件`);
      },
}

通过设置before-remove来阻止文件移除操作

预删除
before-remove:删除文件之前的钩子,参数为上传的文件和文件列表,若返回 false,停止删除

<el-upload
  :before-remove="beforeRemove">
  <el-button size="small" type="primary">点击上传</el-button>
</el-upload>

methods:{
      beforeRemove(file, fileList) {
        return this.$confirm(`确定移除 ${ file.name }`);
      }
}

在这里插入图片描述

使用 before-upload 限制用户上传的图片格式和大小

before-upload:上传文件之前的钩子,参数为上传的文件,若返回false则停止上传

<el-upload
  :before-upload="beforeAvatarUpload">
  <el-button size="small" type="primary">点击上传</el-button>
  <div slot="tip" class="el-upload__tip">只能上传jpg/png文件,且不超过2MB</div>
</el-upload>

methods:{
      beforeAvatarUpload(file) {
      	const imageType = ['image/jpeg','image/png']
        const isJPG = imageType.includes(file.type)
        const isLt2M = file.size / 1024 / 1024 < 2;

        if (!isJPG) {
          this.$message.error('上传头像图片只能是 JPG/PNG 格式!');
        }
        if (!isLt2M) {
          this.$message.error('上传头像图片大小不能超过 2MB!');
        }
        return isJPG && isLt2M;
      }
}

drag拖拽上传

<el-upload
  class="upload-demo"
  drag
  action="https://jsonplaceholder.typicode.com/posts/"
  multiple>
  <i class="el-icon-upload"></i>
  <div class="el-upload__text">将文件拖到此处,或<em>点击上传</em></div>
</el-upload>

在这里插入图片描述

6. vue-quill-editor富文本编译器

1. 下载插件

npm install vue-quill-editor -S

2. 在main.js引入

// 导入富文本编辑器
import  VueQuillEditor from 'vue-quill-editor'
// 导入富文本编辑器样式
import 'quill/dist/quill.core.css'
import 'quill/dist/quill.snow.css'
import 'quill/dist/quill.bubble.css'
// 全局注册富文本编辑器
Vue.use(VueQuillEditor)

3. 使用

<quill-editor 
v-model="content" 
:options="editorOption"
// 可以绑定事件
@blur="onEditorBlur($event)" 	// 失去焦点事件
@focus="onEditorFocus($event)"	// 获取焦点事件
@change="onEditorChange($event)"// 内容改变事件
></quill-editor>
options:是用来对这个富文本编辑器进行设置的。
工具栏是分块的,默认显示的比较多,且有重复功能的,可以在editorOption的modules属性中设置,只显示自己需要的。还可以设置placeholder属性设置输入框中的提示词。
editorOption:{
	// placeholder设置提示词
	placeholder: '请输入正文......',
	// modules设置工具栏
	modules: {
	    toolbar: [
	        ['bold', 'italic', 'underline', 'strike'],
	        ['blockquote', 'code-block'],
	        ['formula'],
	        ['clean'],
	        ['link', 'image', 'video'],
	        [{ 'header': 1 }, { 'header': 2 }],
	        [{ 'list': 'ordered'}, { 'list': 'bullet' }], 
	        [{ 'script': 'sub'}, { 'script': 'super' }],
	        [{ 'indent': '-1'}, { 'indent': '+1' }],
	        [{ 'direction': 'rtl' }],
	        [{ 'size': ['small', false, 'large', 'huge'] }],
	        [{ 'header': [1, 2, 3, 4, 5, 6, false] }],
	        [{ 'color': [] }, { 'background': [] }], 
	        [{ 'font': [] }],
	        [{ 'align': [] }]
	    ]
	}
}

7. 项目中使用lodash

1. 下载插件

cnpm i lodash -S

2. 导入

// 引入lodash库(官方推荐将lodash导入为_)
import _ from 'lodash'

简单说几个常用的方法,了解更多可以去lodash官网地址

_.clone(value):创建一个 value 的浅拷贝
_.cloneDeep(value):创建一个value的深拷贝
_.assign(object, [sources])

分配来源对象的可枚举属性到目标对象上。 来源对象的应用规则是从左到右,随后的下一个对象的属性会覆盖上一个对象的属性

_.merge(object, [sources])

该方法类似_.assign, 除了它递归合并 sources 来源对象自身和继承的可枚举属性到 object 目标对象。

3. 使用

addGoods() {
    // 验证
    this.$refs.addForm.validate(async (valid) => {
        if(!valid) return this.$message.error('请填写必要的表单项!')
        // this.addForm.goods_cat = this.addForm.goods_cat.join(',')
        // 以上写法不正确:级联选择器绑定的要是一个数组(会改变原来的数据)
        // 第一种写法:深拷贝
        let copyForm = JSON.parse(JSON.stringify(this.addForm))
        // 第二种写法:借助lodash的cloneDeep深拷贝方法
        let copyForm = _.cloneDeep(this.addForm)
        // 然后再处理goods_cat字段
        copyForm.goods_cat = copyForm.goods_cat.join(',')
    });            
}
let data1 = {
  name:'uu盘',
  arr:{
    flag:false
  }
}
let data2 = {
  name:'你好',
  arr:[{id:1,bool:false},{id:2,bool:true}]
}
let obj = Object.assign(data2,data1)
console.log(obj);

在这里插入图片描述

let data1 = {
  name:'uu盘',
  arr:{
    flag:false
  }
}
let data2 = {
  name:'你好',
  arr:[{id:1,bool:false},{id:2,bool:true}]
}
// _.assign,它会递归合并
let obj = _.merge(data2,data1)
console.log(obj);

在这里插入图片描述

8. 使用echarts表格

1. 下载插件

cnpm i echarts@4.6.0 -S
最新版本可能会有点问题

2. 引入

import echarts from "echarts";

3. 准备好dom,初始化echarts实例

<div id="table"></div>
<script>
import _ from 'lodash'
import echarts from "echarts";
import { getData } from "@/api/reports.js";
export default {
  data() {
    return {
      options: {
        title: {
          text: "用户来源",
        },
        tooltip: {
          trigger: "axis",
          axisPointer: {
            type: "cross",
            label: {
              backgroundColor: "#E9EEF3",
            },
          },
        },
        grid: {
          left: "3%",
          right: "4%",
          bottom: "3%",
          containLabel: true,
        },
        xAxis: [
          {
            boundaryGap: false,
          },
        ],
        yAxis: [
          {
            type: "value",
          },
        ],
      },
    };
  },
  async mounted() {
    // 初始化一个echarts实例
    var myChart = echarts.init(document.getElementById("table"));
    let { data: res } = await getData();
    if (res.meta.status != 200) return this.$message.error(res.meta.msg);
    const result = _.merge(res.data, this.options)
    myChart.setOption(result)
  },
};
</script>

<style lang='scss' scoped>
#table {
  width: 750px;
  height: 400px;
}
</style>

简单说几个配置项,了解更多可以去echarts官网

title标题组件

title.show = true 是否显示标题组件
title.text = ‘’ 主标题文本,支持使用\n换行
title.link = ‘’ 主标题文本超链接

title: {
	text:'标题',
	link: 'https://www.baidu.com',
}
点击标题可以跳转到百度

grid直角坐标系网格

grid.left/right/top/bottom grid 组件离容器左/右/上/下的距离。
grid.containLabel 它的值为true时为了防止标签溢出

xAxisX轴

xAxis.type 坐标轴的类型 值为‘value’数值轴,适用于连续数据
xAxis. boundaryGap 坐标轴两边留白
xAxis. boundaryGap = true
在这里插入图片描述
xAxis. boundaryGap = false
在这里插入图片描述

yAxisY轴(与X轴差不多)

tooltip提示框组件

tooltip. trigger = ‘’ 触发类型 item(数据项图形触发) axis(坐标轴触发) none(什么都不触发)
tooltip. axisPointer 是一个对象
tooltip. axisPointer.type = “cross” 会自动显示axisPointer的label,label默认不显示(也就是默认只显示指示线)
在这里插入图片描述

legend图例组件

legend.data 图例的数据数组
在这里插入图片描述

series

series.type 类型
series.name 系列名称,用于tooltip的显示
series.data 系列中的数据内容数组
series.stack 数据堆叠,同个类目轴上系列配置相同的stack值后,后一个系列的值会在前一个系列的值上相加。

9. vue后台管理系统打包上线到node

详细请看vue后台管理系统打包上线到node

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值