乐优商城(四)品牌管理(前端)

目录

一、前端页面构建

1.1 页面内容分析

1.2 data-tables组件

1.2.1 基本内容

1.2.2 代码分析

1.2.3 补充

1.3 页面优化

1.3.1 编辑和删除按钮

1.3.2 新增、删除(多个)

1.3.3 搜索

1.3.4 布局调整

1.4 对话框

1.4.1 初步实现弹窗

1.4.2 实现弹窗的可见和关闭

1.4.3 新增品牌的表单页


后台功能——品牌管理(前端)

预期效果图:

前端到后端的完整开发

一、前端页面构建

1.1 页面内容分析

从上图可以看到,页面内容分三个部分来构建,首先是用来展示数据的表格,然后是搜索框,最后是增加和删除按钮。当点击增加按钮会弹出一个对话框用来新增品牌,所以还需要一个对话框。

1.2 data-tables组件

1.2.1 基本内容

v-data-table中有以下核心属性:

  • dark:是否使用黑暗色彩主题,默认是false

  • expand:表格的行是否可以展开,默认是false

  • headers:定义表头的数组,数组的每个元素就是一个表头信息对象,结构:

    {
      text: string, // 表头的显示文本
      value: string, // 表头对应的每行数据的key
      align: 'left' | 'center' | 'right', // 位置
      sortable: boolean, // 是否可排序
      class: string[] | string,// 样式
      width: string,// 宽度
    }
  • items:表格的数据的数组,数组的每个元素是一行数据的对象,对象的key要与表头的value一致

  • loading:是否显示加载数据的进度条,默认是false

  • no-data-text:当没有查询到数据时显示的提示信息,string类型,无默认值

  • pagination.sync:包含分页和排序信息的对象,将其与vue实例中的属性关联,表格的分页或排序按钮被触发时,会自动将最新的分页和排序信息更新。对象结构:

    {
        page: 1, // 当前页
        rowsPerPage: 5, // 每页大小
        sortBy: '', // 排序字段
        descending:false, // 是否降序
    }
  • total-items:分页的总条数信息,number类型,无默认值

  • select-all :是否显示每一行的复选框,Boolean类型,无默认值

  • value:当表格可选的时候,返回选中的行

在官方文档中找到一个基本符合需求的样例,所以在这个基础上进行修改

源代码:

<template>
  <div>
    <v-data-table
      :headers="headers"
      :items="desserts"
      :pagination.sync="pagination"
      :total-items="totalDesserts"
      :loading="loading"
      class="elevation-1"
    >
      <template slot="items" slot-scope="props">
        <td>{{ props.item.name }}</td>
        <td class="text-xs-right">{{ props.item.calories }}</td>
        <td class="text-xs-right">{{ props.item.fat }}</td>
        <td class="text-xs-right">{{ props.item.carbs }}</td>
        <td class="text-xs-right">{{ props.item.protein }}</td>
        <td class="text-xs-right">{{ props.item.iron }}</td>
      </template>
    </v-data-table>
  </div>
</template>

1.2.2 代码分析

先介绍一下基本属性:

<v-data-table
              :headers="headers"
              :items="desserts"
              :search="search"
              :pagination.sync="pagination"
              :total-items="totalDesserts"
              :loading="loading"
              class="elevation-1"
              >
</v-data-table>
  • headers:表头信息,是一个数组

  • items:要在表格中展示的数据,数组结构,每一个元素是一行

  • search:搜索过滤字段,用不到,暂时不管

  • pagination.sync:分页信息,包含了当前页,每页大小,排序字段,排序方式等。加上.sync代表服务端排序,当用户点击分页条时,该对象的值会跟着变化。监控这个值,并在这个值变化时去服务端查询,即可实现页面数据动态加载了。

  • total-items:总条数

  • loading:boolean类型,true:代表数据正在加载,会有进度条。false:数据加载完毕。

  • class: 表格的样式

<template slot="items" slot-scope="props">
        <td>{{ props.item.name }}</td>
        <td class="text-xs-right">{{ props.item.calories }}</td>
        <td class="text-xs-right">{{ props.item.fat }}</td>
        <td class="text-xs-right">{{ props.item.carbs }}</td>
        <td class="text-xs-right">{{ props.item.protein }}</td>
        <td class="text-xs-right">{{ props.item.iron }}</td>
</template>

这段就是在渲染每一行的数据。Vue会自动遍历上面传递的items属性,并把得到的对象传递给这段template中的props.item属性。我们从中得到数据,渲染在页面即可。

所以需要做的事情,主要有两件:

  • 给items和total-Items赋值

  • 当pagination变化时,重新获取数据,再次给items和total-Items赋值

1.2.3 补充

在每一条数据的前面加一个选择框,用来辅助删除操作。

继续在官方文档中寻找~

代码:

<template>
  <v-data-table
    :headers="headers"
    :items="desserts"
    :search="search"
    v-model="selected"
    item-key="name"
    select-all
    class="elevation-1"
  >
    <template slot="headerCell" slot-scope="props">
      <v-tooltip bottom>
        <span slot="activator">
          {{ props.header.text }}
        </span>
        <span>
          {{ props.header.text }}
        </span>
      </v-tooltip>
    </template>
    <template slot="items" slot-scope="props">
      <td>
        <v-checkbox
          v-model="props.selected"
          primary
          hide-details
        ></v-checkbox>
      </td>
      <td>{{ props.item.name }}</td>
      <td class="text-xs-right">{{ props.item.calories }}</td>
      <td class="text-xs-right">{{ props.item.fat }}</td>
      <td class="text-xs-right">{{ props.item.carbs }}</td>
      <td class="text-xs-right">{{ props.item.protein }}</td>
      <td class="text-xs-right">{{ props.item.iron }}</td>
    </template>
  </v-data-table>
</template>

v-model = "selected" :绑定一个数组用来存放已经选中的条目

select-all:可以点击表头中的选择框选中当页全部数据

1.3 页面优化

1.3.1 编辑和删除按钮

将来要对品牌进行增删改,需要给每一行数据添加 修改删除的按钮,一般放到改行的最后一列:

其实就是多了一列,只是这一列没有数据,而是两个按钮而已。

1.3.2 新增、删除(多个)

将这两个按钮放在表格外:

1.3.3 搜索

一个文本输入框

  • name:字段名,表单中会用到

  • label:提示文字

  • value:值。可以用v-model代替,实现双向绑定

1.3.4 布局调整

使用v-card

卡片v-card包含四个基本组件:

  • v-card-media:一般放图片或视频

  • v-card-title:卡片的标题,一般位于卡片顶部

  • v-card-text:卡片的文本(主体内容),一般位于卡片正中

  • v-card-action:卡片的按钮,一般位于卡片底部

可以把新增、删除和搜索放到v-card-title位置,把table放到下面,这样就成一个上下关系。

1.4 对话框

1.4.1 初步实现弹窗

当点击新增按钮,应该出现一个弹窗,然后在弹窗中出现一个表格,就可以填写品牌信息了。

另外,可以通过文档看到对话框的一些属性:

  • value:控制窗口的可见性,true可见,false,不可见

  • max-width:控制对话框最大宽度

  • scrollable :是否可滚动,要配合v-card来使用,默认是false

  • persistent :点击弹窗以外的地方不会关闭弹窗,默认是false

首先,我们在data中定义一个show属性,来控制对话框的显示状态:

然后,在页面添加一个v-dialog

<!--弹出的对话框-->
<v-dialog max-width="500" v-model="show" persistent>
    <v-card>
        <!--对话框的标题-->
        <v-toolbar dense dark color="primary">
            <v-toolbar-title>新增品牌</v-toolbar-title>
        </v-toolbar>
        <!--对话框的内容,表单-->
        <v-card-text class="px-5">
            我是表单
        </v-card-text>
    </v-card>
</v-dialog>

说明:

  • 我们给dialog指定了3个属性,分别是

    • max-width:限制宽度

    • v-model:value值双向绑定到show变量,用来控制窗口显示

    • persisitent:控制窗口不会被意外关闭

  • 因为可滚动需要配合v-card使用,因此我们在对话框中加入了一个v-card

    • v-card的头部添加了一个 v-toolbar,作为窗口的头部,并且写了标题为:新增品牌

      • dense:紧凑显示

      • dark:黑暗主题

      • color:颜色,primary就是整个网站的主色调,蓝色

    • v-card的内容部分,暂时空置,等会写表单

  • class=“px-5":vuetify的内置样式,含义是padding的x轴设置为5,这样表单内容会缩进一些,而不是顶着边框

    基本语法:{property}{direction}-{size}

    • property:属性,有两种paddingmargin

      • p:对应padding

      • m:对应margin

    • direction:只padding和margin的作用方向,

      • t - 对应margin-top或者padding-top属性

      • b - 对应margin-bottom or padding-bottom

      • l - 对应margin-left or padding-left

      • r - 对应margin-right or padding-right

      • x - 同时对应*-left*-right属性

      • y - 同时对应*-top*-bottom属性

    • size:控制空间大小,基于$spacer进行倍增,$spacer默认是16px

      • 0:将margin或padding的大小设置为0

      • 1 - 将margin或者padding属性设置为$spacer * .25

      • 2 - 将margin或者padding属性设置为$spacer * .5

      • 3 - 将margin或者padding属性设置为$spacer

      • 4 - 将margin或者padding属性设置为$spacer * 1.5

      • 5 - 将margin或者padding属性设置为$spacer * 3

1.4.2 实现弹窗的可见和关闭

窗口可见

接下来,我们要在点击新增品牌按钮时,将窗口显示,因此要给新增按钮绑定事件。

<v-btn color="primary" @click="addBrand">新增品牌</v-btn>

然后定义一个addBrand方法:

addBrand(){
    // 控制弹窗可见:
    this.show = true;
}

效果:

窗口关闭

因为我们设置了persistent属性,窗口无法被关闭了。除非把show属性设置为false,因此我们需要给窗口添加一个关闭按钮:

<!--对话框的标题-->
<v-toolbar dense dark color="primary">
    <v-toolbar-title>新增品牌</v-toolbar-title>
    <v-spacer/>
    <!--关闭窗口的按钮-->
    <v-btn icon @click="closeWindow"><v-icon>close</v-icon></v-btn>
</v-toolbar>

并且,我们还给按钮绑定了点击事件,回调函数为closeWindow。

接下来,编写closeWindow函数:

closeWindow(){
    // 关闭窗口
    this.show = false;
}

效果:

1.4.3 新增品牌的表单页

表单的构造有两种选择:

  • 直接在dialog对话框中编写表单代码

  • 另外编写一个组件,组件内写表单代码。然后在对话框引用组件

选第二种方案,优点:

  • 表单代码独立组件,可拔插,方便后期的维护。

  • 代码分离,可读性更好。

缺点:

  • 麻烦

1.4.3.1 创建新组件

将MyBrandForm引入到MyBrand中,这里使用局部组件的语法:

先导入自定义组件:

  // 导入自定义的表单组件
  import MyBrandForm from './MyBrandForm'

然后通过components属性来指定局部组件:

components:{
    MyBrandForm
}

然后在页面中引用:

页面效果:

1.4.3.2 编写表单

效果图:

一共包含五项:两个文本框、一个级联下拉选择框(自定义组件)、一个文件上传和两个按钮(清空、保存)。具体内容请参考项目代码。

1.4.3.3 数据校验

Vuetify的表单校验,是通过rules属性来指定的:

校验规则的写法:

说明:

  • 规则是一个数组

  • 数组中的元素是一个函数,该函数接收表单项的值作为参数,函数返回值两种情况:

    • 返回true,代表成功,

    • 返回错误提示信息,代表失败

1.4.3.4 表单提交

在submit方法中添加表单提交的逻辑:

submit() {
    // 1、表单校验
    if (this.$refs.myBrandForm.validate()) {
        // 2、定义一个请求参数对象,通过解构表达式来获取brand中的属性
        const {categories ,letter ,...params} = this.brand;
        // 3、数据库中只要保存分类的id即可,因此我们对categories的值进行处理,只保留id,并转为字符串
        params.cids = categories.map(c => c.id).join(",");
        // 4、将字母都处理为大写
        params.letter = letter.toUpperCase();
        // 5、将数据提交到后台
        this.$http.post('/item/brand', this.$qs.stringfy(params))
            .then(() => {
            // 6、弹出提示
            this.$message.success("保存成功!");
        })
            .catch(() => {
            this.$message.error("保存失败!");
        });
    }
}
  • 1、通过this.$refs.myBrandForm选中表单,然后调用表单的validate方法,进行表单校验。返回boolean值,true代表校验通过

  • 2、通过解构表达式来获取brand中的值,categories和letter需要处理,单独获取。其它的存入params对象中

  • 3、品牌和商品分类的中间表只保存两者的id,而brand.categories中保存的数对象数组,里面有id和name属性,因此这里通过数组的map功能转为id数组,然后通过join方法拼接为字符串

  • 4、首字母都处理为大写保存

  • 5、发起请求,注意此时必须对表单数据进行转换,将json对象转换为请求参数字符串。

  • 6、弹窗提示成功还是失败,这里用到的是我们的自定义组件功能message组件:

这个插件把$message对象绑定到了Vue的原型上,因此我们可以通过this.$message来直接调用。

包含以下常用方法:

  • info、error、success、warning等,弹出一个带有提示信息的窗口,色调与为普通(灰)、错误(红色)、成功(绿色)和警告(黄色)。使用方法:this.$message.info("msg")
  • confirm:确认框。用法:this.$message.confirm("确认框的提示信息"),返回一个Promise

猜你喜欢

转载自blog.csdn.net/lyj2018gyq/article/details/82220560