论iview的DatePicker获取到的时间 2021-04-24 01:01 iview的DatePicker获取到的时间会比正确时间少8个小时,接下来我将复现这些场景,及如何解决他们。 由于我不是“正统”的前端开发人员,所以可能某些地方有笔误之处,欢迎指出。 如果没有耐心可直接跳到最后看第四章的【总结】部分。 # 一、第一种写法 > 这段是在10:50开始写的 :value="searchData.startBillDate" @on-change="searchData.startBillDate=$event" ```vue <template> <FormItem label="查询时间" prop='searchDate'> <DatePicker :value="searchData.startBillDate" type="date" @on-change="searchData.startBillDate=$event" :editable="false" style="width:200px;"></DatePicker> - <DatePicker :value="searchData.endBillDate" type="date" @on-change="searchData.endBillDate=$event" :editable="false" style="width:200px;"></DatePicker> </FormItem> <Button type="primary" style="margin-right: 20px;" @click="searchFormQuery()">查询</Button> </template> <script> data() { return { searchData: { startBillDate: null, endBillDate: null }, }; }, created() { this.initSearchData(); }, initSearchData() { let currentDate = new Date(); currentDate.setDate(currentDate.getDate() - 30); console.log(currentDate); console.log(new Date()); this.$set(this.searchData, 'startBillDate', currentDate); this.$set(this.searchData, 'endBillDate', new Date()); console.log("打印searchData"); console.log(this.searchData.startBillDate); console.log(this.searchData.endBillDate); }, searchFormQuery() { var searchData = this.searchData; console.log(searchData.startBillDate); console.log(searchData.endBillDate); //发请求 data: searchData } </script> ``` ## 1.1、当刷新页面进入时 显示效果: [](https://imgtu.com/i/cOc0wn) 前端打印: Wed Mar 24 2021 10:50:18 GMT+0800 (中国标准时间) Fri Apr 23 2021 10:50:18 GMT+0800 (中国标准时间) 打印searchData Wed Mar 24 2021 10:50:18 GMT+0800 (中国标准时间) Fri Apr 23 2021 10:50:18 GMT+0800 (中国标准时间) 发请求前一刻前段打印: Wed Mar 24 2021 10:50:18 GMT+0800 (中国标准时间) Fri Apr 23 2021 10:50:18 GMT+0800 (中国标准时间) 通过Network查看该请求的Request Payload: startBillDate: "2021-03-24T02:50:18.413Z" endBillDate: "2021-04-23T02:50:18.463Z" 初始化时,时间是正确的,但是发送请求的时候打印出来的时间比正确的少8个小时。也就意味着,如果进入页面后不做任何动作立即查询,送给后端的时间是错误的。 比如当前是早上8点之前,那么发送请求的时候送给后端的时间就会是前一天! 如果当前时间是早上8点之后,那么发送请求的时候送给后端的时间是今天,但是时间也会少8小时,此时若后端需要接收年月日数据则没有影响,如果接收年月日时分秒数据则有影响。 ## 1.2、当选择时间时 我把开始时间选择到3月1号 [](https://imgtu.com/i/cO2EvD) 发请求前一刻前段打印: 2021-03-01 Fri Apr 23 2021 11:05:07 GMT+0800 (中国标准时间) 通过Network查看该请求的Request Payload: startBillDate: "2021-03-01" endBillDate: "2021-04-23T03:05:07.074Z" 我们给时间框添加了`@on-change="searchData.startBillDate=$event"`,那么当手动点击时间框改变时间时,就触发了on-change事件,此时就会把时间结果付给startBillDate,所以请求前打印和请求中的startBillDate都是我们真是所选的时间,2021-03-01,不会因为任何时间区域而有所改变。 同理,由于我们没有动结束时间,所以endBillDate参数也还是像之前一样,发送请求前打印还是好好地正确时间,在请求中真正给后端的参数就错误了,少了8小时。 ## 1.3、小结 经过上面分析我们知道,这种写法,**若我们手动选择时间,那么时间就一定是正确的**,但是当我们没有选择时间时,无论前端控制台打印的时间有多正确,发送给后端的时间与我们预期的时间比都是错误的,少了8小时。 那么有没有办法解决不手动选择时间时的问题呢? # 二、第二种写法 > 这段是在14:10开始写的 v-model ```vue <FormItem label="查询时间" prop='searchDate'> <DatePicker v-model="searchData.startBillDate" type="date" :editable="false" style="width:200px;"></DatePicker> - <DatePicker v-model="searchData.endBillDate" type="date" :editable="false" style="width:200px;"></DatePicker> </FormItem> <script> data() { return { searchData: { startBillDate: null, endBillDate: null }, }; }, created() { this.initSearchData(); }, initSearchData() { let currentDate = new Date(); currentDate.setDate(currentDate.getDate() - 30); console.log(currentDate); console.log(new Date()); this.$set(this.searchData, 'startBillDate', currentDate); this.$set(this.searchData, 'endBillDate', new Date()); console.log("打印searchData"); console.log(this.searchData.startBillDate); console.log(this.searchData.endBillDate); }, searchFormQuery() { var searchData = this.searchData; console.log(searchData.startBillDate); console.log(searchData.endBillDate); //发请求 data: searchData } </script> ``` ## 2.1、当刷新进入页面时 显示效果: [](https://imgtu.com/i/cOv2es) 前端打印: Wed Mar 24 2021 14:13:18 GMT+0800 (中国标准时间) Fri Apr 23 2021 14:13:19 GMT+0800 (中国标准时间) 打印searchData Wed Mar 24 2021 14:13:18 GMT+0800 (中国标准时间) Fri Apr 23 2021 14:13:19 GMT+0800 (中国标准时间) 发请求前一刻前段打印: Wed Mar 24 2021 14:13:18 GMT+0800 (中国标准时间) Fri Apr 23 2021 14:13:19 GMT+0800 (中国标准时间) 通过Network查看该请求的Request Payload: startBillDate: "2021-03-24T06:13:18.981Z" endBillDate: "2021-04-23T06:13:19.001Z" 很显然,尽管发送之前是对的,实际发送给后端的数据还是错的,比当前正确时间少了8小时。 ## 2.2、当选择时间时 我把开始时间调到3月1号 [](https://imgtu.com/i/cOvMIx) 发生请求前一刻前端打印: Mon Mar 01 2021 00:00:00 GMT+0800 (中国标准时间) Fri Apr 23 2021 14:17:05 GMT+0800 (中国标准时间) 通过Network查看该请求的Request Payload: startBillDate: "2021-02-28T16:00:00.000Z" endBillDate: "2021-04-23T06:17:05.911Z" 选择了时间,和没有选择时间效果一样,都会比想要的时间少8小时。 ## 2.3、小结 这样看来在前端的时候,时间如果手动选择,则会选择为当天的0点,那么发送给后端的时间比这个时间少8小时就是前一天。如果没有手动选择时间,那么前端时间就是当前此刻的正确年月日时分秒,当发送到后端时,时间变为了少8小时。 当使用v-model时,无论如何我也没有找到解决这8小时时差的方法。 # 三、如何解决第一种写法的问题? > 这段是在14:35写的 第一种写法的问题就是没有手动选择时间时,立即查询,此时的时间是错误的。比当前正确的时间是少了8小时的。只要手动选择了就正确,因为手动选择的时候会把事件的结果付给变量,事件的结果一定是正确的。 ## 3.1、第一种解决办法 试着在`initSearchData`方法中添加时间转换 ```vue <script> ... console.log("打印searchData"); this.searchData.startBillDate = formatData.call(this.searchData.startBillDate, "yyyy-MM-dd"); //新增的语句 this.searchData.endBillDate = formatData.call(this.searchData.endBillDate, "yyyy-MM-dd"); //新增的语句 console.log(this.searchData.startBillDate); console.log(this.searchData.endBillDate); </script> ``` 刷新页面时,显示效果: [](https://imgtu.com/i/cOzRP0) 前端打印: Wed Mar 24 2021 14:36:01 GMT+0800 (中国标准时间) Fri Apr 23 2021 14:36:01 GMT+0800 (中国标准时间) 打印searchData 2021-03-24 2021-04-23 发请求前一刻前端打印: 2021-03-24 2021-04-23 通过Network查看该请求的Request Payload: startBillDate: "2021-03-24" endBillDate: "2021-04-23" 这样看起来初始化是正确的,但是会不会是我们在初始化时间时转换了,所以抹去了时分秒,真正的数据时分秒还是少8小时呢? 我们在当天早0~8点观察下。 现在是2021-4-24 0:22,观察下,刷新页面时,页面效果: [](https://imgtu.com/i/cjnlcQ) 前端打印: Thu Mar 25 2021 00:21:14 GMT+0800 (中国标准时间) Sat Apr 24 2021 00:21:14 GMT+0800 (中国标准时间) 打印searchData 2021-03-25 2021-04-24 发请求前一刻前端打印: 2021-03-25 2021-04-24 通过Network查看该请求的Request Payload: startBillDate: "2021-03-25" endBillDate: "2021-04-24" [](https://imgtu.com/i/cjntA0) 再来手动选择一把: 选择开始时间为2021-03-01,结束时间为2021-04-01: 发请求前一刻前端打印: 2021-03-01 2021-04-01 通过Network查看该请求的Request Payload: startBillDate: "2021-03-01" endBillDate: "2021-04-01" 还有,真的是只要手动选时间就是正确的吗? 是的! ## 3.2、第二种解决办法 牺牲“美观度”换取正确性。大多数情况下,我们进行数据查询都会手动选择下时间,所以我们干脆不给默认时间,然后必须让用户自己选。 第一种写法如果不写`:value="searchData.endBillDate" `的话,刷新页面会不显示时间(这种情况下initSearchData()函数也不需要了): [](https://imgtu.com/i/cXpN1f) 必须要手动选择时间,当然一旦手动选择,时间往往是正确的(因为是事件结果赋给了变量): [](https://imgtu.com/i/cXprAs) 发请求前一刻前端打印: 2021-04-01 2021-05-01 通过Network查看该请求的Request Payload: startBillDate: "2021-04-01" endBillDate: "2021-05-01" # 四、总结 vue的`DatePicker`组件会得到错误的时间(比预期的少8小时),这在有些情况下会造成业务错误: 在使用传统的v-model时,总是会出错:当我们需要年月日时分秒数据时,后端拿到的会比预期少8个小时;当我们需要年月日数据时,后端拿到的会比比预期少一天。 解决这个问题需要使用 `@on-change="searchData.startDate=$event" ` 。在这种情况下,刷新页面不会初始化时间,即时间框是空的。必须手动选择年月日,选择后发送给后端的年月日数据一定是正确的。我把这种解决方式称为B写法。 若需要初始化时间,即刷新页面时间框有默认的时间,则需要同时使用 `:value="searchData.startDate"` , `@on-change="searchData.startDate=$event" ` , `this.searchData.startDate = formatData.call(this.searchData.startDate, "yyyy-MM-dd");` 三种做共同控制,才能达到刷新页面时有默认时间显示,且发送给后端正确的数据。我把这种解决方式称为A写法。 【其中searchData(查询数据)是你的model变量,startDate(开始时间)是model变量的时间属性,不要弄混了】 下面是A写法与B写法的具体内容: ## 4.1、B写法 > 效果:页面加载时不会初始化时间,需要手动选择时间,选择时间后均能发送给后端正确的年月日数据 ```vue <template> <FormItem label="查询时间" prop='searchDate'> <DatePicker type="date" @on-change="searchData.startDate=$event" :editable="false" style="width:200px;"></DatePicker> - <DatePicker type="date" @on-change="searchData.endDate=$event" :editable="false" style="width:200px;"></DatePicker> </FormItem> <Button type="primary" style="margin-right: 20px;" @click="searchFormQuery()">查询</Button> </template> <script> data() { return { searchData: { startBillDate: null, endBillDate: null }, }; }, created() { }, searchFormQuery() { var searchData = this.searchData; //发请求 data: searchData } </script> ``` ## 4.2、A写法 > 效果:页面加载时会初始化时间(也自定义设置初始化范围),且无论默认时间还是手动选择时间均能发送给后端正确的年月日数据 ```vue <template> <FormItem label="查询时间" prop='searchDate'> <DatePicker :value="searchData.startDate" type="date" @on-change="searchData.startDate=$event" :editable="false" style="width:200px;"></DatePicker> - <DatePicker :value="searchData.endDate" type="date" @on-change="searchData.endDate=$event" :editable="false" style="width:200px;"></DatePicker> </FormItem> <Button type="primary" style="margin-right: 20px;" @click="searchFormQuery()">查询</Button> </template> <script> data() { return { searchData: { startBillDate: null, endBillDate: null }, }; }, created() { this.initSearchData(); }, // 初始化时间 initSearchData() { let currentDate = new Date(); currentDate.setDate(currentDate.getDate() - 30); this.$set(this.searchData, 'startDate', currentDate); this.$set(this.searchData, 'endDate', new Date()); this.searchData.startDate = formatData.call(this.searchData.startDate, "yyyy-MM-dd"); this.searchData.endDate = formatData.call(this.searchData.endDate, "yyyy-MM-dd"); }, searchFormQuery() { var searchData = this.searchData; //发请求 data: searchData } </script> ``` --- 本篇文章需要感谢以下人员,中途曾帮助我获取到正确的结果: - 王海莹 --END--
发表评论