Object.assign及在Vue中的应用小技巧

本文详细介绍了JavaScript中Object.assign()方法的功能和使用方式,包括如何进行对象复制与合并,并展示了在Vue.js中利用此方法重置组件数据的实用技巧。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

最近看代码的时候跟同事学到了一招。

Object.assign()

Object.assign()方法用于将所有可枚举属性的值从一个或多个源对象复制到目标对象。它将返回目标对象。

// 目标对象有1个,后边可以有多个源对象。注意他只会拷贝源对象自身且是可枚举的属性到目标对象。该方法使用源对象的[[Get]]和目标对象的[[Set]],所以它会调用相关 getter 和 setter。
Object.assign(target, ...sources)

复制对象

var obj = { a: 1 };
var copy = Object.assign({}, obj);
console.log(copy); // { a: 1 }

注意,Object.assign()是浅拷贝。

合并对象

var o1 = { a: 1 };
var o2 = { b: 2 };
var o3 = { c: 3 };

var obj = Object.assign(o1, o2, o3);
console.log(obj); // { a: 1, b: 2, c: 3 }
console.log(o1);  // { a: 1, b: 2, c: 3 }, 注意目标对象自身也会改变。

注意,具有相同属性的对象,同名属性,后边的会覆盖前边的。

Vue中的使用技巧

由于Object.assign()有上述特性,所以我们在Vue中可以这样使用:
Vue组件可能会有这样的需求:在某种情况下,需要重置Vue组件的data数据。此时,我们可以通过this.$data获取当前状态下的data,通过this.$options.data()获取该组件初始状态下的data。然后只要使用Object.assign(this.$data, this.$options.data())就可以将当前状态的data重置为初始状态,非常方便!

<template> <div> <el-dialog :visible.sync="dialogVisible" width="70%" :show-close="false" :close-on-click-modal="false" append-to-body @open="handleOpen" @close="handleClose" > <template slot="title"> <div style="text-align: center; font-size: 22px;"> {{ title }} </div> </template> <el-form :model="detailForm" label-width="130px" v-loading="loading"> <el-row> <el-col :span="8"> <el-form-item label="日期:"> <el-input readonly v-model="detailForm.recordDate"></el-input> </el-form-item> </el-col> <el-col :span="8"> <el-form-item label="班别:"> <el-input readonly v-model="detailForm.workClass"></el-input> </el-form-item> </el-col> </el-row> <el-form-item label="异常机况:"> <el-table :data="eqpList" style="width: 100%" id="eqpTable"> <el-table-column prop="area" label="Area"></el-table-column> <el-table-column prop="eqpId" label="Eqp Id"></el-table-column> <el-table-column prop="eqpName" label="Eqp Name"></el-table-column> <el-table-column prop="eqpStatus" label="Eqp Status"></el-table-column> <el-table-column prop="eqpHour" label="Hour"></el-table-column> <el-table-column prop="eqpUser" label="User"></el-table-column> <el-table-column prop="comments" label="Comment"></el-table-column> </el-table> <el-input type="textarea" v-model="detailForm.abnormal" :autosize="{ minRows: 2 }" placeholder="请输入异常机况 或 选中粘贴图片" @paste="handlePaste($event, abnormalImageRef)" :readonly="!detailForm.editAuth" ></el-input> <el-upload ref="abnormalImageRef" v-model="detailForm.abnormalImageList" action="#" :http-request="handleHttpUpload" list-type="picture-card" :before-upload="beforeUpload" :on-success="() => uploadSuccess('abnormalImageList')" :on-error="uploadError" :on-remove="(file, fileList) => handleRemove('abnormalImageList', fileList)" :accept="fileType.join(',')" :on-preview="handlePreview" :disabled="!detailForm.editAuth" > <i class="el-icon-plus"></i> </el-upload> </el-form-item> <el-form-item label="产片:"> <el-table :data="lotList" style="width: 100%" id="lotTable"> <el-table-column prop="eqp" label="机台"></el-table-column> <el-table-column prop="priority" label="Priority"></el-table-column> <el-table-column prop="lotId" label="Lot ID"></el-table-column> <el-table-column prop="maskTitle" label="Mask Title"></el-table-column> <el-table-column prop="dueDay" label="Due Day"></el-table-column> </el-table> <el-input type="textarea" v-model="detailForm.product" :autosize="{ minRows: 2 }" placeholder="请输入产片 或 选中粘贴图片" @paste="handlePaste($event, productImageRef)" :readonly="!detailForm.editAuth" ></el-input> <el-upload ref="productImageRef" v-model="detailForm.productImageList" action="#" :http-request="handleHttpUpload" list-type="picture-card" :before-upload="beforeUpload" :on-success="() => uploadSuccess('productImageList')" :on-error="uploadError" :on-remove="(file, fileList) => handleRemove('productImageList', fileList)" :accept="fileType.join(',')" :on-preview="handlePreview" :disabled="!detailForm.editAuth" > <i class="el-icon-plus"></i> </el-upload> </el-form-item> <el-form-item label="工程师交接事项:"> <el-input type="textarea" v-model="detailForm.engHandover" :autosize="{ minRows: 2 }" placeholder="请输入工程师交接事项 或 选中粘贴图片" @paste="handlePaste($event, engHandoverImageRef)" :readonly="!detailForm.editAuth" ></el-input> <el-upload ref="engHandoverImageRef" v-model="detailForm.engHandoverImageList" action="#" :http-request="handleHttpUpload" list-type="picture-card" :before-upload="beforeUpload" :on-success="() => uploadSuccess('engHandoverImageList')" :on-error="uploadError" :accept="fileType.join(',')" :on-remove="(file, fileList) => handleRemove('engHandoverImageList', fileList)" :on-preview="handlePreview" :disabled="!detailForm.editAuth" > <i class="el-icon-plus"></i> </el-upload> </el-form-item> <el-form-item label="课长:" v-if="detailForm.managerName !== null"> <el-input v-model="detailForm.managerName" readonly></el-input> </el-form-item> <el-form-item label="接班人:" v-if="detailForm.assigneeName !== null"> <el-input type="textarea" v-model="detailForm.assigneeName" readonly autosize></el-input> </el-form-item> </el-form> <template slot="footer"> <el-button type="primary" @click="save" v-if="detailForm.editAuth">保存</el-button> <el-button @click="closeDialog">取消</el-button> <el-button type="primary" @click="submit" v-if="detailForm.submitAuth">提交</el-button> <el-button type="primary" @click="audit" v-if="detailForm.auditAuth">审核</el-button> <el-button type="primary" @click="assign" v-if="detailForm.assignAuth">签核</el-button> </template> </el-dialog> <el-dialog :visible.sync="previewVisible" :show-close="false"> <img width="100%" :src="previewImageUrl" alt="Preview Image"/> </el-dialog> </div> </template> <script> import { getJournalForEdit, saveJournal, submitJournal, auditJournal, assignJournal, clearEditUser } from '@/api/mfgLog/area'; import request from '@/utils/request'; import {Message, MessageBox } from "element-ui"; import dayjs from 'dayjs'; import { getToken } from '@/utils/auth' export default { data() { return { loading: false, dialogVisible: false, title: '光罩厂制造部站点交接记录簿', fileType: ['image/jpeg', 'image/png', 'image/gif'], abnormalImageRef: null, engHandoverImageRef: null, productImageRef: null, previewVisible: false, previewImageUrl: '', detailForm: { recordDate: '', workClass: '', workArea: '', abnormal: '', lotList: [], eqpList: [], abnormalImage: '', abnormalImageList: [], product: '', productImage: '', productImageList: [], engHandover: '', engHandoverImage: '', engHandoverImageList: [], managerName: '', assigneeName: '', editAuth: false, submitAuth: false, auditAuth: false, assignAuth: false, id: '' }, timer: null }; }, mounted() { // 监听事件以重置计时器 window.addEventListener('keydown', this.resetTimer); window.addEventListener('mousemove', this.resetTimer); window.addEventListener('mouseenter', this.resetTimer); // 浏览器关闭事件 window.addEventListener('beforeunload', (e) => { this.userInactive(); }); }, beforeDestroy() { // 清除事件监听和计时器 window.removeEventListener('keydown', this.resetTimer); window.removeEventListener('mousemove', this.resetTimer); window.removeEventListener('mouseenter', this.resetTimer); clearTimeout(this.timer); }, methods: { handleOpen() { this.resetTimer(); }, handleClose() { clearTimeout(this.timer); }, resetTimer() { // 用户进行了操作,重置计时器 if (this.timer) { clearTimeout(this.timer); } this.startTimer(); }, startTimer() { // 设置5分钟后的无操作处理 this.timer = setTimeout(() => { // 用户5分钟内无操作,执行相关逻辑 if (this.dialogVisible) { this.userInactive(); } }, 5 * 60 * 1000); }, userInactive() { // 用户处于非活跃状态的逻辑处理 if (this.detailForm.editAuth) { this.save(); } this.closeDialog(); }, showDialog(row) { this.loading = true; getJournalForEdit(row).then(res => { Object.assign(this.detailForm, res.data); // 显示提示信息 if (!this.detailForm.editAuth && !this.detailForm.assignAuth && this.detailForm.editUser) { Message.warning({ message: "当前日志正在被 " + this.detailForm.editUserName + " 编辑", position: 'top', // 确保消息显示在页面顶部 duration: 5000 // 消息显示时间为 5 秒 }); return 0; } this.detailForm.abnormalImageList = []; if (this.detailForm.abnormalImage?.length > 0) { let abnormalList = this.detailForm.abnormalImage.split(","); for (let index in abnormalList) { this.detailForm.abnormalImageList.push({ url: abnormalList[index] }); } } this.detailForm.productImageList = []; if (this.detailForm.productImage?.length > 0) { let productList = this.detailForm.productImage.split(","); for (let index in productList) { this.detailForm.productImageList.push({ url: productList[index] }); } } this.detailForm.engHandoverImageList = []; if (this.detailForm.engHandoverImage?.length > 0) { let engHandoverList = this.detailForm.engHandoverImage?.split(","); for (let index in engHandoverList) { this.detailForm.engHandoverImageList.push({ url: engHandoverList[index] }); } } this.title = "光罩厂制造部 " + this.detailForm.workArea + " 站点交接记录簿"; // 判断当前时间是否允许提交/审核日志 if (this.detailForm.submitAuth || this.detailForm.auditAuth) { // 白班18点30分之前不允许提交和审核 let authTime = this.detailForm.recordDate + " 18:30:00"; if ('N' == this.detailForm.workClass.substring(0, 1)) { // 晚班06点30分之前不允许提交和审核 authTime = dayjs(this.detailForm.recordDate).add(1, 'day').format("YYYY-MM-DD") + " 06:30:00"; } if (dayjs().isBefore(dayjs(authTime))) { this.detailForm.submitAuth = false; this.detailForm.auditAuth = false; } } // 父系统页面打开遮罩 window.parent.postMessage("open", '*'); this.dialogVisible = true; // 设置初始计时器 this.loading = false; }).catch(error => { console.log(error); this.loading = false; }); }, closeDialog() { clearEditUser({ id: this.detailForm.id }).catch(error => { Message.error(error.msg ? error.msg : error); }); this.$emit('close'); // 父系统页面关闭遮罩 window.parent.postMessage("close", '*'); this.dialogVisible = false; }, save() { this.detailForm.abnormalImage = this.detailForm.abnormalImageList.map(item => item.url).join(","); this.detailForm.productImage = this.detailForm.productImageList.map(item => item.url).join(","); this.detailForm.engHandoverImage = this.detailForm.engHandoverImageList.map(item => item.url).join(","); this.loading = true; saveJournal(this.detailForm).then(res => { this.loading = false; Message.success("保存成功"); this.closeDialog(); }).catch(error => { this.loading = false; }); }, submit() { MessageBox.confirm("确认要提交吗?", "提示", { confirmButtonText: '确认', cancelButtonText: '取消', type: 'warning', }).then(res => { this.detailForm.abnormalImage = this.detailForm.abnormalImageList.map(item => item.url).join(","); this.detailForm.productImage = this.detailForm.productImageList.map(item => item.url).join(","); this.detailForm.engHandoverImage = this.detailForm.engHandoverImageList.map(item => item.url).join(","); this.loading = true; submitJournal(this.detailForm).then(res => { this.loading = false; Message.success("提交成功"); this.closeDialog(); }).catch(error => { this.loading = false; Message.error(error.msg ? error.msg : error); }); }).catch(error => { console.log(error); }); }, audit() { MessageBox.confirm("确认要提交审核吗?", "提示", { confirmButtonText: '确认', cancelButtonText: '取消', type: 'warning', }).then(res => { this.detailForm.abnormalImage = this.detailForm.abnormalImageList.map(item => item.url).join(","); this.detailForm.productImage = this.detailForm.productImageList.map(item => item.url).join(","); this.detailForm.engHandoverImage = this.detailForm.engHandoverImageList.map(item => item.url).join(","); this.detailForm.lotList = this.detailForm.lotList this.detailForm.eqpList = this.detailForm.eqpList this.loading = true; auditJournal(this.detailForm).then(res => { this.loading = false; Message.success("审核成功"); this.closeDialog(); }).catch(error => { this.loading = false; Message.error(error.msg ? error.msg : error); }); }).catch(error => { console.log(error); }); }, assign() { MessageBox.confirm("确认要签核吗?", "提示", { confirmButtonText: '确认', cancelButtonText: '取消', type: 'warning', }).then(res => { this.loading = true; assignJournal({ id: this.detailForm.id }).then(res => { this.loading = false; Message.success("签核成功"); this.closeDialog(); }).catch(error => { this.loading = false; Message.error(error.msg ? error.msg : error); }); }).catch(error => { console.log(error); }); }, handleHttpUpload(options) { return process.env.VUE_APP_BASE_API + '/viewException/uploadImage' }, handleRemove(listName, fileList) { console.log(listName) console.log(fileList) console.log(this.detailForm[listName]) this.detailForm[listName] = fileList; }, headers(){ return { "Authorization": 'Bearer ' + getToken() } }, beforeUpload(rawFile) { const imgType = this.fileType.includes(rawFile.type); if (!imgType) { Message.warning({ title: '温馨提示', message: '上传图片不符合所需的格式!', }); } return imgType; }, uploadSuccess(imageListName) { Message.success({ title: '温馨提示', message: '图片上传成功!', }); this.detailForm[imageListName].forEach(item => { if (item.url.indexOf("/api/") < 0) item.url = item.response.url; }); }, uploadError() { Message.error({ title: '温馨提示', message: '图片上传失败,请您重新上传!', }); }, handlePaste(event, uploadRef) { const items = (event.clipboardData || window.clipboardData).items; let file = null; if (!items || items.length === 0) { Message.error("当前浏览器不支持粘贴板"); return; } // 搜索剪切板items for (let i = 0; i < items.length; i++) { if (items[i].type.indexOf("image") !== -1) { file = items[i].getAsFile(); break; } } if (!file) { return; } uploadRef.handleStart(file); // 将粘贴过来的图片加入预上传队列 uploadRef.submit(); // 提交图片上传队列 }, handlePreview(file) { this.previewImageUrl = file.url; this.previewVisible = true; } } }; </script> <style scoped> .layout-padding-custom { padding: 20px; } .border-vxe-table { margin-top: 20px; } </style> 报错vue.runtime.esm.js:619 [Vue warn]: Property or method "eqpList" is not defined on the instance but referenced during render. Make sure that this property is reactive, either in the data option, or for class-based components, by initializing the property. See: https://vuejs.org/v2/guide/reactivity.html#Declaring-Reactive-Properties. found in ---> <Detail> at src/views/mfgLog/area/detail.vue <Index> at src/views/mfgLog/area/index.vue <AppMain> at src/layout/components/AppMain.vue <Layout> at src/layout/index.vue <App> at src/App.vue <Root> warn @ vue.runtime.esm.js:619 warnNonPresent @ vue.runtime.esm.js:2024 get @ vue.runtime.esm.js:2079 render @ detail.vue:110 Vue._render @ vue.runtime.esm.js:3569 updateComponent @ vue.runtime.esm.js:4081 get @ vue.runtime.esm.js:4495 Watcher @ vue.runtime.esm.js:4484 mountComponent @ vue.runtime.esm.js:4088 Vue.$mount @ vue.runtime.esm.js:8459 init @ vue.runtime.esm.js:3137 createComponent @ vue.runtime.esm.js:6022 createElm @ vue.runtime.esm.js:5969 createChildren @ vue.runtime.esm.js:6097 createElm @ vue.runtime.esm.js:5998 patch @ vue.runtime.esm.js:6521 Vue._update @ vue.runtime.esm.js:3960 updateComponent @ vue.runtime.esm.js:4081 get @ vue.runtime.esm.js:4495 Watcher @ vue.runtime.esm.js:4484 mountComponent @ vue.runtime.esm.js:4088 Vue.$mount @ vue.runtime.esm.js:8459 init @ vue.runtime.esm.js:3137 merged @ vue.runtime.esm.js:3322 createComponent @ vue.runtime.esm.js:6022 createElm @ vue.runtime.esm.js:5969 patch @ vue.runtime.esm.js:6521 Vue._update @ vue.runtime.esm.js:3960 updateComponent @ vue.runtime.esm.js:4081 get @ vue.runtime.esm.js:4495 Watcher @ vue.runtime.esm.js:4484 mountComponent @ vue.runtime.esm.js:4088 Vue.$mount @ vue.runtime.esm.js:8459 init @ vue.runtime.esm.js:3137 createComponent @ vue.runtime.esm.js:6022 createElm @ vue.runtime.esm.js:5969 patch @ vue.runtime.esm.js:6521 Vue._update @ vue.runtime.esm.js:3960 updateComponent @ vue.runtime.esm.js:4081 get @ vue.runtime.esm.js:4495 Watcher @ vue.runtime.esm.js:4484 mountComponent @ vue.runtime.esm.js:4088 Vue.$mount @ vue.runtime.esm.js:8459 init @ vue.runtime.esm.js:3137 createComponent @ vue.runtime.esm.js:6022 createElm @ vue.runtime.esm.js:5969 createChildren @ vue.runtime.esm.js:6097 createElm @ vue.runtime.esm.js:5998 patch @ vue.runtime.esm.js:6521 Vue._update @ vue.runtime.esm.js:3960 updateComponent @ vue.runtime.esm.js:4081 get @ vue.runtime.esm.js:4495 Watcher @ vue.runtime.esm.js:4484 mountComponent @ vue.runtime.esm.js:4088 Vue.$mount @ vue.runtime.esm.js:8459 init @ vue.runtime.esm.js:3137 createComponent @ vue.runtime.esm.js:6022 createElm @ vue.runtime.esm.js:5969 createChildren @ vue.runtime.esm.js:6097 createElm @ vue.runtime.esm.js:5998 createChildren @ vue.runtime.esm.js:6097 createElm @ vue.runtime.esm.js:5998 patch @ vue.runtime.esm.js:6521 Vue._update @ vue.runtime.esm.js:3960 updateComponent @ vue.runtime.esm.js:4081 get @ vue.runtime.esm.js:4495 Watcher @ vue.runtime.esm.js:4484 mountComponent @ vue.runtime.esm.js:4088 Vue.$mount @ vue.runtime.esm.js:8459 init @ vue.runtime.esm.js:3137 merged @ vue.runtime.esm.js:3322 createComponent @ vue.runtime.esm.js:6022 createElm @ vue.runtime.esm.js:5969 updateChildren @ vue.runtime.esm.js:6260 patchVnode @ vue.runtime.esm.js:6363 patch @ vue.runtime.esm.js:6526 Vue._update @ vue.runtime.esm.js:3963 updateComponent @ vue.runtime.esm.js:4081 get @ vue.runtime.esm.js:4495 run @ vue.runtime.esm.js:4570 flushSchedulerQueue @ vue.runtime.esm.js:4326 eval @ vue.runtime.esm.js:1989 flushCallbacks @ vue.runtime.esm.js:1915 Promise.then timerFunc @ vue.runtime.esm.js:1942 nextTick @ vue.runtime.esm.js:1999 queueWatcher @ vue.runtime.esm.js:4418 update @ vue.runtime.esm.js:4560 notify @ vue.runtime.esm.js:730 reactiveSetter @ vue.runtime.esm.js:1055 eval @ vue-router.esm.js:2932 eval @ vue-router.esm.js:2931 updateRoute @ vue-router.esm.js:2352 eval @ vue-router.esm.js:2206 eval @ vue-router.esm.js:2340 step @ vue-router.esm.js:1944 step @ vue-router.esm.js:1951 step @ vue-router.esm.js:1951 runQueue @ vue-router.esm.js:1955 eval @ vue-router.esm.js:2335 step @ vue-router.esm.js:1944 eval @ vue-router.esm.js:1948 eval @ vue-router.esm.js:2322 eval @ vue-router.esm.js:2070 eval @ vue-router.esm.js:2146 eval @ permission.js:110 Promise.then eval @ permission.js:110 eval @ vue-router.esm.js:2087 eval @ vue-router.esm.js:2114 eval @ vue-router.esm.js:2114 flatMapComponents @ vue-router.esm.js:2113 eval @ vue-router.esm.js:2049 iterator @ vue-router.esm.js:2300 step @ vue-router.esm.js:1947 step @ vue-router.esm.js:1951 step @ vue-router.esm.js:1951 eval @ vue-router.esm.js:1948 eval @ vue-router.esm.js:2322 eval @ permission.js:36 iterator @ vue-router.esm.js:2300 step @ vue-router.esm.js:1947 runQueue @ vue-router.esm.js:1955 confirmTransition @ vue-router.esm.js:2330 transitionTo @ vue-router.esm.js:2203 replace @ vue-router.esm.js:2556 eval @ vue-router.esm.js:2316 eval @ permission.js:27 Promise.then eval @ permission.js:24 Promise.then eval @ permission.js:23 iterator @ vue-router.esm.js:2300 step @ vue-router.esm.js:1947 runQueue @ vue-router.esm.js:1955 confirmTransition @ vue-router.esm.js:2330 transitionTo @ vue-router.esm.js:2203 init @ vue-router.esm.js:2923 beforeCreate @ vue-router.esm.js:1271 invokeWithErrorHandling @ vue.runtime.esm.js:1863 callHook @ vue.runtime.esm.js:4235 Vue._init @ vue.runtime.esm.js:5018 Vue @ vue.runtime.esm.js:5099 eval @ main.js:135 ./src/main.js @ app.js:4942 __webpack_require__ @ app.js:854 fn @ app.js:151 1 @ app.js:5230 __webpack_require__ @ app.js:854 checkDeferredModules @ app.js:46 (匿名) @ app.js:994 (匿名) @ app.js:997 vue.runtime.esm.js:619 [Vue warn]: Property or method "lotList" is not defined on the instance but referenced during render. Make sure that this property is reactive, either in the data option, or for class-based components, by initializing the property. See: https://vuejs.org/v2/guide/reactivity.html#Declaring-Reactive-Properties. found in ---> <Detail> at src/views/mfgLog/area/detail.vue <Index> at src/views/mfgLog/area/index.vue <AppMain> at src/layout/components/AppMain.vue <Layout> at src/layout/index.vue <App> at src/App.vue <Root>
最新发布
08-08
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值