leyou_04_使用vue.js搭建页面—使用ajax完成品牌的查询

1.使用vue.js搭建页面

 1.1使用的模板插件Vuetify

  中文UI组件官网:https://vuetifyjs.com/zh-Hans/getting-started/quick-start

 1.2要实现的效果

  1.3创建Brand.vue初始化页面

<template>
  <span>
    hello
  </span>
</template>

<script>
  export default {
    name: "myBrand"
  }
</script>

<!-- scoped:当前样式只作用于当前组件的节点 -->
<style scoped>

</style>
知识兔

 

  1.4首先是一个5列的表格 选用这个

  1.5复制模版

<template>
  <div>
    <v-data-table
      :headers="headers"  
      :items="brand"
      :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>
知识兔

  

  headers:表头信息,是一个数组也就是表格的列信息

  text:表格列的名称   value:该列关联的字段   align:对齐方式   sortable:是否需要排默认false

headers: [
          {text: '品牌id', value: 'id', align: 'center', sortable: true},
          {text: '品牌名称', value: 'name', align: 'center', sortable: false},
          {text: '品牌LoGo', value: 'image', align: 'center', sortable: false},
          {text: '品牌首字母', value: 'letter', align: 'center', sortable: true},
          {text: '操作', align: 'center', sortable: false},

        ],
知识兔
  • items:要在表格中展示的数据,数组结构,每一个元素是一行。在这里应该是品牌集合

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

  • total-items:总条数,在这里是品牌的总记录数

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

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

1.6页面搭建完成接下来只需要使用watch监控页面数据发生改变时发送相应的ajax请求

<template xmlns:v-bind="http://www.w3.org/1999/xhtml">
  <div>
    <v-layout class="px-3 pb-2">
      <v-flex xs2>
        <v-btn color="info" small>新增品牌</v-btn>
      </v-flex>
      <v-spacer/>
      <v-flex xs4>
        <v-col cols="12" sm="6" md="3">
          <v-text-field label="搜索" hide-details append-icon="search" v-model="key"></v-text-field>
        </v-col>
      </v-flex>
    </v-layout>
    <v-data-table
      :headers="headers"
      :items="brands"
      :pagination.sync="pagination"
      :toatl-items="totalBrands"
      :loading="loading"
      class="elevation-1"
    >
      <template slot="items" slot-scope="props">
        <td class="text-xs-center">{{props.item.id}}</td>
        <td class="text-xs-center">{{props.item.name}}</td>
        <td class="text-xs-center"><img v-if="props.item.image" v-bind:src="props.item.image" width="130" height="40"/>
        </td>
        <td class="text-xs-center">{{props.item.letter}}</td>
        <td class="text-xs-center">
          <v-btn color="success" small>修改</v-btn>
          <v-btn color="error" small>删除</v-btn>
        </td>

      </template>

    </v-data-table>
  </div>
</template>

<script>
  export default {
    data() {
      return {
        totalDesserts: 0,
        desserts: [],
        loading: true,
        options: {},
        headers: [
          {text: '品牌id', value: 'id', align: 'center', sortable: true},
          {text: '品牌名称', value: 'name', align: 'center', sortable: false},
          {text: '品牌LoGo', value: 'image', align: 'center', sortable: false},
          {text: '品牌首字母', value: 'letter', align: 'center', sortable: true},
          {text: '操作', align: 'center', sortable: false},

        ],
        brands: [],
        pagination: {},
        totalBrands: 0,
        loading: false,
        key: "",//搜索条件
      }
    },
  }
</script>

<style scoped>

</style>
知识兔
知识兔
在列的最后增加一列图标
<template slot="items" slot-scope="props">        <td class="text-xs-center">          <v-btn color="success" small>修改
       <v-icon>edit</v-icon>//用一个图标来代替修改 
</v-btn> <v-btn color="error" small>删除</v-btn> </td></template>

增加按钮和搜索框

<v-layout class="px-3 pb-2"><!--代表是一行 -->      <v-flex xs2><!--设置宽度 -->        <v-btn color="info" small>新增品牌</v-btn>      </v-flex>      <v-spacer/> <!--自动补全中的的空间 -->      <v-flex xs4>        <v-col cols="12" sm="6" md="3">          <v-text-field label="搜索" hide-details append-icon="search" v-model="key"></v-text-field>        </v-col>      </v-flex>    </v-layout>

1.7对搜索框和分页,排序,每页记录数进行监控当数据发生改变时调用ajax

//监控watch:{      key(){        this.loadBrands();      },      pagination:{//深度监控        deep:true,        handler(){          this.loadBrands();        }      }},

1.8发送ajax方法

methods: {      loadBrands() {        this.$http.get("/item/brand/page", {          params: {            page:this.pagination.page,//当前页            rows:this.pagination.rowsPerPage,//每页记录数            sortBy:this.pagination.sortBy,//排序字段            desc:this.pagination.descending,//是否降序            key: this.key//搜索条件          }        }).then(resq =>{          this.brands=resq.data.items;          this.totalBrands=resq.data.total;        })      }    },
this.$http.get("/item/brand/page", 通过vue.js的原型去配置的
在http.js中定义了
Vue.prototype.$http = axios;// 将axios添加到 Vue的原型,这样一切vue实例都可以使用该对象

1.9config.js中请求地址的自动拼接 发送的任何请求都会自动拼接api

const baseUrl = 'http://api.leyou.com'  api: `${baseUrl}/api`,

2.后台的处理(使用restful风格)

2.1拿到ajax传递的参数

@RestController@RequestMapping("brand")public class BrandController {    @Autowired    private BrandService brandService;    @GetMapping("page")    public ResponseEntity<PageResult<Brand>> queryBrandPage(            @RequestParam(value = "page", defaultValue = "1") Integer page,            @RequestParam(value = "rows", defaultValue = "5") Integer rows,            @RequestParam(value = "storyBy", required = false) String storyBy,            @RequestParam(value = "desc", defaultValue = "false") boolean desc,            @RequestParam(value = "key", required = false) String key) {           PageResult<Brand> result=brandService.queryBrandPage(page,rows,storyBy,desc,key);        System.out.println(result);           return  ResponseEntity.ok(result);    }}

2.2在servicer中处理//分页//过滤//排序//查询//结果集的封装

通过通用mapper操作数据库

@Servicepublic class BrandService {    @Autowired    private BrandMapper brandMapper;    public PageResult<Brand> queryBrandPage(Integer page, Integer rows, String storyBy, boolean desc, String key) {        //分页   mapper自带的分页助手        PageHelper.startPage(page, rows);        //过滤  select * from tb_brand where name like "%"+key+"%" or letter==key order by storyBy  desc        Example example = new Example(Brand.class);        if (StringUtils.isNotBlank(key)) {            example.createCriteria().orLike("name", "%" + key + "%").orEqualTo("letter", key.toUpperCase());        }        //排序        if (StringUtils.isNotBlank(storyBy)) {            String orderByClause=storyBy+(desc? " desc":" asc");            example.setOrderByClause(orderByClause);        }        //查询        List<Brand> list = brandMapper.selectByExample(example);        if (CollectionUtils.isEmpty(list)){            throw  new LyException(ExceptionEnum.BRAND_NOT_FOND);        }        //帮我们把查询到的结果List进行封装  封装的结果集里面有Total,pageNum,pageSizedeng        PageInfo<Brand> info = new PageInfo<>(list);        //封装结果集        PageResult<Brand> result = new PageResult<Brand>(info.getTotal(),list);        return result;    }}
 PageInfo<Brand> info = new PageInfo<>(list);
帮我们把查到的sql语句结果强转为PageInfo对象
PageInfo对象中定义了很多的分页属性
例如:
private static final long serialVersionUID = 1L;    //当前页    private int pageNum;    //每页的数量    private int pageSize;    //当前页的数量    private int size;    //当前页面第一个元素在数据库中的行号    private int startRow;    //当前页面最后一个元素在数据库中的行号    private int endRow;    //总记录数    private long total;    //总页数    private int pages;    //结果集    private List<T> list;
 
计算机