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
运行效果
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<ageResult> 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属性来指定局部组件:
components:{
MyBrandForm
}
c、编写表单
i、表单
查察官网文档,找到表单干系内容
v-form,表单组件,内部可以有很多输入项。v-form有下面的属性:
- value:true,代表表单验证通过;false,代表表单验证失败
v-form提供了两个方法:
- reset:重置表单数据
- validate:校验整个表单数据,条件是你写好了校验规则。返回Boolean表示校验成功或失败
我们在data中界说一个valid属性,跟表单的value进行双向绑定,观察表单是否通过校验,同时把等会要跟表单关联的品牌brand对象声明出来:
export default {
name: “my-brand-form”,
data() {
return {
valid:false, // 表单校验效果标志
brand:{
name:‘’, // 品牌名称
letter:‘’, // 品牌首字母
image:‘’,// 品牌logo
categories:[], // 品牌所属的商品分类数组
}
}
}
}
然后,在页面先写一个表单:
修改会原来的路由规则
ii、文本框
我们的品牌总共需要这些字段:
表单项主要包罗文本框、密码框、多选框、单选框、文本域、下拉选框、文件上传等。思考下我们的品牌需要哪些?
- 文本框:品牌名称、品牌首字母都属于文本框
- 文件上传:品牌需要图片,这个是文件上传框
- 下拉选框:商品分类提前已经界说好,这里需要通过下拉选框展示,提供给用户选择。
先看文本框,昨天已经用过的,叫做v-text-field:
查察文档,v-text-field有以下关键属性:
- append-icon:文本框后追加图标,需要填写图标名称。无默认值
- clearable:是否添加一个清空图标,点击会清空文本框。默认是false
- color:颜色
- counter:是否添加一个文本计数器,在角落表现文本长度,指定true或允许的组大长度。无默认值
- dark:是否应用黑暗色调,默认是false
- disable:是否禁用,默认是false
- flat:是否移除默认的动画效果,默认是false
- full-width:指定宽度为全屏,默认是false
- hide-details:是否因此错误提示,默认是false
- hint:输入框的提示文本
- label:输入框的标签
- multi-line:是否转为文本域,默认是false。文本框和文本域可以自由切换
- placeholder:输入框占位符文本,focus后消散
- required:是否为必填项,假如是,会在label后加*,不具备校验功能。默认是false
- rows:文本域的行数,multi-line为true时才有效
- rules:指定校验规则及错误提示信息,数组结构。默认[]
- single-line:是否单行文本表现,默认是false
- suffix:表现后缀
接下来,我们先添加两个字段:品牌名称、品牌的首字母,校验规则暂时不写:
iii、级联下拉菜单
接下来就是商品分类了,按照刚才的分析,商品分类应该是下拉选框。
但是各人仔细思考,商品分类包罗三级。在展示的时间,应该是先由用户选中1级,才表现2级;选择了2级,才表现3级。形成一个多级分类的三级联动效果。
这个时间,就不是普通的下拉选框,而是三级联动的下拉选框!
如许的选框,在Vuetify中并没有提供(它提供的是根本的下拉框)。因此我已经给各人编写了一个无穷级联动的下拉选框,可以或许满足我们的需求。
<v-cascader
url=“/item/category/list”
multiple
required
v-model=“brand.categories”
label=“请选择商品分类”/>
- url:加载商品分类选项的接口路径
- multiple:是否多选,这里设置为true,因为一个品牌可能有多个分类
- requried:是否是必须的,这里为true,会在提示上加*,提示用户
- v-model:关联我们brand对象的categories属性
- label:笔墨说明
演示效果如下
iV、文件上传项
在Vuetify中,也没有文件上传的组件。
还好,我已经给各人写好了一个文件上传的组件:
我们添加上传的组件:
品牌LOGO:
<v-upload
v-model=“brand.image”
url=“/upload”
:multiple=“false”
:pic-width=“250”
:pic-height=“90”
/>
注意:
- 文件上传组件自己没有提供笔墨提示。因此我们需要自己添加一段笔墨说明
- 我们要实现笔墨和图片组件左右放置,因此这里利用了v-layout布局组件:
- layout添加了row属性,代表这是一行,假如是column,代表是多行
- layout下面有v-flex组件,是这一行的单位,我们有2个单位
- <v-flex xs3> :表现笔墨说明,xs3是响应式布局,代表占12格中的3格
- 剩下的部分就是图片上传组件了
- v-upload:图片上传组件,包罗以下属性:
- v-model:将上传的效果绑定到brand的image属性
- url:上传的路径,我们先随便写一个。
- multiple:是否运行多图片上传,这里是false。因为品牌LOGO只有一个
- pic-width和pic-height:可以控制l图片上传后展示的宽高
最闭幕果:
V、按钮
上面已经把全部的表单项写完。最后就差提交和清空的按钮了。
在表单的最下面添加两个按钮:
<v-btn @click=“submit” color=“primary”>提交
<v-btn @click=“clear” >重置
- 通过layout来进行布局,my-4增大上下边距
- v-spacer占用肯定空间,将按钮都倾轧到页面右侧
- 两个按钮分别绑定了submit和clear事故
我们先将方法界说出来:
methods:{
submit(){
// 提交表单
},
clear(){
// 重置表单
}
}
重置表单相对简朴,因为v-form组件已经提供了reset方法,用来清空表单数据。
只要我们拿到表单组件对象,就可以调用方法了。
我们可以通过$refs内置对象来获取表单组件。
首先,在表单上界说ref属性:
clear(){
// 重置表单
this.$refs.myBrandForm.reset();//获取带ref对应的表单数据
//设置商品分类为空
this.categories = [];
}
要注意的是,这里我们还手动把this.categories清空了,因为我写的级联选择组件并没有跟表单结合起来。需要手动清空。
(2)表单校验
Vuetify的表单校验,是通过rules属性来指定的:
校验规则的写法:
nameRules: [
v => !!v || “品牌名称不能为空”,
v => v.length > 1 || “品牌名称至少2位”
],
letterRules: [
v => !!v || “首字母不能为空”,
v => /1{1}$/.test(v) || “品牌字母只能是1个字母”
]
效果:
(3)提交表单信息
在submit方法中添加表单提交的逻辑:
submit(){
// 提交表单
if(this.$refs.myBrandForm.validate()){
//界说一个哀求参数的对象,通过结构表达式来获取brand当中的属性
const { categories,letter, …params } = this.brand;
//数据库当中只需要保存分类id即可,因此我们对categories的值进行处理,只保存id,并转换为字符串
params.cids = categories.map(c => c.id).join(“,”);
//将字母都处理为大写
params.letter = letter.toUpperCase();
// 5、将数据提交到背景
this.$http.post(‘/item/brand’, 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、发起哀求
- 6、弹窗提示成功还是失败,这里用到的是我们的自界说组件功能message组件:
这个插件把$message对象绑定到了Vue的原型上,因此我们可以通过this.$message来直接调用。
包罗以下常用方法:
- info、error、success、warning等,弹出一个带有提示信息的窗口,色调与为普通(灰)、错误(红色)、成功(绿色)和警告(黄色)。利用方法:this.$message.info(“msg”)
- confirm:确认框。用法:this.$message.confirm("确认框的提示信息"),返回一个Promise
- 设置在提交成功以后关闭窗口
自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到如今。
深知大多数前端工程师,想要提升技能,每每是自己探索发展或者是报班学习,但对于培训机构动则几千的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!
因此网络整理了一份《2024年Web前端开辟全套学习资料》,初衷也很简朴,就是希望可以或许帮助到想自学提升又不知道该从何学起的朋友,同时减轻各人的负担。
既有适合小白学习的零根本资料,也有适合3年以上履历的小同伴深入学习提升的进阶课程,根本涵盖了95%以上前端开辟知识点,真正体系化!
由于文件比较大,这里只是将部分目次截图出来,每个节点里面都包罗大厂面经、学习笔记、源码讲义、实战项目、解说视频,并且会连续更新!
假如你觉得这些内容对你有帮助,可以扫码获取!!(备注:前端)
最后
分享一套阿里大牛整理的前端资料给各人,点击前端校招面试题精编剖析大全即可获取
❤️ 谢谢支持,喜欢的话别忘了 关注、点赞哦。
_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzQ0NzU3MDM0,size_16,color_FFFFFF,t_70)
- 1、通过this.$refs.myBrandForm选中表单,然后调用表单的validate方法,进行表单校验。返回boolean值,true代表校验通过
- 2、通过解构表达式来获取brand中的值,categories和letter需要处理,单独获取。其它的存入params对象中
- 3、品牌和商品分类的中间表只保存两者的id,而brand.categories中保存的数对象数组,里面有id和name属性,因此这里通过数组的map功能转为id数组,然后通过join方法拼接为字符串
- 4、首字母都处理为大写保存
- 5、发起哀求
- 6、弹窗提示成功还是失败,这里用到的是我们的自界说组件功能message组件:
这个插件把$message对象绑定到了Vue的原型上,因此我们可以通过this.$message来直接调用。
包罗以下常用方法:
- info、error、success、warning等,弹出一个带有提示信息的窗口,色调与为普通(灰)、错误(红色)、成功(绿色)和警告(黄色)。利用方法:this.$message.info(“msg”)
- confirm:确认框。用法:this.$message.confirm("确认框的提示信息"),返回一个Promise
- 设置在提交成功以后关闭窗口
自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到如今。
深知大多数前端工程师,想要提升技能,每每是自己探索发展或者是报班学习,但对于培训机构动则几千的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!
因此网络整理了一份《2024年Web前端开辟全套学习资料》,初衷也很简朴,就是希望可以或许帮助到想自学提升又不知道该从何学起的朋友,同时减轻各人的负担。
[外链图片转存中…(img-pR3TtD6M-1712938045455)]
[外链图片转存中…(img-iGf1caya-1712938045456)]
既有适合小白学习的零根本资料,也有适合3年以上履历的小同伴深入学习提升的进阶课程,根本涵盖了95%以上前端开辟知识点,真正体系化!
[外链图片转存中…(img-fjIOjkdv-1712938045456)]
由于文件比较大,这里只是将部分目次截图出来,每个节点里面都包罗大厂面经、学习笔记、源码讲义、实战项目、解说视频,并且会连续更新!
假如你觉得这些内容对你有帮助,可以扫码获取!!(备注:前端)
最后
分享一套阿里大牛整理的前端资料给各人,点击前端校招面试题精编剖析大全即可获取
❤️ 谢谢支持,喜欢的话别忘了 关注、点赞哦。
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。 |