<v-data-table
:headers=“headers”
:items=“brands”
:pagination.sync=“pagination”
:total-items=“totalDesserts”
:loading=“loading”
class=“elevation-1”
- 完善其他相关内容
- :loading="loading"设置加载前开启加载后关闭
先默认设置为不显示
- 完善渲染表格的内容
全部代码
<v-data-table
:headers=“headers”
:items=“brands”
:pagination.sync=“pagination”
:total-items=“totalBrands”
:loading=“loading”
class=“elevation-1”
{{ props.item.id }} {{ props.item.name }} {{ props.item.image }} {{ props.item.letter }}- 页面效果
- 设置数据居中
- 设置图片显示
品牌中有,id,name,image,letter字段
(5)完善品牌管理的,新增品牌,搜索框,编辑以及删除按钮
- 设置操作(设置当中的修改和删除按钮)
在headers当中
访问页面效果
完善按钮效果
设置标签缩小 在后面填写small
设置按钮为图标
edit
delete
效果
- 新增按钮
新增品牌
效果
- 搜索框(并控制其宽度)
新增品牌
效果
发现页面下方以及按钮不太好看
在搜索框下默认有错误提示
设置搜索框隐藏细节并去掉按钮的small
效果
设置搜索框距离按钮远一些
页面效果
设置搜索框的图标
(6)实现数据的动态查询以及axios
a、发送Ajax请求(异步查询工具)
异步查询数据,自然是通过ajax查询,大家首先想起的肯定是jQuery。但jQuery与MWVM的思想不吻合,而且ajax只是jQuery的一小部分。因此不可能为了发起ajax请求而去引用这么大的一个库。
http://www.axios-js.com/zh-cn/docs/
axios快速入门
执行 GET
请求
// 为给定 ID 的 user 创建请求
axios.get(‘/user?ID=12345’)
.then(function (response) {
console.log(response);
})
.catch(function (error) {
console.log(error);
});
// 上面的请求也可以这样做
axios.get(‘/user’, {
params: {
ID: 12345
}
})
.then(function (response) {
console.log(response);
})
.catch(function (error) {
console.log(error);
});
执行 POST
请求
axios.post(‘/user’, {
firstName: ‘Fred’,
lastName: ‘Flintstone’
})
.then(function (response) {
console.log(response);
})
.catch(function (error) {
console.log(error);
});
执行多个并发请求
function getUserAccount() {
return axios.get(‘/user/12345’);
}
function getUserPermissions() {
return axios.get(‘/user/12345/permissions’);
}
axios.all([getUserAccount(), getUserPermissions()])
.then(axios.spread(function (acct, perms) {
// 两个请求现在都执行完成
}));
axios API
可以通过向 axios
传递相关配置来创建请求
axios(config)
// 发送 POST 请求
axios({
method: ‘post’,
url: ‘/user/12345’,
data: {
firstName: ‘Fred’,
lastName: ‘Flintstone’
}
});
// 获取远端图片
axios({
method:‘get’,
url:‘http://bit.ly/2mTM3nY’,
responseType:‘stream’
})
.then(function(response) {
response.data.pipe(fs.createWriteStream(‘ada_lovelace.jpg’))
});
b、完善页面的Ajax请求
在http.js当已经将axios对象添加到Vue的静态常量当中,直接可以通过this.$http来调用axios
虽然Vue类以及写好了但是依旧可以往里面添加东西
设置请求测试
this.$http.get(“/brand/page”,{//设置请求路径
params:{//设置请求参数
page : 1,
}
}).then(resp => {//在http.js当已经将axios对象添加到Vue的静态常量当中,直接可以通过this.$http来调用axios
})
- 搜索功能
双向绑定数据(v-model)
设置初始值
实现发送请求返回对应的数据(设置搜索框改变数据的时候边改变边发送数据)
全部代码
新增品牌
<v-data-table
:headers=“headers”
:items=“brands”
:pagination.sync=“pagination”
:total-items=“totalBrands”
:loading=“loading”
class=“elevation-1”
{{ props.item.id }} {{ props.item.name }} {{ props.item.letter }}edit
delete
运行效果
- 分页查询(设置pagination)
Vuetify在this的pagination当中提供了默认的分页信息
每当中分页信息发生变化的时候就方式请求,所以需要对pagination的值进行监控,将分页参数发送到后台
- 运行观察效果
http://manage.leyou.com/#/item/brand
通过上述发送的请求编写后端,并返回当前页面的数据和总条数
2、 后台提供查询接口
(1)数据库
前台页面已经准备好,接下来就是后台提供数据接口了
CREATE TABLE tb_brand
(
id
bigint(20) NOT NULL AUTO_INCREMENT COMMENT ‘品牌id’,
name
varchar(50) NOT NULL COMMENT ‘品牌名称’,
image
varchar(200) DEFAULT ‘’ COMMENT ‘品牌图片地址’,
letter
char(1) DEFAULT ‘’ COMMENT ‘品牌的首字母’,
PRIMARY KEY (id
)
) ENGINE=InnoDB AUTO_INCREMENT=325402 DEFAULT CHARSET=utf8 COMMENT=‘品牌表,一个品牌下有多个商品(spu),一对多关系’;
简单的四个字段
这里需要注意的是,品牌和商品分类之间是多对多关系。因此我们有一张中间表,来维护两者间关系;
DROP TABLE IF EXISTS tb_category_brand
;
CREATE TABLE tb_category_brand
(
category_id
bigint(20) NOT NULL COMMENT ‘商品类目id’,
brand_id
bigint(20) NOT NULL COMMENT ‘品牌id’,
PRIMARY KEY (category_id
,brand_id
)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT=‘商品分类和品牌的中间表,两者是多对多关系’;
但是,你可能会发现,这张表中并没有设置外键约束,似乎与数据库的设计范式不符。为什么这么做?
-
外键会严重影响数据库读写的效率
-
数据删除时会比较麻烦
在电商行业当中,性能是非常
(2)实体类
创建对应的实体类
package com.leyou.item.pojo;
import lombok.Data;
import tk.mybatis.mapper.annotation.KeySql;
import javax.persistence.Id;
import javax.persistence.Table;
@Data
@Table(name = “tb_brand”)
public class Brand {
/*
useGeneratedKeys设置为 true 时,表示如果插入的表id以自增列为主键,
则允许 JDBC 支持自动生成主键,并可将自动生成的主键id返回。
useGeneratedKeys参数只针对 insert 语句生效,默认为 false;
*/
@Id
@KeySql(useGeneratedKeys = true)
private Long id;
private String name;//
private String image;
private Character letter;
}
(3)创建实体类对应Mapper
package com.leyou.item.mapper;
import com.leyou.item.pojo.Brand;
import tk.mybatis.mapper.common.Mapper;
public interface BrandMapper extends Mapper {
}
(4)实体类对应的Service
(7)生成实体类对应的控制层
、修改页面的代码的请求路径(在前加上item)
b、创建返回结果的数据的对象PageResult类
在这里封装一个类用来表示分页结果
package com.leyou.common.vo;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.util.List;
/*
@Data 生成getter,setter等函数
@NoArgsConstructor 生成无参构造函数
@AllArgsConstructor //生成全参数构造函数
*/
@Data
public class PageResult {
private Long total;//总条数
private Integer totalPage;//总页数
private List items;//当前页数据
public PageResult() {
}
public PageResult(Long total,List items){
this.total = total;
this.items = items;
}
public PageResult(Long total, Integer totalPage, List items) {
this.total = total;
this.totalPage = totalPage;
this.items = items;
}
}
c、完善BrandController
package com.leyou.item.web;
import com.leyou.common.vo.PageResult;
import com.leyou.item.pojo.Brand;
import com.leyou.item.pojo.Category;
import com.leyou.item.service.BrandService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import java.util.List;
@RestController
@RequestMapping(“brand”)
public class BrandController {
@Autowired
public BrandService brandService;
@GetMapping(“page”)
public ResponseEntity<PageResult> queryBrandByPage(
//设置请求参数参数名称value对应页面上的name,defaultValue默认值 然后是参数类型和参数名称
//相当于Integer name = Intgert.paseInt(request.getParamate(“name”)); 其中(“name”)等价于value=“name”
//Integer name等价于Integer page
//request=false(ture)表示前端的参数是否一定要传入。true表示必须传入参数,false表示可传或不传
@RequestParam(value = “page”,defaultValue = “1”) Integer page,
@RequestParam(value = “rows”,defaultValue = “5”) Integer rows,
@RequestParam(value = “sortBy”,required = false) String sortBy,
@RequestParam(value = “desc”,defaultValue = “flase”) Boolean desc,
@RequestParam(value = “key”,required = false) String key
){
//上面配置好5个参数
//编写业务代码
PageResult result = brandService.queryBrandByPage(page,rows,sortBy,desc,key);
return ResponseEntity.ok(result);
}
}
d、创建对应商品没有查询到的错误异常
BRAND_NOT_FOUND(404,“品牌不存在”),
e、完善业务层代码
package com.leyou.item.service;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.leyou.common.enums.ExceptionEnum;
import com.leyou.common.exception.LyException;
import com.leyou.common.vo.PageResult;
import com.leyou.item.mapper.BrandMapper;
import com.leyou.item.pojo.Brand;
import lombok.val;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import tk.mybatis.mapper.entity.Example;
import java.util.List;
@Service
public class BrandService {
@Autowired
private BrandMapper brandMapper;
public PageResult queryBrandByPage(Integer page, Integer rows, String sortBy,
Boolean desc, String key) {
//分页(过滤器拦截MyBatis在其后面拼接分页条件)
PageHelper.startPage(page,rows);//自动创建好分页的条件
//过滤
Example example = new Example(Brand.class);//设置条件并指定到那张表查询
if(StringUtils.isNotBlank(key))//判断只要key不为空
{
//过滤条件
// select * from tb_brand where name like “%%” or letter = ‘’ limit page,rows order by desc
//设置条件
example.createCriteria().//创建条件,并在后面设置对应的条件
orLike(“name”,“%”+key+“%”).//第一个条件
orEqualTo(“letter”,key.toUpperCase());//第二个条件 (key.toUpperCase()变成大写)
}
//排序
if(StringUtils.isNotBlank(sortBy)){//如果不为空做排序
//当sortBy是id的时候根据id查询,当sortBy是字母的时候根据字母排序,
// 三元运算符判断desc如果是true则DESC否则是ASC
String orderByClause = sortBy+(desc ? " DESC":" ASC");
example.setOrderByClause(orderByClause);//设置OrderBy排序,(直接编写SQL语句)
}
//查询
List list = brandMapper.selectByExample(example);
if(CollectionUtils.isEmpty(list)){
throw new LyException(ExceptionEnum.BRAND_NOT_FOUND);
}
PageResult pageResult = new PageResult();
pageResult.setItems(list);//设置数据
//解析分页结果
PageInfo pageInfo = new PageInfo(list);//得到分页信息
pageResult.setTotal(pageInfo.getTotal());//设置总条数
return pageResult;
}
}
f、如果想要在上述代码当中看到SQL语句,需要添加如下的配置
以下配置设置SQL语句输出在控制台
mybatis:
configuration:
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
(8)运行项目并测试
http://manage.leyou.com/#/item/brand
成功获取到数据
并在控制台输出了SQL语句
(9)完善页面代码
全部前端代码
新增品牌
<v-data-table
:headers=“headers”
:items=“brands”
:pagination.sync=“pagination”
:total-items=“totalBrands”
:loading=“loading”
class=“elevation-1”
{{ props.item.id }} {{ props.item.name }} {{ props.item.letter }}edit
delete
重新运行测试
http://manage.leyou.com/#/item/brand
(10)完善一下搜索功能
this.pagination.page = 1;//每次修改条件的时候都将起始页设置为1
3、品牌新增功能
(1)页面搭建
a、初步编写弹框
当我们点击新增按钮,应该出现一个弹窗,然后在弹窗中出现一个表格,我们就可以填写品牌信息了。我们查看Vuetify官网,弹窗是如何实现:
新增品牌
我是表单
将这段代码复制到页面当中
接下来,我们要在点击新增品牌按钮时,将窗口显示,因此要给新增按钮绑定事件
<v-btn color=“primary” @click=“addBrand”>新增品牌
然后定义一个addBrand方法:
addBrand(){
// 控制弹窗可见:
this.show = true;
}
效果:
窗口关闭
现在,悲剧发生了,因为我们设置了persistent属性,窗口无法被关闭了。除非把show属性设置为false
因此我们需要给窗口添加一个关闭按钮:
并且,我们还给按钮绑定了点击事件,回调函数为closeWindow。
接下来,编写closeWindow函数:
closeWindow(){
// 关闭窗口
this.show = false;
}
效果:
b、新增品牌的表单页
接下来就是写表单了。我们有两种选择:
-
直接在dialog对话框中编写表单代码
-
另外编写一个组件,组件内写表单代码。然后在对话框引用组件
选第几种?
我们选第二种方案,优点:
-
表单代码独立组件,可拔插,方便后期的维护。
-
代码分离,可读性更好。
我们新建一个MyBrandForm.vue
组件:
将MyBrandForm引入到MyBrand中,这里使用局部组件的语法:
// 导入自定义的表单组件
import MyBrandForm from ‘./MyBrandForm’
修改一下表单的名称以及添加一些内容
<my-brand-form @close=“closeWindow” >
然后通过components属性来指定局部组件:
最后
自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。
深知大多数初中级Android工程师,想要提升技能,往往是自己摸索成长,自己不成体系的自学效果低效漫长且无助。
因此收集整理了一份《2024年Web前端开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Android开发知识点!不论你是刚入门Android开发的新手,还是希望在技术上不断提升的资深开发者,这些资料都将为你打开新的学习之门!
如果你觉得这些内容对你有帮助,需要这份全套学习资料的朋友可以戳我获取!!
由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!
g对话框中编写表单代码
- 另外编写一个组件,组件内写表单代码。然后在对话框引用组件
选第几种?
我们选第二种方案,优点:
-
表单代码独立组件,可拔插,方便后期的维护。
-
代码分离,可读性更好。
我们新建一个MyBrandForm.vue
组件:
将MyBrandForm引入到MyBrand中,这里使用局部组件的语法:
// 导入自定义的表单组件
import MyBrandForm from ‘./MyBrandForm’
修改一下表单的名称以及添加一些内容
<my-brand-form @close=“closeWindow” >
然后通过components属性来指定局部组件:
最后
自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。
深知大多数初中级Android工程师,想要提升技能,往往是自己摸索成长,自己不成体系的自学效果低效漫长且无助。
因此收集整理了一份《2024年Web前端开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
[外链图片转存中…(img-LCdhGMWi-1715532176711)]
[外链图片转存中…(img-599Rk6YM-1715532176712)]
[外链图片转存中…(img-OebWQaPb-1715532176712)]
既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Android开发知识点!不论你是刚入门Android开发的新手,还是希望在技术上不断提升的资深开发者,这些资料都将为你打开新的学习之门!
如果你觉得这些内容对你有帮助,需要这份全套学习资料的朋友可以戳我获取!!
由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!