想要了解Upload更多请看这里 - > https://ng.ant.design/components/upload/zh
本文注重实现,并补充说明所用知识点~
背景:获取图片并在列表中显示缩略图且可预览图片,可向列表中添加新的图片或删除图片。
先上代码:
test.component.ts
import { Component, OnInit } from '@angular/core';
import { UploadFile } from 'ng-zorro-antd';
import { Obj } from './obj';
@Component({
selector: 'app-test',
templateUrl: './test.component.html',
styleUrls: ['./test.component.less'],
})
export class TestComponent implements OnInit {
public addObj: Obj = new Obj();
imageList: Array = []; // 图片数组
imageList_copy: Array = []; //图片数组
showUploadList = {
showPreviewIcon: true,
showRemoveIcon: true,
hidePreviewIconInNonImage: true
};
previewImage: string | undefined = '';
previewVisible = false;
/**
* 获取详情
* @param id id
*/
getInfo(id): void {
this.service.getInfo(id)
.subscribe((res: Result) => {
if (res.rlt == 0) {
this.addObj = res.datas;
this.imageList = this.addObj.contentList.filter(ele => { return ele.contentType == 0 });
this.imageList.forEach(element => {
element['url'] = element.filePath.replace('\\', '\/') + '\/' + element.storeName;
});
this.imageList_copy = Object.assign([], this.imageList);
}
});
}
handlePreview = (file: UploadFile) => {
this.previewImage = file.url || file.thumbUrl;
this.previewVisible = true;
};
//上传图片
upLoadChange(event) {
let file = event ? event.file : null;
let datas = file && file.id ? file : file.response && file.response.rlt == 0 && file.response.datas;
if (datas) {
if (event.type == 'success') {
this.imageList_copy.push(datas);
console.log('after upload', this.imageList_copy);
this.imageList_copy.forEach(ele => {
if (this.addObj.contentList.indexOf(ele) == -1) {
this.addObj.contentList.push(ele);
}
})
} else if (event.type == 'removed') {
this.deleteImageById(datas.id, this.imageList_copy);
console.log('after removed', this.imageList_copy);
}
}
}
deleteImageById(id, arr) {
let index = arr.findIndex(ele => ele.id == id);
if (arr.length > 0 && index != -1) {
arr.splice(index, 1);
this.addObj.contentList = arr; //更新附件数组
}
}
}
test.component.html
上传
参数 | 说明 | 类型 | 默认值 |
---|---|---|---|
[nzAction] | 必选参数, 上传的地址 | string | - |
[nzListType] | 上传列表的内建样式,支持三种基本样式 text, picture 和 picture-card | ‘text’ / ‘picture’ / ‘picture-card’ | ‘text’ |
[nzFileList] | 文件列表,双向绑定 | UploadFile[] | - |
(nzChange) | 上传文件改变时的状态 | EventEmitter< UploadChangeParam> | - |
[nzShowUploadList] | 是否展示 uploadList, 可设为一个对象,用于单独设定 showPreviewIcon 和 showRemoveIcon | boolean / { showPreviewIcon?: boolean, showRemoveIcon?: boolean } | true |
[nzPreview] | 点击文件链接或预览图标时的回调;注意:务必使用 => 定义处理方法。 | (file: UploadFile) => void | - |
注意!注意!!
[nzFileList] 是双向绑定!!!(一开始我就掉坑了 TT)
初始效果如图:
选择一张图片上传
有注意到用了Object.assign()拷贝方式吗?目的自己猜啦,这里不多说><
this.imageList_copy = Object.assign([], this.imageList);
重点说下ES6中增加的Object.assign()方法~
Object.assign方法用于对象的合并,将源对象( source )的所有可枚举属性,复制到目标对象( target )
Object.assign(target, source_1, ..., source_n)
它会修改target对象,然后将它返回:先将source_1对象的所有可枚举属性复制给target,然后依次复制source_1等的属性。
深拷贝和浅拷贝
涉及一下深拷贝和浅拷贝的概念。javascript中存储对象都是存地址的,所以浅拷贝是都指向同一块内存区块,而深拷贝则是另外开辟了一块区域。如下实例:
// 浅拷贝
const a = {t: 1, p: 'gg'};
const b = a;
b.t = 3;
console.log(a); // {t: 3, p: 'gg'}
console.log(b); // {t: 3, p: 'gg'}
//深拷贝
const c = {t: 1, p: 'gg'};
const d = deepCopy(c);
d.t = 3;
console.log(c); // {t: 1, p: 'gg'}
console.log(d); // {t: 3, p: 'gg'}
明显看出,浅拷贝在改变其中一个值时,会导致其他也一起改变,而深拷贝不会。
Object.assign()
现在用es6 中的Object.assign() 方法,举举例子:
// Cloning an object
let obj = { a: 1 };
let copy = Object.assign({}, obj);
console.log(copy); // { a: 1 }
// Merging objects
let o1 = { a: 1 };
let o2 = { b: 2 };
let o3 = { c: 3 };
let obj1 = Object.assign(o1, o2, o3);
console.log(obj1); // { a: 1, b: 2, c: 3 }
console.log(o1); // { a: 1, b: 2, c: 3 }, target object itself is changed.
console.log(o2); // { b: 2 }
console.log(o3); // { c: 3 }
虽然既可以复制又可以混合对象,但需要注意的是它只merge根属性,下面的就不做处理了。 且看例子:
const defaultOpt = {
title: {
text: 'hello world',
subtext: 'It\'s my world.'
}
};
const opt = Object.assign({}, defaultOpt, {
title: {
subtext: 'Yes, your world.'
}
});
console.log(opt);
// 预期结果
{
title: {
text: 'hello world',
subtext: 'Yes, your world.'
}
}
// 实际结果
{
title: {
subtext: 'Yes, your world.'
}
}
稍微处理一下:
const defaultOpt = {
title: {
text: 'hello world',
subtext: 'It\'s my world.'
}
};
const opt = Object.assign({}, defaultOpt);
opt.title.subtext = 'Yes, your world.';
console.log(opt);
// 结果正常
{
title: {
text: 'hello world',
subtext: 'Yes, your world.'
}
}
但是,很悲催的是:
const defaultOpt = {
title: {
text: 'hello world',
subtext: 'It\'s my world.'
}
};
const opt1 = Object.assign({}, defaultOpt);
const opt2 = Object.assign({}, defaultOpt);
opt2.title.subtext = 'Yes, your world.';
console.log('opt1:');
console.log(opt1);
console.log('opt2:');
console.log(opt2);
// 结果
opt1:
{
title: {
text: 'hello world',
subtext: 'Yes, your world.'
}
}
opt2:
{
title: {
text: 'hello world',
subtext: 'Yes, your world.'
}
}
我们并没有去更改opt1 的subtext ,只是改了opt2 的。但结果两个配置变得一模一样
这说明一点:在title 这一层只是简单的浅拷贝 ,而没有继续深入的深拷贝。
总结
Object.assign()
只是一级属性复制,比浅拷贝多深拷贝了一层而已。实行的是浅拷贝
,而不是深拷贝。也就是说,如果源对象某个属性的值是对象,那么目标对象拷贝得到的是这个对象的引用。用的时候,还是要注意这个问题的。
附
一个可以简单实现深拷贝的方法:const obj1 = JSON.parse(JSON.stringify(obj));
先将一个对象转成json字符串,然后又将字符串转回对象。
const defaultObj = {
title: {
text: 'hello world',
subtext: 'It\'s my world.'
}
};
const obj1 = JSON.parse(JSON.stringify(defaultObj));
const obj2 = JSON.parse(JSON.stringify(defaultObj));
obj2.title.subtext = 'Yes, your world.';
console.log('obj1:');
console.log(obj1);
console.log('obj2:');
console.log(obj2);
// 结果
obj1:
{
title: {
text: 'hello world',
subtext: 'It\'s my world.'
}
}
obj2:
{
title: {
text: 'hello world',
subtext: 'Yes, your world.'
}
}