问题集

Object.keys() & for…in 顺序

Object.keys在内部会根据属性名key的类型进行不同的排序逻辑。分三种情况:

  • 如果属性名的类型是Number,那么Object.keys返回值是按照key从小到大排序 ‘1’也算是number
  • 如果属性名的类型是String,那么Object.keys返回值是按照属性被创建的时间升序排序。
  • 如果属性名的类型是Symbol,那么逻辑同String相同

解构赋值

可以取代 delete xxx

1
2
3
4
5
6
7

const { name,...rest } = { name:'z', age:10, sex:'female' }
// name = 'z' , rest = { age:10, sex:'female' }

const [ item,...rest ] = [ { first:'a' }, 23, 55 ]
// item = { first:'a' } , rest = [ 23, 55 ]

json简写

keyvalue名字一样的时候可以省略value

1
2
3
4
5
6
7

let name = 'zz'
let age = 10

let json = { name, age, say(){ console.log('') } }
// => let json = { name:name, age:age, say:function(){ console.log('') } }

JavaScript浮点数运算精度问题

描述

一开始看到百度的部分解决方案是通过扩大N倍换为整数,但是亲测有问题。直接乘10的N次方部分数据还是会出现精度问题。

解决

  1. 我是通过先转换成字符串、然后去掉小数点转为整数
  2. 两个数之间小数点位数进行比较、少的在乘10的n-m次方,运算后在除以10的Math.max(n,m)

目前没发现bug、不确定是正确的方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
/**
* 浮点数运算
* type: 1 加法,2 减法
*/
function floatAddOrMinus(type: number, arg1: string, arg2: string) {
let len1 = 0
let len2 = 0
let m = 0
let item1 = 0
let item2 = 0;
try {
len1 = arg1.split(".")[1].length;
} catch (e) {
len1 = 0;
}
try {
len2 = arg2.split(".")[1].length;
} catch (e) {
len2 = 0;
}

if (len1 > len2) {
m = len1;
item1 = 0;
item2 = len1 - len2;
} else {
m = len2;
item1 = len2 - len1;
item2 = 0;
}

if (type === 1) {
return (
(Number(arg1.replace(".", "")) * 10 ** item1 +
Number(arg2.replace(".", "")) * 10 ** item2) /
10 ** m
);
} else {
return (
(Number(arg1.replace(".", "")) * 10 ** item1 -
Number(arg2.replace(".", "")) * 10 ** item2) /
10 ** m
);
}
}

vue3中ref和其他属性绑定值重名导致绑定失效

群友遇到的问题、我一开始看着也没觉得哪里不对。感觉以后能用的上,先存着 。

描述

使用element-plus 中的 el-form 的时候,model绑定了formData,但是在页面上对表单进行操作的时候,数据绑定无效。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<el-form 
ref="formData"
:model="formData"
:rules="rule">
<el-row justify="center">
<el-col :span="12">
<el-form-item label="入库类型" prop="inOutType">
<el-select v-model="formData.inOutType" clearable>
<el-option label="外购" value="外购"></el-option>
<el-option label="其他" value="其他"></el-option>
</el-select>
</el-form-item>
</el-col>
</el-row>
</el-form>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
// ...
setup(){
let formData: IEmptyObject = reactive({
warningUseTime: 0,
typeName: '',
categoryCode: '',
categoryName: '',
maintenanceCode: '',
maintenanceName: '',
model: '',
attribute: '',
unit: '',
warningProductionQuantity: 0
});

return { formData }
}
// ...

错误原因

ref绑定的内容和model绑定的内容重复了,vue3中ref绑定的内容也是通过在setup中定义变量进行获取。具体原因还没仔细看,估计是ref的优先级更高?

proxy多个路由代理

重写失效、请求路径包含某个 代理名 代理失效。

记下 还没解决

哈希路由引起样式问题

在一个页面引入了样式,并且添加了 scoped ,但是在进行页面跳转的时候,这些引入的样式会影响另一页面。刷新之后就好了

初步猜测是因为路由用的哈希模式的原因

hash 值变化不会导致浏览器向服务器发出请求

所以在第一个页面加载的样式,在跳转之后没有刷新,样式就一直会存在,因此影响到了页面的样式

解决方法

  • emit父子组件通讯,点击事件触发后、强制刷新
  • 监听hash值的变化、变化之后、强制刷新
1
2
3
4
5
6
7
8
9
10
11
12
setup: () => {
const route = useRoute();
watch(
() => route.path,
(to, from) => {
if (from.includes("papercss") && from !== to) {
location.reload();
}
}
);
}

el-date-picker限制时间选择范围

两个时间选择器、开始时间与结束时间的时间选择范围为24h,并且精确到 (format="yyyy-MM-dd HH:mm")

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
<!-- 基本使用 -->
<el-form-item prop="beginDateStr" label="开始时间">
<el-date-picker
v-model="formData.beginDateStr"
type="datetime"
placeholder="选择日期时间"
format="yyyy-MM-dd HH:mm"
>
</el-date-picker>
</el-form-item>
<el-form-item prop="endDateStr" label="结束时间">
<el-date-picker
v-model="formData.endDateStr"
type="datetime"
format="yyyy-MM-dd HH:mm"
placeholder="选择日期时间"
>
</el-date-picker>
</el-form-item>

Picker Options 配置

开始时间限制

首先对开始时间进行限制 限制在当前日期之前;并且当开始日期改变的时候,结束日期清空

disabledDate 日期禁用范围

1
2
3
4
5
6
7
8
<el-date-picker
v-model="formData.beginDateStr"
type="datetime"
placeholder="选择日期时间"
format="yyyy-MM-dd HH:mm"
:picker-options="pickerOptionsStart"
@change="handleChangeStart"
></el-date-picker>
1
2
3
4
5
6
7
8
9
private pickerOptionsStart = {
disabledDate: (time: Date) => {
return time.getTime() > Date.now();
},
}

private handleChangeStart() {
this.formData.endDateStr = '';
}

结束时间限制

因为是24h限制、所以 开始时间+24h 和 开始时间-24h 的时间都得禁用;精确到分钟,小时和分钟也得进行限制

selectableRange 时间选择范围
这个属性没有在el-date-picker里面,在el-time-picker里面,个人觉得文档写的不是很人性…
因为跨天的话、时间范围是不一样的 比如开始时间是2021-05-31 02:00
那么结束时间的范围是2021-05-31 02:00 - 2021-06-01 02:00
如果选的是31号 则 selectableRange = '02:00-23:59'
如果选的是1号 则 selectableRange = '00:00-02:00'
所以还得对日期选择进行监听,本来是想通过点击/change事件进行监听的
但是无效,然后通过监听input框内数据的变化 来进行监听

1
2
3
4
5
6
7
8
9
10
11
<el-date-picker
v-model="formData.endDateStr"
type="datetime"
format="yyyy-MM-dd HH:mm"
placeholder="选择日期时间"
@input="handleChangeInputDate($event)"
:picker-options="{
disabledDate: (time) => hanldeDisabledDate(time),
selectableRange: dafaulttime,
}"
></el-date-picker>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
private dafaulttime: string = '00:00:00-23:59:59';

private handleChangeInputDate(e: Date) {
// 区别 同一天和下一天的时间限制
if (this.formData.beginDateStr) {
const begin = new EasyDate(this.formData.beginDateStr).format('dd');
const end = new EasyDate(e).format('dd');
if (begin === end) {
this.dafaulttime =
new EasyDate(this.formData.beginDateStr).format('HH:mm:ss') +
'-23:59:59';
} else {
this.dafaulttime =
'00:00:00-' +
new EasyDate(this.formData.beginDateStr).format('HH:mm:ss');
}
}
}

private hanldeDisabledDate(time: Date) {
// 24 * 3600 * 1000 == 8.64e7
if (this.formData.beginDateStr) {
const pickerMinDate = new Date(this.formData.beginDateStr).getTime();
const maxTime = pickerMinDate + 8.64e7;
const minTime = pickerMinDate - 8.64e7;
return time.getTime() >= maxTime || time.getTime() <= minTime;
} else {
return time.getTime() > Date.now();
}
}

针对daterangedatetimerange类型进行时间限制

不仅仅需要配置disabledDate,还需要配置onPick获取当前点击的日期
onPick Function({ maxDate, minDate }) 选中日期执行的回调,只选择一个的时候返回的minDate

实例:只能选择31天的范围

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<span>起止时间:</span>
<el-date-picker
style="width: 240px; margin-right: 10px"
v-model="dateRange"
type="datetimerange"
range-separator="至"
value-format="yyyy-MM-dd HH:mm:ss"
start-placeholder="开始日期"
end-placeholder="结束日期"
@change="dateChange"
:picker-options="{
disabledDate: (time) => hanldeDisabledDate(time),
onPick: (time) => hanldeOnPick(time),
}"
:clearable="false"
></el-date-picker>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24

private hanldeOnPick(e: IEmptyObject) {
if (!e.maxDate) {
const timeRange = 8.64e7 * 31;
this.pickDateRange.maxTime = e.minDate.getTime() + timeRange;
this.pickDateRange.minTime = e.minDate.getTime() - timeRange;
} else {
this.pickDateRange.minTime = null;
this.pickDateRange.maxTime = null;
}
}

private hanldeDisabledDate(e: Date) {
const pickerDate = e.getTime();
if (this.pickDateRange.minTime && this.pickDateRange.maxTime) {
return (
e.getTime() <= this.pickDateRange.minTime ||
e.getTime() >= Date.now() ||
e.getTime() >= this.pickDateRange.maxTime
);
} else {
return e.getTime() >= Date.now();
}
}

主要问题

结束时间的 picker-options 属性,如果直接通过一个对象传递的话 ,会失效..,不清楚原因。我猜测是双向数据绑定相关的东西的问题

1
2
3
4
5
6
7
8
9
10
11
12
13
// √ 生效
:picker-options="{
disabledDate: (time) => hanldeDisabledDate(time),
selectableRange: dafaulttime,
}"

// × 不生效
:picker-options="pickerOption"

private pickerOption = {
disabledDate: (time) => hanldeDisabledDate(time),
selectableRange: dafaulttime,
}

multipart/form-data 文件流请求和参数相关

一般的接口请求都是以json的形式进行传输、这次的表单会有文件上传的情况 所以用formdata的形式进行传输。

表单数据存在body内 且content-type需要设置为application/json,文件数据存在file内

  1. formData请求,参数必须为FromData类型的
1
2
3
4
5
6
let params = new FormData()

params.append('file',value,name)

// params.get('file') 获取file值
// params.set('file',newValue) 设置file值
  1. 对于不是文本/二进制类型的数据,还需要使用Blob对象进行转换

如上图所示,body内传递的是Object对象,而且,bodycontent-type需要设置为application/json类型

1
2
3
4
5
let obj = {...}
let blob = new Blob([JSON.stringify(obj)],{type:'application/json'})

params.append('body',blob)

  1. axios主要配置
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
// http.ts
const instance = axios.create({
timeout: 600000, // by huangrong
headers: { 'Content-Type': 'application/json' },
baseURL: '/',
// transformResponse: (data: any) => {
// //
// }
});

instance.upload = (url, data, config = {}, params) => {
const formData = new FormData();
data.forEach(item => {
formData.append('file', item.value, item.name || item.filename);
});
if (params && Object.keys(params).length > 0) {
for (const m in params) {
if (params.hasOwnProperty(m)) {
const key = m;
const value = params[m];
formData.append(key, value);
}
}
}
return instance.request({
method: 'post',
...config,
url,
data: formData,
});
};


// 请求拦截器
instance.interceptors.request.use(config => {
const { params = {} } = config;
config.params = { ...params, time: new Date().getTime() };
// add token if need
config.headers = {
...(config.headers || {}),
'X-Auth-Token': CookieStorage.token,
'X-Stargate-AppId': 25,
};
return config;
}, err => {
// show err
}
);

// common-api.ts
export function uploadFile(path: string, file: IUploadParam[], config?: AxiosRequestConfig, params?: IEmptyObject) {
return http.upload(path, file, config, params).then(res => {
return Promise.resolve(res.data);
});
}

// index.vue
uploadFile(
this.path,
(this.$refs.imageUpload as any).fileList,
{},
{
body: new Blob(
[
JSON.stringify({
...this.formData,
factory: this.factory,
workshop: this.workshop,
}),
],
{ type: 'application/json' }
),
}
)

axios实现文件导出功能,无法获取response的异常信息

如图所示: 上方是调文件导出接口,返回的异常信息。下方是普通请求获取的异常信息。上方的data内没有errorMsg

错误原因

可以看到上方红圈内的dataBlob类型的(文件存储类型),所以不能直接获取,需要FileReader对象进行处理,转换获取blob、file文件的数据。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
// 响应拦截器
instance.interceptors.response.use(response => {
return Promise.resolve(response);
}, error => {
// show error_msg and reject
// console.log('响应失败信息', error.response);
if (error && error.response && error.response.status) {
let errCode = 0;
let errMsg = '';
if (!!error.response.data) {
// 文件流错误处理
if (error.response.config.responseType === 'blob') {
const reader = new FileReader();
reader.readAsText(error.response.data);
reader.onload = () => {
try {
const { errorMsg } = JSON.parse(reader.result as string);
errMsg = errorMsg;
handleError(error.response.status, errMsg);
} catch (error) {
console.log('解析错误');
}
};
} else {
// 普通错误处理
const { status, errorMsg } = error.response.data;
errCode = status;
errMsg = errorMsg;
handleError(error.response.status, errMsg);
}
}
}
return Promise.reject(error);
});

扫一扫,分享到微信

微信分享二维码
来发评论吧~
Powered By Valine
v1.4.14
  • Copyrights © 2019-2023 John Doe
  • Visitors:1918 | Views:3637

请我喝杯咖啡吧~

支付宝
微信