电商后台管理系统--笔记

发布于:2023-01-21 ⋅ 阅读:(1084) ⋅ 点赞:(0)

电商后台管理系统–笔记

线上预览地址==>>http://52xhl.top/admin/

线上后台接口==>>http://www.52xhl.top:8889/api/private/v1/

小破站教程===>>https://www.bilibili.com/video/BV1x64y1S7S7

gitee仓库 ===>>https://gitee.com/elfin-chen/shop

后台api接口==>>http://52xhl.top/markdown/api.html

配置工作

router 配置使用

  • router>index.js中 引入
import Vue from "vue";
import VueRouter from "vue-router";
  • 声明变量 方便路由懒加载
//懒加载
const Login = () => import( /* webpackChunkName: "login_home_welome" */ '../views/login.vue')
const Home = () => import( /* webpackChunkName: "login_home_welome" */ '../views/home.vue')
const Welcome = () => import( /* webpackChunkName: "login_home_welome" */ '../views/welcome.vue')
  • 具体设置方法
const routes = [{
    path: "/", //访问更目录
    redirect: "/login", //地址重定向到/home
  },
  {
    path: "/login",
    component: Login,
  },
  {
    path: "/home",
    component: Home,
    redirect: '/welcome',
    children: [{
        path: "/welcome",
        component: Welcome,
      },
      {
        path: "/users",
        component: Users,
      },],
  },
];
  • 前置路由守卫
router.beforeEach((to, from, next) => {
  if (to.path !== '/login') {
    //判断是否登录
    if (sessionStorage.getItem('token')) {
      next();
    } else {
      Vue.prototype.$message.error('请先登录');
      next('/login?redirect=' + to.path);
    }
  } else {
    next();
  }
})
  • router使用方法
//query 是地址里 域名/后面的内容 解析成对象
this.$route.query.redirect
//跳转
this.$router.push({ path: '/home' })
this.$router.push('/goods/add');

axios配置使用

  • vue ui中安装 main.js导入
//axios
import axios from "axios";
  • 配置请求根路径
axios.defaults.baseURL = 'http://127.0.0.1:8888/api/private/v1/
  • 请求前守卫
//挂载token
axios.interceptors.request.use(config => {
  NProgress.start();
  // 在发送请求之前做些什么
  config.headers.Authorization = window.sessionStorage.getItem('token');
  return config;
})
  • 请求后守卫
axios.interceptors.response.use(config => {
  NProgress.done();
  return config
})
  • 把axios挂载到vue的原型对象上
Vue.prototype.$http = axios
  • 请求方式
 //post
 let { data: res } = await this.$http.post("login", this.login);

element ui 配置使用

  • vue ui中安装(按需加载) main.js导入
import "./plugins/element.js";
  • plugins/element.js配置按需加载项
import Vue from "vue";
import { Button,Form,Message,MessageBox, } from "element-ui";
Vue.use(Button);
Vue.use(Form);
//消息提示挂载到原型对象
Vue.prototype.$message = Message;
Vue.prototype.$confirm = MessageBox.confirm;

iconfont 配置使用

  • https://www.iconfont.cn/ 下载素材 把压缩包解压到项目目录 assets/font/....
  • main.js引入css
//iconfont
import "./assets/font/iconfont.css";
  • 使用时直接添加需要的图片类名 比如 iconfont icon-denglu

global全局样式使用

  • 创建文件assets/css/global.css
  • main.js引入全局样式
//全局css
import "./assets/css/global.css";

moment配置使用

  • 导入
import moment from 'moment';
  • 使用方法
moment(parseInt(v)).format('YYYY-MM-DD')

lodash配置使用

  • 导入
import _ from 'lodash';
  • 使用

    • 深拷贝
    let cat = _.cloneDeep(this.basicinfo_data.classification)	
    
    • 合并
    option = _.merge(res.data, option)
    

vue-quill-editor配置使用

  • 导入
//富文本
import VueQuillEditor from 'vue-quill-editor'

import 'quill/dist/quill.core.css' // import styles
import 'quill/dist/quill.snow.css' // for snow theme
import 'quill/dist/quill.bubble.css' // for bubble theme

Vue.use(VueQuillEditor)
  • 使用
<!-- 富文本 -->
<quill-editor ref="myQuillEditor" v-model="supertxt" />

vue-table-with-tree-grid配置使用

  • 导入
//vue-table
import ZkTable from 'vue-table-with-tree-grid'
Vue.component('tree-table', ZkTable)
  • 使用
<tree-table style="margin: 15px 0;" :border="true" show-index index-text="#" :expand-type="false" :selection-type="false" :data="tableData" :columns="columns">
---
</tree-table>

echarts 配置使用

  • 导入
import * as echarts from 'echarts'
  • 准备一个盒子
<div ref="main" style="width: 600px;height:400px;"></div>
  • 数据操作
var myChart = echarts.init(this.$refs.main);
option = _.merge(res.data, option) //option合并了
myChart.setOption(option);

总结知识点

Container 布局容器

image-20220811132757675

  • width 设置侧边栏宽度
<el-container class="box">
	 <el-header>
	 </el-header>
 	 <el-container class="content">
		  <el-aside :width="!flg ? '200px' : '64px'">
 		  </el-aside>
 		  <el-main>
        <router-view></router-view>
        </el-main>
     </el-container>
</el-container>

Form 表单

image-20220811154720872

  • ref 方便通过this.$refs的方式使用form表单的方法 比如
    • validate 表单校验 this.$refs.loginref.validate(v => {}) 返回校验结果在回调函数内操作
    • resetFields 重置表单 this.$refs.loginref.resetFields()
  • rules 表单校验规则 放在data的return里
  • rulesprop 绑定变量名要相同
  • model 表单绑定的对象
  • label-width 表单左侧的文字区域 宽度
  • <el-form-item prop="username"> 继承绑定 rules校验规则 : model对象中的具体属性
  • <el-button type="primary" @click="dl">登录</el-button> type指定了按钮颜色
<el-form ref="loginref" :rules="rules" :model="login" class="form" label-width="0">
  <el-form-item prop="username">
    <el-input prefix-icon="iconfont icon-denglu" v-model="login.username">
    </el-input>
  </el-form-item>
  <el-form-item prop="password">
    <el-input type="password" prefix-icon="iconfont icon-mima" v-model="login.password"></el-input>
    </el-form-item>
  <el-form-item class="btns">
    <el-button type="primary" @click="dl">登录</el-button>
    <el-button type="info" @click="cz">重置</el-button>
  </el-form-item>
</el-form>

数据

	login: {
        username: "admin",
        password: "123456",
      },
      rules: {
        username: [
          { required: true, message: '请输入用户名', trigger: 'blur' },
          { min: 3, max: 10, message: '长度在 3 到 10 个字符', trigger: 'blur' }
        ],
        password: [
          { required: true, message: '请输入密码', trigger: 'blur' }
        ],
      }
  • 自定义表单校验规则
//自定义校验表单
    let checkEmail = (rule, value, callback) => {
      if (!value) {
        return callback(new Error('不能为空'));
      }
      if (value.indexOf('@') == -1) {
        callback(new Error('请输入正确的邮箱'));
      } else {
        callback();
      }
    };
    
email: [
          { validator: checkEmail, trigger: 'blur' }
        ]

Message 消息提示

image-20220811154756982

  • error是错误类型,还有很多类型 和button的type一样
this.$message.error(res.meta.msg);

sessionStorage 本地存储

image-20220811154833110

  • 写入token
sessionStorage.setItem('token', res.data.token);
  • 读取token
sessionStorage.getItem('token');
  • 移出token
sessionStorage.removeItem('token')

NavMenu 导航菜单

image-20220811155022491

  • el-menu 是整个menu el-submenu 是子菜单
  • router 启用router模式 以 index 作为 path 进行路由跳转
  • collapse 是否折叠 collapse-transition 折叠动画
  • unique-opened 始终只保持一个菜单展开
  • background-color text-color active-text-color 背景颜色 文字颜色 选中文字颜色
  • default-active 当前激活高亮的的 index
    • 子菜单
    • index 是当前的索引 唯一标识 用来跳转
    • <template slot="title"> 菜单的标题 也就是菜单的内容
<el-menu :router="true" :collapse="flg" :collapse-transition="false" :unique-opened=true
    background-color="#333744" text-color="#fff" active-text-color="#409eff"
    :default-active="$route.path == '/goods/add' ? '/goods' : $route.path">
    <!-- 一级菜单 -->
    <el-submenu :index="item.path" v-for="(item, index) in asideList" :key="item.id">
        <template slot="title">
            <i :class="'iconfont ' + iconImg[index]"></i>
            <span>{{ item.authName }}</span>
        </template>
        <!-- 二级菜单 -->
        <el-menu-item :index="'/' + item2.path" v-for="(item2) in item.children" :key="item2.id">
            <template slot="title">
                <i class="el-icon-menu"></i>
                <span>{{ item2.authName }}</span>
            </template>
        </el-menu-item>
    </el-submenu>
</el-menu>

Breadcrumb 面包屑

image-20220811154954276

  • :to="{ path: '/home' }" 指定跳转路径
	 <!-- 面包屑 -->
    <el-breadcrumb separator-class="el-icon-arrow-right">
      <el-breadcrumb-item :to="{ path: '/home' }">首页</el-breadcrumb-item>
      <el-breadcrumb-item>用户管理</el-breadcrumb-item>
      <el-breadcrumb-item>用户列表</el-breadcrumb-item>
    </el-breadcrumb>

Card 卡片

image-20220811154646571

 <el-card class="box-card"></el-card>

Layout 布局

image-20220811155251042

  • 栅格布局 宽度分为24份 高度不限制
  • :span="8" 占用8份
  • :gutter="20" 每一个格子有多少间隔
<!-- 栅格布局 每一行col总共24份 当前占8份  gutter每一格中间的空隙 -->
<el-row :gutter="20">
  <el-col :span="8">
    <div class="grid-content bg-purple">
      <!-- 一个输入框  clear清空触发事件 -->
      <el-input @clear="init" clearable v-model="gettableinfo.query" placeholder="请输入内容" class="input-with">
        <!-- slot="append" 尾部的插槽 -->
        <el-button @click="init" slot="append" icon="el-icon-search"></el-button>
      </el-input>
    </div>
  </el-col>
  <!-- 当前栅格占4 -->
  <el-col :span="4">
    <div class="grid-content bg-purple">
      <el-button @click="adduser_dialog = true" type="primary">添加用户</el-button>
    </div>
  </el-col>
</el-row>

Button 按钮

  • 第一行 type 类型
  • 第二行 plain 朴素
  • 第三行 round 圆角
  • 第四行 circle 圆形
  • size 尺寸
  • icon="el-icon-search" 图标

image-20220811155502699

  <el-button>默认按钮</el-button>
  <el-button type="primary">主要按钮</el-button>
  <el-button type="success">成功按钮</el-button>
  <el-button type="info">信息按钮</el-button>
  <el-button type="warning">警告按钮</el-button>
  <el-button type="danger">危险按钮</el-button>

Input 输入框

  • prefix-icon头部图标 suffix-icon尾部图标

  • clearable 是否显示清空的x @clear 点击x的清空事件

  • slot="append" 尾部插槽 按钮

  • disabled 禁用

<el-input @clear="init" clearable v-model="gettableinfo.query" placeholder="请输入内容" class="input-with">
   <!-- slot="append" 尾部的插槽 -->
   <el-button @click="init" slot="append" icon="el-icon-search"></el-button>
</el-input>

Switch 开关

image-20220811162224308

  • @change 状态发生变化时的回调函数
<el-switch @change="switch_value(scope.row)" v-model="scope.row.mg_state"></el-switch>

Tooltip 文字提示

image-20220811162347487

  • enterable 鼠标是否可进入到 tooltip 中
  • effect 提示的主题样式
  • content 提示的内容
<el-tooltip :enterable="false" class="item" effect="dark" content="分配权限" placement="top">
  <el-button @click="allot(scope.row)" size="mini" type="warning" icon="el-icon-setting"></el-button>
</el-tooltip>

Tag 标签

image-20220811165459130

  • closable 是否显示xx
  • @close 点击xx的事件
  • type="primary" 样式 和 button一样
  • disable-transitions 禁用渐变动画
  • {{ item1.authName }} 标签内容
<el-tag @close="removtag3(props.row, item1.id)" closable type="primary" disable-transitions>
  {{ item1.authName }}
</el-tag>

动态编辑标签

1

<el-tag v-for="(tag, index) in props.row.attr_vals" :key="'tag' + index" closable
  :disable-transitions="true" @close="handleClose(props.row.attr_vals, tag, props.row)"
  :style="[{ marginLeft: 25 + 'px' }]">
  {{ tag }}
</el-tag>
<el-input style="margin-left: 25px;width: 100px;" class="input-new-tag" v-if="props.row.inputVisible"
  v-model="props.row.taginput" ref="taginput" size="small"
  @keyup.enter.native="handleInputConfirm(props.row)" @blur="handleInputConfirm(props.row)">
</el-input>
<el-button style="margin-left: 25px;" v-else class="button-new-tag" size="small"
  @click="tagbtn(props.row)">+ New Tag</el-button>

Table 表格

image-20220811160743588

  • :data 表格绑定的数据对象
  • border 边框 stripe 隔行变色
  • label 表中每一个属性的表头名字
  • type="index" 表示当前列是索引
  • prop="username" 表示数据绑定的表格数据 data 中的username属性
  • <template slot-scope="scope"> 插槽 自定义内容 scope.row 是当前行数据
  • <el-table-column type="expand"> 该插槽时展开后 看到的内容
<el-table :data="tableData" :border="true" stripe style="width: 100%">
  <!-- 每一行 index表示当前行是索引-->
  <el-table-column label="#" type="index"></el-table-column>
  <!-- prop="username" 这个属性表示表格内容采用table的 :data对象内的对应属性-->
  <el-table-column label="姓名" prop="username"></el-table-column>
  <el-table-column label="邮箱" prop="email"></el-table-column>
  <el-table-column label="电话" prop="mobile"></el-table-column>
  <el-table-column label="角色" prop="role_name"></el-table-column>
  <el-table-column label="状态" prop="mg_state">
    <!-- 自定义表格内容 插槽 插槽传入的数据在scope.row内-->
    <template slot-scope="scope">
      <!-- 开关触发事件 change -->
      <el-switch @change="switch_value(scope.row)" v-model="scope.row.mg_state">
      </el-switch>
    </template>
  </el-table-column>
  <el-table-column label="操作">
    <!-- eslint-disable-next-line  去除报错-->
    <template slot-scope="scope">
      <el-button @click="setitem(scope.row)" size="mini" type="primary" icon="el-icon-edit"></el-button>
      <el-button @click="deleteitem(scope.row.id)" size="mini" type="danger" icon="el-icon-delete"></el-button>
      <!-- 
        tooltip 文字提示 enterable鼠标不能进入到提示区域
        effect 主题 content文字内容  placement悬浮提示到哪
      -->
      <el-tooltip :enterable="false" class="item" effect="dark" content="分配权限" placement="top">
        <el-button @click="allot(scope.row)" size="mini" type="warning" icon="el-icon-setting"></el-button>
      </el-tooltip>
    </template>
  </el-table-column>
</el-table>

Pagination 分页器

image-20220811163403894

  • @size-change 每页条数变化时触发
  • @current-change 当前页数变化时触发
  • current-page 当前页数
  • page-sizes 每页显示个数选择器的选项设置
  • page-size 每一页显示条目个数
  • layout 关于分页器的各种工具
  • total 数据总条数 数量
<el-pagination @size-change="handleSizeChange" @current-change="handleCurrentChange"
  :current-page="gettableinfo.pagenum" :page-sizes="[2, 5, 10]" :page-size="gettableinfo.pagesize"
  layout="total, sizes, prev, pager, next, jumper" :total="total">
</el-pagination>

Dialog 对话框

image-20220811163503656

  • title 对话框标题
  • @close 对话框关闭事件
  • :visible.sync 控制对话框是否显示的变量
  • slot="footer" 底部插槽
<el-dialog title="收货地址" @close="set_close" :visible.sync="setuser_dialog">
  <!-- 插槽 footer 弹窗尾部-->
  <div slot="footer" class="dialog-footer">
    <el-button @click="setuser_dialog = false">取 消</el-button>
    <el-button type="primary" @click="set_ok()">确 定</el-button>
  </div>
</el-dialog>

MessageBox 弹框

image-20220811164051614

  • 直接函数调用就能弹出
deleteitem(id) {
  this.$confirm('此操作将永久删除, 是否继续?', '提示', {
    confirmButtonText: '确定',
    cancelButtonText: '取消',
    type: 'warning'
  }).then(async () => {
    //删除操作
    this.$message.success('删除成功');
  }).catch(() => {
    //取消操作
    // this.$message({
    //   type: 'info',
    //   message: '已取消删除'
    // });
  });
},

Tree 树形控件

image-20220811170556834

  • ref 绑定后方便使用他的事件

    • this.$refs.tree.getCheckedKeys() 返回目前被选中的节点的 key 所组成的数组
    • this.$refs.tree.getHalfCheckedKeys() 返回目前半选中的节点的 key 所组成的数组
  • data 是绑定的数据 []

  • show-checkbox 显示复选框

  • node-key 节点的key

  • default-expand-all 是否默认展开所有节点

  • default-checked-keys 默认勾选的节点的 key 的数组

  • props 配置选项

  • defaultProps: {
      children: 'children',
      label: 'authName'
    },
    
<el-tree ref="tree" :data="allot_role_data" show-checkbox node-key="id" default-expand-all
	:default-checked-keys="efaultCheckedKeys" :props="defaultProps">
</el-tree>
  • 遍历三级菜单(打勾的) 当前数据是三级子菜单树的数据 遍历成数组
    //遍历三级菜单 打钩的
    foreachCheckedKeys(node) {
      if (!node.children) {
        return this.efaultCheckedKeys.push(node.id)
      }
      node.children.forEach(item => {
        this.foreachCheckedKeys(item)
      });
    },

Alert 警告

image-20220811182042545

  • center 居中
  • title 标题
  • closable 是否可关闭
  • type 类型
  • show-icon 显示图标
<el-alert center style="margin-bottom: 15px;;" title="添加商品信息" :closable="false" type="info" show-icon>
</el-alert>

Steps 步骤条

image-20220811182331282

  • align-center 居中
  • active 当前索引 数字类型
  • finish-status 完成步骤的样式
<el-steps align-center style="width: 100%;" :active="active - 0" finish-status="success">
    <el-step title="基本信息"></el-step>
    <el-step title="商品参数"></el-step>
    <el-step title="商品属性"></el-step>
    <el-step title="商品图片"></el-step>
    <el-step title="商品内容"></el-step>
    <el-step title="完成"></el-step>
</el-steps>

Tabs 标签页

image-20220811182612970

  • :before-leave 切换标签之前的钩子
  • @tab-click tab 被选中时触发
  • tab-position 位置
  • v-model 点击会吧name的值给绑定
<el-tabs :before-leave="beforeLeave" @tab-click="tabClick" v-model="active" style="margin-top: 25px;"
    tab-position="left">
                    <el-tab-pane name="0" label="基本信息">
                    ---
                    </el-tab-pane>
                    <el-tab-pane name="1" label="商品参数">
                    ---
                    </el-tab-pane>
                    <el-tab-pane name="2" label="商品属性">
                    ---
                    </el-tab-pane>
                    <el-tab-pane name="3" label="商品图片">
                    ---
                    </el-tab-pane>
                    <el-tab-pane name="4" label="商品内容">
                    ---
                    </el-tab-pane>
</el-tabs>

Cascader 级联选择器

image-20220811183146490

  • clearable 清除按钮
  • options 数据源
  • props 数据源的配置
selectprop: {
                label: 'cat_name',
                value: 'cat_id',
                children: 'children',
                expandTrigger: 'hover',
            },
  • @change 值变化触发
<el-cascader style="width: 100%;" clearable v-model="basicinfo_data.classification"
    :options="selectoptions" :props="selectprop" @change="handleChange">
</el-cascader>

Checkbox 多选框

image-20220811183813648

  • el-checkbox-groupv-model绑定一个数组
  • label 复选框的值
<el-checkbox-group v-model="item.attr_vals">
    <el-checkbox style="margin: 0 5px 0 0 ;" v-for="(v, i) in item.attr_vals"
        :key="'checkbox_in' + i" :border="true" :label="v">
    </el-checkbox>
</el-checkbox-group>

Upload 上传

image-20220811184137959

  • :on-remove 文件列表移除文件时的钩子
  • on-success 文件上传成功时的钩子
  • headers 设置上传的请求头部
  • action 上传地址
  • on-preview 点击文件列表中已上传的文件时的钩子
  • list-type 文件列表的类型
<el-upload :on-remove="onRemove" :on-success="onSuccess" :headers="headers"
    action="http://127.0.0.1:8888/api/private/v1/upload" :on-preview="handlePreview"
    list-type="picture">
    <el-button size="small" type="primary">点击上传</el-button>
</el-upload>

tree-table树形展开表

vue-table-with-tree-grid

image-20220811191517371

  • show-index 是否显示索引

  • index-text 索引的标题文字

  • expand-type 是否为展开行类型表格

  • selection-type 是否为多选类型表格

  • columns 配置项

    • columns: [
              {
                label: '分类名称',
                prop: 'cat_name',
              },
              {
                label: '是否有效',
                align: 'center',
                type: 'template',
                template: 'isok',
              },
              {
                label: '排序',
                align: 'center',
                type: 'template',
                template: 'sort',
              },
              {
                label: '操作',
                align: 'center',
                type: 'template',
                template: 'operation',
              },
            ],
      
<tree-table style="margin: 15px 0;" :border="true" show-index index-text="#" :expand-type="false"
  :selection-type="false" :data="tableData" :columns="columns">
  <template slot="isok" slot-scope="scope">
    <i style="color:lightgreen" class="el-icon-success" v-if="scope.row.cat_deleted === false"></i>
    <i style="color:red" class="el-icon-error" v-else></i>
  </template>
  <template slot="sort" slot-scope="scope">
    <el-tag v-if="scope.row.cat_level == 0">一级</el-tag>
    <el-tag v-else-if="scope.row.cat_level == 1" type="success">二级</el-tag>
    <el-tag v-else type="warning">三级</el-tag>
  </template>
  <template slot="operation" slot-scope="scope">
    <el-button @click="set_btn(scope.row)" size="mini" type="primary" icon="el-icon-edit">编辑
    </el-button>
    <el-button @click="delete_btn(scope.row.cat_id)" size="mini" type="danger" icon="el-icon-delete">删除
    </el-button>
  </template>
</tree-table>

项目优化

nprogress添加进度条效果

  • 导入
//导入nprogress
import NProgress from 'nprogress'
import 'nprogress/nprogress.css'
  • 使用 在axios发起请求前和后设置进度条开始结束

NProgress.start(); NProgress.done();

axios.interceptors.request.use(config => {
  NProgress.start();
  // 在发送请求之前做些什么
  config.headers.Authorization = window.sessionStorage.getItem('token');
  return config;
})
axios.interceptors.response.use(config => {
  NProgress.done();
  return config
})

移除所有的console

babel-plugin-transform-remove-console

image-20220811200252037

chainWebpack自定义打包入口

  • 把main.js拆成生产和开发环境 main-prod.js main-dev.js

image-20220811201543750

通过extemals加载外部CDN资源

image-20220811201928746

  • vue.config.js中生产环境配置
config.set('externals', {
  vue: 'Vue',
  'vue-router': 'VueRouter',
  axios: 'axios',
  lodash: '_',
  echarts: 'echarts',
  nprogress: 'NProgress',
  'vue-quill-editor': 'VueQuillEditor',
  "moment": "moment",
})
  • 通过externals 加载外部cdn资源
<!-- nprogress 的样式表文件 -->
    <link rel="stylesheet" href="https://cdn.staticfile.org/nprogress/0.2.0/nprogress.min.css" />
    <!-- 富文本编辑器 的样式表文件 -->
    <link rel="stylesheet" href="https://cdn.staticfile.org/quill/1.3.4/quill.core.min.css" />
    <link rel="stylesheet" href="https://cdn.staticfile.org/quill/1.3.4/quill.snow.min.css" />
    <link rel="stylesheet" href="https://cdn.staticfile.org/quill/1.3.4/quill.bubble.min.css" />
    <!-- element-ui 的样式表文件 -->
    <link rel="stylesheet" href="https://unpkg.com/element-ui/lib/theme-chalk/index.css">


    <script src="https://cdn.staticfile.org/vue/2.6.3/vue.min.js"></script>
    <script src="https://cdn.bootcdn.net/ajax/libs/vue-router/3.2.0/vue-router.min.js"></script>
    <script src="https://cdn.staticfile.org/axios/0.19.2/axios.min.js"></script>
    <script src="https://cdn.staticfile.org/lodash.js/4.17.15/lodash.min.js"></script>
    <script src="https://cdn.staticfile.org/echarts/4.7.0/echarts.min.js"></script>
    <script src="https://cdn.staticfile.org/nprogress/0.2.0/nprogress.min.js"></script>
    <!-- 富文本编辑器的 js 文件 -->
    <script src="https://cdn.staticfile.org/quill/1.3.4/quill.min.js"></script>
    <script src="https://cdn.jsdelivr.net/npm/vue-quill-editor@3.0.6/dist/vue-quill-editor.js"></script>

    <!-- element-ui 的 js 文件 -->
    <!-- <script src="https://cdn.staticfile.org/element-ui/2.13.0/index.js"></script> -->

    <!-- moment -->
    <script src="https://cdn.bootcss.com/moment.js/2.20.1/moment.min.js"></script>
    <script src="https://cdn.bootcss.com/moment.js/2.20.1/locale/zh-cn.js"></script>
  • 配置好后 main-prod.js中重复引入的配置文件就可以注释了

自定制首页内容

生产环境 true

      config.plugin('html').tap(args => {
        args[0].isProd = true
        return args
      })

开发环境 false

      config.plugin('html').tap(args => {
        args[0].isProd = false
        return args
      })

index.html中配置

  <title><%= htmlWebpackPlugin.options.isProd ? '' : 'dev - ' %>电商后台管理系统</title>
  <% if (htmlWebpackPlugin.options.isProd) {%>
  //引入的cdn
  <% } %>

index.html中

<head>
  <meta charset="utf-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width,initial-scale=1.0">
  <link rel="icon" href="<%= BASE_URL %>favicon.ico">
  <title><%= htmlWebpackPlugin.options.isProd ? '' : 'dev - ' %>电商后台管理系统</title>
  <% if (htmlWebpackPlugin.options.isProd) {%>

    <!-- nprogress 的样式表文件 -->
    <link rel="stylesheet" href="https://cdn.staticfile.org/nprogress/0.2.0/nprogress.min.css" />
    <!-- 富文本编辑器 的样式表文件 -->
    <link rel="stylesheet" href="https://cdn.staticfile.org/quill/1.3.4/quill.core.min.css" />
    <link rel="stylesheet" href="https://cdn.staticfile.org/quill/1.3.4/quill.snow.min.css" />
    <link rel="stylesheet" href="https://cdn.staticfile.org/quill/1.3.4/quill.bubble.min.css" />
    <!-- element-ui 的样式表文件 -->
    <link rel="stylesheet" href="https://unpkg.com/element-ui/lib/theme-chalk/index.css">


    <script src="https://cdn.staticfile.org/vue/2.6.3/vue.min.js"></script>
    <script src="https://cdn.bootcdn.net/ajax/libs/vue-router/3.2.0/vue-router.min.js"></script>
    <script src="https://cdn.staticfile.org/axios/0.19.2/axios.min.js"></script>
    <script src="https://cdn.staticfile.org/lodash.js/4.17.15/lodash.min.js"></script>
    <script src="https://cdn.staticfile.org/echarts/4.7.0/echarts.min.js"></script>
    <script src="https://cdn.staticfile.org/nprogress/0.2.0/nprogress.min.js"></script>
    <!-- 富文本编辑器的 js 文件 -->
    <script src="https://cdn.staticfile.org/quill/1.3.4/quill.min.js"></script>
    <script src="https://cdn.jsdelivr.net/npm/vue-quill-editor@3.0.6/dist/vue-quill-editor.js"></script>

    <!-- element-ui 的 js 文件 -->
    <!-- <script src="https://cdn.staticfile.org/element-ui/2.13.0/index.js"></script> -->

    <!-- moment -->
    <script src="https://cdn.bootcss.com/moment.js/2.20.1/moment.min.js"></script>
    <script src="https://cdn.bootcss.com/moment.js/2.20.1/locale/zh-cn.js"></script>

    <% } %>
</head>

vue.config.js

module.exports = {
  publicPath: "./", //打包时加上
  productionSourceMap: false,
  // 发布模式
  chainWebpack: config => {
    config.when(process.env.NODE_ENV === 'production', config => {
      config.entry('app').clear().add('./src/main-prod.js')

      config.set('externals', {
        vue: 'Vue',
        'vue-router': 'VueRouter',
        axios: 'axios',
        lodash: '_',
        echarts: 'echarts',
        nprogress: 'NProgress',
        'vue-quill-editor': 'VueQuillEditor',
        "moment": "moment",
      })

      config.plugin('html').tap(args => {
        args[0].isProd = true
        return args
      })
    })

    // 开发模式
    config.when(process.env.NODE_ENV === 'development', config => {
      config.entry('app').clear().add('./src/main-dev.js')

      config.plugin('html').tap(args => {
        args[0].isProd = false
        return args
      })
    })
  }
}

实现路由懒加载

image-20220811203252018

‘@babel/plugin-syntax-dynamic-import’

  • /**/ 中间的内容 可以把路由分组 打包到一起加载

其他

小知识

  • 使用对象赋值的使用 其实赋值了一个引用地址 修改了值会连带着改变

  • 接口请求来之后 数据有问题可以自己处理或者添加,到对象上 和上游下游一个道理

  • 比如 row传下来可以绑定东西上去 比如res.data可以绑定东西上去

  • 这段代码可以去除报错 <!-- eslint-disable-next-line -->

  • 字符串 ‘0’ - 0 = 0

用到的方法

map

 .this.options = res.data.map((v, i, arr) => {
        return {
          value: v.id,
          label: v.roleName,
        };
      });

递归循环

//遍历三级菜单 打钩的
    foreachCheckedKeys(node) {
      if (!node.children) {
        return this.efaultCheckedKeys.push(node.id)
      }
      node.children.forEach(item => {
        this.foreachCheckedKeys(item)
      });
    },

forEach

res.data.forEach((item) => {
      item.attr_vals = item.attr_vals ? item.attr_vals.split(' ') : []
      item.checkbox = true;
    })

findIndex

//找到
            let path = file.response.data.tmp_path;
            let weizhi = this.pics.findIndex((item) => {
                return item.pic === path
            });

splice

 //删除
            this.pics.splice(weizhi, 1)

join

attr_value: item.attr_vals.join(' ')

split

item.attr_vals = item.attr_vals ? item.attr_vals.split(' ') : []

indexOf

 //当前点击的索引
      let listindex = list.indexOf(tag)

$nextTick

this.$nextTick(() => {
        this.$refs.taginput.$refs.input.focus()
      })

深拷贝

//深拷贝
    deepcopy(copy, obj) {
      //获取属性 判断是数组?是对象?还是简单数据类型
      for (let k in obj) {
        if (obj[k] instanceof Array) {
          copy[k] = [];
          this.deepcopy(copy[k], obj[k]);
        } else if (obj[k] instanceof Object) {
          copy[k] = {};
          this.deepcopy(copy[k], obj[k]);
        } else {
          copy[k] = obj[k];
        }
      }
    },
本文含有隐藏内容,请 开通VIP 后查看

网站公告

今日签到

点亮在社区的每一天
去签到