电商后台管理系统项目总结

720 阅读2分钟

1.项目的开发环境

开发依赖:

"dependencies": {
   "axios": "^0.21.1",
   "babel-plugin-transform-remove-console": "^6.9.4",
   "core-js": "^3.6.5",
   "echarts": "^5.1.2",
   "element-ui": "^2.4.5",
   "moment": "^2.29.1",
   "nprogress": "^0.2.0",
   "quill": "^1.3.6",
   "vue": "^2.6.11",
   "vue-quill-editor": "^3.0.6",
   "vue-router": "^3.2.0",
   "vue-table-with-tree-grid": "^0.2.4",
   "vuex": "^3.4.0"
 },

element-ui全局安装

   vue add element-ui   //在终端输入

1609579-20190601175931058-1913620039.png
这里可以看到让我们选择全部引入还是按需引入,此时我们选择按需引入 Import on demand 1609579-20190601180054830-1746260489.png\

然后选择zh-CN,这时候我们可以看到此处多了一个plugins的文件夹,里面有一个element.js的文件,并main.js
中多了一个import的内容。然后如果我们仔细观察的话会发现其实babel.config.js也是注入了相关内容的。

1609579-20190601180322290-1609951225.png

1609579-20190601180801295-1201526341.png

element-ui ----> Form 表单

<template>
  <el-form :model="ruleForm" :rules="rules" ref="ruleForm" label-width="100px" class="demo-ruleForm">
    <el-form-item label="活动名称" prop="name">
      <el-input v-model="ruleForm.name"></el-input>
    </el-form-item>
    <el-form-item>
      <el-button type="primary" @click="submitForm('ruleForm')">立即创建</el-button>
      <el-button @click="resetForm('ruleForm')">重置</el-button>
    </el-form-item>
  </el-form>
</template>
<script>
export default {
  data() {
    return {
      ruleForm: {
        name: ''
      },
      rules: {
        name: [
          { required: true, message: '请输入活动名称', trigger: 'blur' },
          { min: 3, max: 5, message: '长度在 3 到 5 个字符', trigger: 'blur' }
        ]
      }
    }
  },
  methods: {
    submitForm(formName) {
      this.$refs[formName].validate((valid) => {
        if (valid) {
          // 验证成功执行此代码块
          alert('submit!')
        } else {
          // 验证失败执行此代码块
          console.log('error submit!!')
          return false
        }
      })
    },
    resetForm(formName) {
     // 重置表单
      this.$refs[formName].resetFields()
    }
  }
}
</script>

ruleForm: input双向绑定的数据
rules: 表单的验证规则
prop: 为需校验的字段名

element-ui ----> Cascader 级联选择器

<el-cascader v-model="value" :options="options" @change="handleChange"></el-cascader>

options: 可选项数据源,键名可通过 Props 属性配置

Props:

expandTrigger: 次级菜单的展开方式 可选择click/hover 默认'click'
checkStrictly: 是否严格的遵守父子节点不互相关联
value: 指定选项的值为选项对象的某个属性值
label: 指定选项标签为选项对象的某个属性值
children: 指定选项的子选项为选项对象的某个属性值

element-ui ----> Pagination 分页

<el-pagination 
  @size-change="handleSizeChange" 
  @current-change="handleCurrentChange"
  :current-page="currentPage4" 
  :page-sizes="[100, 200, 300, 400]" 
  :page-size="100" layout="total, sizes, prev, pager, next, jumper" 
  :total="400">
</el-pagination>

size-change和current-change: 事件来处理页码大小和当前页变动时候触发的事件
page-sizes: 接受一个整型数组,数组元素为展示的选择每页显示个数的选项,[100, 200, 300, 400]表示四个选项,每页显示 100 个,200 个,300 个或者 400 个数据
total: 表示数据的总数

2. 登录界面的实现

当用户点击了登录按钮时,进行数据请求,同时将登录成功之后的 token,保存到客户端的 sessionStorage 中,然后进行路由跳转.同时在axios的请求拦截器中携带token.最后再使用路由的全局前置守卫进行读取sessionStorage里面存储的进行判断是否有值,有值进行跳转,否则返回登录页面.

登录按钮的点击事件

 submitForm(formName) {
   this.$refs[formName].validate((valid) => {
     if (!valid) return
     this.$http.post('login', this.ruleForm).then(res => {
       console.log(res.data)
       if (res.data.meta.status !== 200) return this.$message.error('登录失败!')
       this.$message.success('登录成功')
       // 1. 将登录成功之后的 token,保存到客户端的 sessionStorage 中
       // 1.1 项目中出了登录之外的其他API接口,必须在登录之后才能访问
       // 1.2 token 只应在当前网站打开期间生效,所以将 token 保存在 sessionStorage 中
       window.sessionStorage.setItem('token', res.data.data.token)
       // 2. 通过编程式导航跳转到后台主页,路由地址是 /home
       this.$router.push('/home')
     })
   })
 },
})

请求拦截器

  axios.interceptors.request.use((config) => {
    // 这个config里面要携带token
    config.headers.Authorization = window.sessionStorage.getItem('token') || ''
    return config
})

全局前置守卫

  router.beforeEach((to, from, next) => {
    // to 将要访问的路径
    // from 代表从哪个路径跳转而来
    // next 是一个函数,表示放行
    //     next()  放行    next('/login')  强制跳转
    
    if (to.path === '/login') return next()
    // 获取token
    const tokenStr = window.sessionStorage.getItem('token')
    if (!tokenStr) return next('/login')
    next()
  })

3.整个页面的布局是基于的element-ui常用的组件中的Container 布局容器实现的

<el-container>
  <el-header>Header</el-header>  //头部
  <el-container>
    <el-aside width="200px">Aside</el-aside>
    <el-main>Main</el-main>
  </el-container>
</el-container>

)MI09XQQE4G43L)LTSG)}D5.png

4. 项目 ---->优化

4.1. 给项目添加进度条,使用nprogress

 安装命令 npm install nprogress -S  // nprogress里面有start() done()这两个方法

配置:

  1.首先在封装的axios里面导入nprogress 
    import NProgress from 'nprogress'
  2. 在请求拦截器里面添加 NProgress.start()   //什么时候开始
  3. 在响应拦截器里面添加 NProgress.done()    //什么时候完成

4.2. 修改打包时的警告提示和错误

4.3 去除打包的console.log (发布阶段在打包阶段去掉console.log() )

可以使用 babel-plugin-transform-remove-console来自动去除console.log()

   安装命令 npm install babel-plugin-transform-remove-console -D  
   

配置: 在babel.config.js中配置如下内容

   const proPlugins = []
   if (process.env.NODE_ENV === 'production') {
     proPlugins.push('transform-remove-console')
   }
   module.exports = {
     presets: [
       '@vue/cli-plugin-babel/preset'
     ],
     plugins: [
       ...proPlugins   // 展开数组
     ]
   }

4.4. 完成打包多入口,将开发阶段和发布阶段的打包入口分开

新创建一个main-dev.js 和 main-prod.js把原来main.js的内容分别复制到这两个文件中 然后在vue.config.js当中配置如下内容:

  module.exports = {
      chainWebpack: config => {
          // 发布模式
         config.when(process.env.NODE_ENV === 'production', config => {
            // entry找到默认的打包入口,调用clear则是删除默认的打包入口
            // add添加新的打包入口
            config.entry('app').clear().add('./src/main-prod.js')
          })
        // 开发模式
        config.when(process.env.NODE_ENV === 'development', config => {
        config.entry('app').clear().add('./src/main-dev.js')
      })
    }
  }

4.5. 将引用本地文件的东西替换成CDN加载

首先在vue.config.js中上面配置的发布模式中添加如下内容

  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',
      echarts: 'echarts',
      nprogress: 'NProgress',
      moment: 'moment',
      lodash: '_',
      quill: 'quill'
    })
    // html-webpack-plugin 将index进行赋值 isProd 似乎是开发阶段
    config.plugin('html').tap(args => {
      args[0].isProd = true
      return args
    })
  })

然后在public目录下的index.html中引入CDN,如下: (注意版本一定要统一!!!!)

<% if(htmlWebpackPlugin.options.isProd) { %>  //判断是不是开发阶段,是的话替换为{}里面的内容
    <script src="https://cdn.bootcdn.net/ajax/libs/vue/2.6.11/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.bootcdn.net/ajax/libs/axios/0.21.1/axios.min.js"></script>
    <script src="https://cdn.bootcdn.net/ajax/libs/echarts/5.1.2/echarts.min.js"></script>
    <script src="https://cdn.bootcdn.net/ajax/libs/nprogress/0.2.0/nprogress.min.js"></script>
    <script src="https://cdn.bootcdn.net/ajax/libs/lodash.js/4.17.21/lodash.core.min.js"></script>
        <!-- moment -->
    <script src="https://cdn.bootcdn.net/ajax/libs/moment.js/2.29.1/moment.min.js"></script>
        <!-- elementUI -->
    <script src="https://cdn.bootcdn.net/ajax/libs/element-ui/2.15.2/index.min.js"></script>
    <link href="https://cdn.bootcdn.net/ajax/libs/element-ui/2.15.2/theme-chalk/index.min.css" rel="stylesheet">
    <link href="https://cdn.bootcdn.net/ajax/libs/quill/1.3.6/quill.snow.min.css" rel="stylesheet">
<% } %>

4.6. 启用GZIP压缩功能

在vue.config.js中配置如下内容:

   const CompressionWebpackPlugin = require('compression-webpack-plugin')
   const productionGzipExtensions = ['js', 'css']
   
   configureWebpack: {
       plugins: [
         // 配置compression-webpack-plugin压缩
         new CompressionWebpackPlugin({
           algorithm: 'gzip',
           test: new RegExp('\\.(' + productionGzipExtensions.join('|') + ')$'),
           threshold: 10240,
           minRatio: 0.8
         })
       ]

4.7. 开启路由懒加载

   {
     path: 'welcome',
     component: () => import('../views/Welcome.vue')
   },