Vue项目总结

285 阅读5分钟

项目前期准备

1、创建Vue项目

打开服务器

打开小皮面板,由其提供的网址和初始账户密码登录面板。打开数据库,删除其原始遗留的文件,添加自己服务器中的数据库并将其导入。数据库导入完成后,进入服务器文件夹,Shift+右键打开PowerShell窗口,输入 命令node app.js,打开服务器。

安装脚手架

打开DOS命令窗口,全局安装脚手架,安装的是Vue CLI v4.5.13版本。

npm install @vue/cli -g

创建项目

有两种可以创建Vue项目的方法

  1. 首先创建一个文件夹,在其中创建我的Vue项目,使用命令创建
vue create myproject

选择手动选择配置项Manually select features,除了一些默认的选项,还选择了PWA(渐进式网页应用:Progressive Web App (PWA) Support)支持、 Router和CSS Pre-processors。然后选择Vue 2.x版本,因为此项目使用的是hash模式的路由,所以不需要history模式的路由;CSS预处理选择Less,之后选择标准的ESLint + Standard config配置,后续的配置Enter就可。

2.进入DOS窗口使用命令,打开GUI,在网页上打开Vue项目管理器并创建新的项目。

vue ui

打开Vue项目管理器,并创建新的项目,配置项的选择和使用命令时创建的一样,这里就不一一赘述了。

安装element-ui

如果你是使用命令创建项目

npm add element-ui

或者在项目管理器中点击依赖→安装依赖→安装依赖→搜索element-ui→选择官方element-ui→安装依赖,即可完成element-ui的安装。

项目开始

分析项目结构

所有的代码数据基本都是放在src目录之下的。在src目录下创建api项目,主要用来存放一些有关数据请求的文件;assets存放的是一些css、fontsimages文件;component存放的各种组件文件,在其之下又根据项目结构创建不同的目录;plugin目录,用来存放一些需要插入的文件,如element.js文件;router存放的是我们在开发过程中需要配置的各种路由;utils目录存放的是我们在开发过程中使用到的一些工具文件;view下存放的是一些视图文件。

vue项目结构.PNG

本项目的view主要分为登录、主页面和一个欢迎页面。

项目开始

登录界面Login

登录页面主要包含用户名和密码两个输入框,由一个form表单构成,使用element-ui中的表单以及icon图标。 因为用户名和密码都有验证条件,给表单绑定rules属性,用来验证其用户名和密码是否正确。

用户名和密码rules.PNG required:是否是必填项

message:当required为false时的提示信息

trigger‘blur’:当失焦时验证条件

在登录页面使用会话存储sessionStorage中的token,来验证用户名和密码。

在localStorage、sessionStorage、cookie三种存储方式中选择sessionStorage的原因:

localStorage:本地存储,只要用户不主动清除数据,其数据则会永久存在,因此不适用本项目;

sessionStorage:会话存储,sessionStorage存储的数据并不会失效,只有当用户关闭浏览器时,其数据则会自动清除,对于本项目来说,是非常合适的。

cookie:cookie存储也可以用来存储用户名和密码信息,但是它每次都会携带在HTTP头中,发送给服务端,当使用cookie保存过多数据会影响它的性能。

结合种种原因,选择了sessionStorage。

在api目录下,axios.js用来处理ajax请求,在axios的请求拦截器中的配置中携带token。

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

为登录页面配置路由,路由配置在router目录下的index.js文件中配置,并设置路由守卫

router.beforeEach(async (to, from, next) => {
  if (to.path !== '/login') {
    if (window.sessionStorage.getItem('token')) {
      next()
    } else {
      next('/login')
    }
  } else {
    next()
  }
})

当sessionStorage中没有登录的token值时,页面会自动跳转到登录界面。

主界面Home

主界面布局主要分为三大块,Header、Aside和Main,使用了element-ui中的Container布局容器。首先要在router中为Home配置路由并引入。

Header

头部分为左边和右边两部分,左边包含一张系统的logo图片和title文字;右边则是一个退出此平台的按钮,当店家此按钮时,则会清除存储在sessionStorage中的token值,当用户再次进入此Home页面时则会自动跳转到登录页面,必须登录之后才可以进入。

Aside

Aside里放的是侧边导航栏,使用NavMenu导航菜单,根据后台侧边导航接口,异步请求导航内容。

 // 请求侧边导航栏数据
  async created() {
    const { data: res } = await this.$http('menus')
    this.menuList = res.data
  },

因为每一个一级导航都有一个相对应的icon图标,因此针对图标定义了一个icon图标数组,专门用来存放一级导航对应的图标,最后再遍历循环。

async getMenuList() {
      const { data: res } = await this.$http.get('menus')
      if (res.meta.status === 200) {
        this.menuList = res.data
        res.data.forEach(item => {
          for (var j in this.iconlist) {
            if (item.id + '' === j) {
              item.icon = this.iconlist[j]
            }
          }
        });
      } else 
        this.$message.error(res.meta.msg)
      }
    }

Main

用户列表

在components目录下创建一个新目录,专门用来存放有关用户管理的一些组件。

为用户列表界面配置路由,而这些子界面的路由都作为Home的children路由来配置,配置之后再引入组件即可完成。

用户列表的头部是一个Breadcrumb面包屑导航,因为后面的开发会复用面包屑导航,这里我们将面包屑导航作为一个组件引入,方便后期的复用。

面包屑导航下方是一个Card卡片,卡片中的内容分,为上下两部分,上方是一个复合型的搜索框和一个可以添加新用户的按钮,下方是一个Form表单和Pagination分页,表单中的数据和分页我们通过后台提供的接口来获得。

11用户列表.PNG

在操作中有三个按钮,包括编辑、删除和可以为用户分配不同的角色的按钮。

12用户列表-操作.PNG

为了方便后期维护,我将编辑用户和分配角色作为子组件引入。

在添加用户中,当点击“添加用户”按钮时,弹出一个添加用户的dilog,包括用户名、密码、邮箱和手机号。当用户添加完成后需要对用户天际的数据验证是否合法,当验证通过点击确定之后,即可向后台发出请求将新添加的数据存储到数据库中。

对于邮箱和手机号需要使用正则表达式来验证其是否合法。

// 验证邮箱是否合法
var checkemail = (rule, value, callback) => {
  const regEmail = /^[_a-z0-9-]+(\.[_a-z0-9-]+)*@[a-z0-9-]+(\.[a-z0-9-]+)*(\.[a-z]{2,})$/;
  if (regEmail.test(value)) {
    callback()
  } else {
    callback(new Error('请输入正确的邮箱'))
  }
};
// 验证手机号是否合法
var checkmobile = (rule, value, callback) => {
  const regMobile = /^(13[0-9]|14[01456879]|15[0-35-9]|16[2567]|17[0-8]|18[0-9]|19[0-35-9])\d{8}$/;
  if (regMobile.test(value)) {
    callback()
  } else {
    callback(new Error('请输入正确的手机号'))
  }
};

在编辑用户中,要实现这样一个功能,当点击某一个用户的编辑按钮时,要弹出一个编辑用户的Dialog对话框,同时此用户的用户名、邮箱和手机号也将同时显示在对话框中的表单中。当用户没有修改信息时,给用户一个提信息;当用户确认已经重新修改信息时,要对后台发出一个请求,将此用户的信息保存起来,同时更新列表中的数据。

要实现以上功能,父子组件之间需要通信,当点击某一个用户时,父组件要“告诉子组件我点击的是哪一个用户,这个用户的用户名等信息是什么”,而子组件通过prop来接收来自父组件的数据,当用户修改完成后子组件通过$emit抛出一个事件,“告诉我已经修改完成了,你可以更新列表数据了”。

在分配角色中,用到了Select选择器器,需要先获取到所有的角色列表,根据其唯一的id值来确认选择的是哪一个角色。

权限管理

角色列表

在角色列表中,不同的用户有不同的权限等级,不同的等级有不同的tag颜色,使用v-if、v-else即可实现此功能。

权限列表

在权限列表中,当点击分配权限按钮时,在弹出的对话框中是一个权限树,可以给用户分配不同的权限。

商品管理

商品列表

在商品列表中除了正常请求商品的数据之外,还有一个添加按钮。当我们点击添加按钮时需要跳转到另一个页面,因此需要为商品添加按钮配置路由,这个路由也是在Home中注册,然后给添加按钮增加一个点击事件 @click="$router.push('/goods/add')",即可实现跳转。

添加商品上方有一个Steps步骤条,下方左侧是一个左边的Tabs标签页。

左侧tabs标签页中的商品内容中需要使用到富文本编辑器,现在项目管理器中下载,然后在main.js中引入,最后直接使用即可。

//main.js
// 引入富文本编辑器
import VueQuillEditor from 'vue-quill-editor'
// 引入富文本编辑器的 styles
import 'quill/dist/quill.core.css'
import 'quill/dist/quill.snow.css'
import 'quill/dist/quill.bubble.css'
// 全局注册富文本编辑器
Vue.use(VueQuillEditor)


//在页面中的使用
 <quill-editor v-model="addGoodsForm.goods_introduce"></quill-editor>
分类参数

分类参数上方是一个Cascader级联选择器,下方是一个Table表格

商品分类

在商品分类中的Form表单中用到了tree-table表格树。

在项目管理器中可以搜索vue-table-with-tree-grid并将其安装到项目中,也可以使用

npm install vue-table-with-tree-grid -S安装,安装之后main.js文件中引用并注册即可使用。

// 引入表格树
import TreeTable from 'vue-table-with-tree-grid'
// 全局注册组件
Vue.component('tree-table', TreeTable)

订单管理

订单列表

订单列表的数据请求同用户列表的数据请求,无甚大区别。

数据统计

数据统计是一个echarts图,也是用到了lodash,因此我们需要先下载,使用

npm install echarts -S
npm install lodash -S

或者在项目管理器中搜索下载也可。

下载之后在需要使用的页面中引入即可使用。

// 1、引入 echarts.js 
import * as echarts from 'echarts';
// 引入loadsh
import _ from 'lodash'

具体实例代码如下:


<template>
    <el-card>
      <div id="main" style="width: 750px;height:450px;"></div>
    </el-card>
</template>
<script>
// 1、引入 echarts.js 
import * as echarts from 'echarts';
// 引入loadsh
import _ from 'lodash'

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() {
    // 2、 基于准备好的dom,初始化echarts实例
    var myChart = echarts.init(document.getElementById('main'));
    const { data: res } = await this.$http.get('reports/type/1')
    if (res.meta.status !== 200) {
      return this.$message.error('请求折线图数据失败')
    }
    //  3、指定图表的配置项和数据
    const result = _.merge(res.data, this.options)
    // 4、 使用刚指定的配置项和数据显示图表。
    myChart.setOption(result);
    // console.log(option);
  }
};
</script>