@Prop @Watch('onChange') maxAmplitude: number
时间: 2025-06-24 18:36:45 浏览: 13
### Vue.js 使用 `@Prop` 和 `@Watch` 装饰器监听 `maxAmplitude` 属性变化
Vue.js 结合 TypeScript 可以通过装饰器模式更方便地定义组件的行为。下面展示了一个具体的例子,演示如何使用 `@Prop` 和 `@Watch` 装饰器来监听 `maxAmplitude` 属性的变化。
#### 定义 `@Prop` 装饰器
`@Prop` 是用来声明一个组件的外部传入属性。它可以通过对象形式指定验证规则,例如类型、默认值等。
```typescript
<template>
<div>{{ maxAmplitude }}</div>
</template>
<script lang="ts">
import { Component, Prop, Watch, Vue } from 'vue-property-decorator';
@Component
export default class ExampleComponent extends Vue {
@Prop({ type: Number, required: true }) readonly maxAmplitude!: number;
private localMaxAmplitude: number = this.maxAmplitude;
@Watch('maxAmplitude')
onMaxAmplitudeChanged(newVal: number, oldVal: number): void {
console.log(`maxAmplitude changed from ${oldVal} to ${newVal}`);
this.localMaxAmplitude = newVal;
}
mounted(): void {
console.log('Initial maxAmplitude:', this.maxAmplitude);
}
}
</script>
```
在这个代码中,我们做了如下操作:
- 使用 `@Prop` 来接收父级传递下来的 `maxAmplitude` 属性,并将其标记为只读[^1]。
- 创建了一个本地变量 `localMaxAmplitude` 并初始化为其初始值。
- 利用 `@Watch` 装饰器监听 `maxAmplitude` 的变化,在其发生变化时打印日志并同步到本地变量[^2]。
---
#### 处理 `maxAmplitude` 属性变更
当 `maxAmplitude` 发生改变时,`@Watch` 装饰器会自动调用对应的回调函数。该回调函数接受两个参数:新值 (`newVal`) 和旧值 (`oldVal`)。这使得我们可以轻松追踪属性的变化过程。
如果需要进一步处理这些变化(如触发其他逻辑或通知子组件),可以直接在回调函数内部实现相应业务逻辑。
---
#### 注意事项
- **数据流方向**
父组件向子组件传递的数据应该是单向流动的。因此,通常不会直接修改由 `@Prop` 接收的数据,而是复制一份副本进行操作[^3]。
- **性能优化**
当频繁更新某个 prop 值时,需注意避免不必要的计算开销。可以结合防抖或者节流技术减少重复渲染次数[^4]。
- **错误处理**
在实际项目开发过程中,应对可能出现的各种边界情况进行充分测试,确保应用健壮性和稳定性[^5]。
---
###
阅读全文
相关推荐



<template> <a-card :bordered="false" style="margin-bottom: 10px;"> </a-card> <a-card :bordered="false" > <bt-inventory-add-form v-if="showAddModal" ref="btInventoryAddForm" :contractId="contractId" @ok="getList" @close="showAddModal = false" /> <bt-inventory-edit-form v-if="showEditModal" ref="btInventoryEditForm" :contractId="contractId" @ok="getList" @close="showEditModal = false" /> <a-tooltip title="刷新"> <a-icon @click="getList" class="action" :type="loading ? 'loading' : 'reload'" /> </a-tooltip> <a-table :loading="loading" rowKey="id" size="middle" @change="handleTableChange" @refresh="getList" :columns="columns" :data-source="btInventoryList" :row-selection="{ selectedRowKeys: selectedRowKeys, onChange: onSelectChange }" :pagination="false" > </a-table> </a-card> 暂无相关库存数据 <a-tag v-if="isOutbound" color="green" style="margin-left:8px;">已出库</a-tag> </template> <script> import { listBtInventory, delBtInventory, exportBtInventory } from '@/api/tt/Inventory' import AdvanceTable from '@/components/pt/table/AdvanceTable' import BtInventoryAddForm from '@/views/bt/btoutbound/modules/BtInventoryAddForm' import BtInventoryEditForm from '@/views/bt/btoutbound/modules/BtInventoryEditForm' export default { name: 'BtInventory', props: { isOutbound: { type: Boolean, default: false, // 默认不显示“已出库” }, contractId: { type: String, required: true }, title: { type: String, default: '子表' } },watch: { hasData: { immediate: true, handler(newVal) { if (!newVal && !this.isOutbound) { this.$emit('outbound-status', true); this.isOutbound = true; } } } }, components: { AdvanceTable, BtInventoryAddForm, BtInventoryEditForm }, data () { return { hasData:false, showAddModal: false, showEditModal: false, // 遮罩层 loading: true, // 选中数组 ids: [], // 选中的主键集合 selectedRowKeys: [], // 选中的数据集合 selectedRows: [], // 高级搜索 展开/关闭 advanced: false, // 非单个禁用 single: true, // 非多个禁用 multiple: true, // 总条数 total: 0, // label的百分比 labelCol: { span: 6 }, // 内容区域的百分比 wrapperCol: { span: 18 }, // 合同管理表格数据 btInventoryList: [], // 查询参数 queryParam: { pageNum: 1, pageSize: 1000, itemName: undefined, description: undefined, quantity: undefined, beginIndate: undefined }, columns: [ { title: '物资名称', dataIndex: 'itemName', ellipsis: true, align: 'left', width: '12.8%' }, { title: '规格型号', dataIndex: 'description', ellipsis: true, align: 'left', width: '12.8%' }, { title: '总库存', dataIndex: 'fulfilledQuantity', align: 'right', width: '12.8%' }, { title: '当前库存数量', dataIndex: 'quantity', align: 'right', width: '12.8%' }, { title: '入库日期', dataIndex: 'indate', align: 'center', width: '12.8%' }, // { // title: '操作', // dataIndex: 'operation', // align: 'center', // width: '10%', // scopedSlots: { customRender: 'operation' } // } ] } }, created () { this.getList() }, methods: { /** 查询合同管理列表 */ getList () { this.loading = true this.queryParam.contractId = this.contractId listBtInventory(this.queryParam).then(response => { this.btInventoryList = response.data.list this.total = response.data.total this.loading = false if(this.btInventoryList.length > 0){ this.hasData = true }else{ this.hasData = false } }) }, /** 搜索按钮操作 */ handleQuery () { this.queryParam.pageNum = 1 this.getList() }, /** 重置按钮操作 */ resetQuery () { this.queryParam = { pageNum: 1, pageSize: 1000, itemName: undefined, description: undefined, quantity: undefined, beginIndate: undefined } this.handleQuery() }, /** 翻页操作 */ onShowSizeChange (current, pageSize) { this.queryParam.pageSize = pageSize this.getList() }, /** 翻页操作 */ onSizeChange (current, size) { this.queryParam.pageNum = 1 this.queryParam.pageSize = size this.getList() }, /** 翻页操作 */ changeSize (current, pageSize) { this.queryParam.pageNum = current this.queryParam.pageSize = pageSize this.getList() }, /** 翻页操作 */ onSelectChange (selectedRowKeys, selectedRows) { this.selectedRowKeys = selectedRowKeys this.selectedRows = selectedRows this.ids = this.selectedRows.map(item => item.id) this.single = selectedRowKeys.length !== 1 this.multiple = !selectedRowKeys.length }, /** 查询折叠和展开操作 */ toggleAdvanced () { this.advanced = !this.advanced }, handleAdd () { this.showAddModal = true this.$nextTick(() => ( this.$refs.btInventoryAddForm.handleAdd() )) }, handleUpdate (record, ids) { this.showEditModal = true this.$nextTick(() => ( this.$refs.btInventoryEditForm.handleUpdate(record, ids) )) }, /** 删除按钮操作 */ handleDelete (row) { var that = this const btInventoryIds = row.id || this.ids this.$confirm({ title: '确认删除所选中数据?', onOk () { return delBtInventory(btInventoryIds) .then(() => { that.onSelectChange([], []) that.getList() that.$message.success( '删除成功', 3 ) }) }, onCancel () {} }) }, /** 导出按钮操作 */ handleExport () { var that = this this.$confirm({ title: '是否确认导出?', content: '此操作将导出当前条件下所有数据而非选中数据', onOk () { return exportBtInventory(that.queryParam) .then(response => { that.download(response.msg) that.$message.success( '导出成功', 3 ) }) }, onCancel () {} }) }, handleTableChange (pagination, filters, sorter) { if (sorter.field !== undefined && sorter.field !== null && sorter.field !== '') { this.queryParam.orderByColumn = 'a.' + sorter.field this.queryParam.isAsc = sorter.order } this.getList() } } } </script> <style scoped> .empty-container { padding: 20px; text-align: center; background: #fff; border-radius: 4px; } .action { font-size: 16px; cursor: pointer; margin-left: 8px; } .action:hover { color: #1890ff; } </style><template> <a-card :bordered="false" style="margin-bottom: 10px;"> <a-form :labelCol="labelCol" :wrapperCol="wrapperCol" ref="queryForm"> <a-row :gutter="32"> <a-col :span="6" > <a-form-item label="合同名称"> <a-input v-model="queryParam.contractName" placeholder="请输入合同名称" allow-clear @keyup.enter.native="handleQuery"/> </a-form-item> </a-col> <a-col :span="6" > <a-form-item label="合同正式编号"> <a-input v-model="queryParam.contractId" placeholder="请输入合同正式编号" allow-clear @keyup.enter.native="handleQuery"/> </a-form-item> </a-col> <a-col :span="6" > <a-form-item label="对方签约单位"> <a-input v-model="queryParam.counterpartContractUnit" placeholder="请输入对方签约单位" allow-clear @keyup.enter.native="handleQuery"/> </a-form-item> </a-col> <a-col> <a-button type="primary" @click="handleQuery"><a-icon type="search" />查询</a-button> <a-button style="margin-left: 8px" @click="resetQuery"><a-icon type="redo" />重置</a-button> {{ advanced ? '收起' : '展开' }} <a-icon :type="advanced ? 'up' : 'down'"/> </a-col> </a-row> </a-form> </a-card> <a-card :bordered="false" class="table-card"> <bt-contracts-detailed-add-form v-if="showAddModal" ref="contractmanageAddForm" :firstContractTypeOptions="firstContractTypeOptions" :secondContractTypeOptions="secondContractTypeOptions" :sealTypeOptions="sealTypeOptions" :signTypeOptions="signTypeOptions" @ok="getList" @close="showAddModal = false" /> <bt-contracts-detailed-edit-form v-if="showEditModal" ref="contractmanageEditForm" :firstContractTypeOptions="firstContractTypeOptions" :secondContractTypeOptions="secondContractTypeOptions" :sealTypeOptions="sealTypeOptions" :signTypeOptions="signTypeOptions" @ok="getList" @close="showEditModal = false" /> <BtLiveEidt v-if="showLiveModal" ref="liveEidt" :firstContractTypeOptions="firstContractTypeOptions" :secondContractTypeOptions="secondContractTypeOptions" :sealTypeOptions="sealTypeOptions" :signTypeOptions="signTypeOptions" @ok="getList" @close="showLiveModal = false" /> <outBound v-if="visible" ref="outBoundref" @close="onClose" /> <advance-table title="出库管理" :pagination="{ current: queryParam.pageNum, pageSize: queryParam.pageSize, total: total, showSizeChanger: true, showLessItems: true, showQuickJumper: true, showTotal: (total, range) => 第 ${range[0]}-${range[1]} 条,总计 ${total} 条, onChange: changeSize, onShowSizeChange: onShowSizeChange }" tableKey="base-contractmanage-index-table" @change="handleTableChange" rowKey="id" size="middle" @refresh="getList" :columns="columns" :data-source="contractmanageList" :loading="loading" :format-conditions="true" :row-selection="{ selectedRowKeys: selectedRowKeys, onChange: onSelectChange }" > <bt-inventory-index ref="BtInventoryIndex" title="子表" :contractId="record.id" @outbound-status="(status) => handleOutboundStatus(record, status)" /> {{ firstContractTypeFormat(record) }} {{ secondContractTypeFormat(record) }} {{ sealTypeFormat(record) }} {{ signTypeFormat(record) }} <a-radio-group default-value="a" size="small"> <a-button type="primary" @click="handleUpdate1(record)" v-hasPermi="['bt:btOutbound:edit']" :size="size" ghost> <a-icon type="upload" />生活出库 </a-button> | <a-button type="primary" @click="handleUpdate(record)" v-hasPermi="['bt:btOutbound:edit']" :size="size" > <a-icon type="upload" />生产出库 </a-button> | <a-button type="dashed" @click="showDrawer(record)" v-hasPermi="['bt:btOutbound:list']" :size="size"> <a-icon type="table" />出库记录 </a-button> <a-button v-if="record.hasOutbound" type="danger" @click="resetOutboundStatus(record)" :size="size" > <a-icon type="undo" />重置为未出库 </a-button> </a-radio-group> <a-tag v-if="record.hasOutbound" color="green">已出库</a-tag> <a-tag v-else color="orange">未出库</a-tag> </advance-table> </a-card> </template> <script> import { listBtContractsDetailed, delBtContractsDetailed, exportBtContractsDetailed, getInitData } from '@/api/tt/ContractsDetailed' import AdvanceTable from '@/components/pt/table/AdvanceTable' import BtContractsDetailedAddForm from '@/views/bt/btoutbound/modules/BtContractsDetailedAddForm' import BtContractsDetailedEditForm from '@/views/bt/btoutbound/modules/BtContractsDetailedEditForm' import BtInventoryIndex from '@/views/bt/btoutbound/BtInventoryIndex' import outBound from '@/views/bt/btoutbound/outbound/index.vue' import BtLiveEidt from './modules/BtLiveEidt.vue' export default { name: 'BtoutBound', components: { AdvanceTable, BtInventoryIndex, outBound, BtContractsDetailedAddForm, BtContractsDetailedEditForm, BtLiveEidt }, data () { return { size:'small', visible: false, showAddModal: false, showEditModal: false, showLiveModal: false, // 遮罩层 loading: true, // 选中数组 ids: [], // 选中的主键集合 selectedRowKeys: [], // 选中的数据集合 selectedRows: [], // 高级搜索 展开/关闭 advanced: false, // 非单个禁用 single: true, // 非多个禁用 multiple: true, // 总条数 total: 0, // label的百分比 labelCol: { span: 6 }, // 内容区域的百分比 wrapperCol: { span: 18 }, // 合同管理表格数据 contractmanageList: [], // 一级合同类型字典 firstContractTypeOptions: [], // 二级合同类型字典 secondContractTypeOptions: [], // 用章类别字典 sealTypeOptions: [], // 签署类型字典 signTypeOptions: [], outBoundId: 0, // 查询参数 queryParam: { pageNum: 1, pageSize: 10, contractName: undefined, contractId: undefined, organizer: undefined, counterpartContractUnit: undefined }, columns: [ { title: '合同分类', dataIndex: 'contractClassification', ellipsis: true, align: 'left', width: '12.8%' }, { title: '合同名称', dataIndex: 'contractName', ellipsis: true, align: 'left', width: '12.8%' }, { title: '合同正式编号', dataIndex: 'contractId', ellipsis: true, align: 'left', width: '12.8%' }, { title: '采购方式', dataIndex: 'procurementMethod', ellipsis: true, align: 'left', width: '12.8%' }, { title: '对方签约单位', dataIndex: 'counterpartContractUnit', ellipsis: true, align: 'left', width: '12.8%' }, { title: '我方签订日期', dataIndex: 'ourSignDate', ellipsis: true, align: 'left', width: '12.8%' }, { title: '合同总金额', dataIndex: 'totalContractAmount', ellipsis: true, align: 'left', width: '12.8%' }, { title: '删除作废', dataIndex: 'deletedOrVoided', ellipsis: true, align: 'left', width: '12.8%' }, { title: '出库状态', dataIndex: 'hasOutbound', align: 'center', width: '10%', customRender: (text, record) => { return record.hasOutbound ? <a-tag color="green">已出库</a-tag> : <a-tag color="orange">未出库</a-tag>; } }, { title: '操作', dataIndex: 'operation', align: 'center', width: '60%', scopedSlots: { customRender: 'operation' } } ] } }, created () { this.getList() getInitData('contract_type_level1,contract_type_level2,sys_oper_type,sys_oper_type').then(response => { this.firstContractTypeOptions = response.data.contract_type_level1 this.secondContractTypeOptions = response.data.contract_type_level2 this.sealTypeOptions = response.data.sys_oper_type this.signTypeOptions = response.data.sys_oper_type }) }, methods: { resetOutboundStatus(record) { const index = this.contractmanageList.findIndex(item => item.id === record.id); if (index !== -1) { this.$set(this.contractmanageList[index], 'hasOutbound', false); // 更新前端状态 localStorage.removeItem(outbound_${record.id}); // 清除 localStorage 存储 this.$message.success("已重置为未出库"); } }, handleOutboundStatus(record, status) { const index = this.contractmanageList.findIndex(item => item.id === record.id); if (index !== -1 && status && !this.contractmanageList[index].hasOutbound) { this.$set(this.contractmanageList[index], 'hasOutbound', true); localStorage.setItem(outbound_${record.id}, 'true'); // 存储到 localStorage } }, onClose () { this.visible = false this.$emit('close') }, showDrawer(record) { this.visible = true const that = this that.$nextTick(() => ( that.$refs.outBoundref.handleList(record) )) }, // onClose() { // this.visible = false; // }, /** 查询合同管理列表 */ getList () { this.loading = true; listBtContractsDetailed(this.queryParam).then(response => { this.contractmanageList = response.data.list.map(item => { // 从 localStorage 读取是否已出库 const storedOutbound = localStorage.getItem(outbound_${item.id}); return { ...item, hasOutbound: storedOutbound === 'true' || false, }; }); this.total = response.data.total; this.loading = false; }); }, // 一级合同类型字典翻译 firstContractTypeFormat (row) { if (row.firstContractType) { return this.selectDictLabel(this.firstContractTypeOptions, row.firstContractType) } else { return '' } }, // 二级合同类型字典翻译 secondContractTypeFormat (row) { if (row.secondContractType) { return this.selectDictLabel(this.secondContractTypeOptions, row.secondContractType) } else { return '' } }, // 用章类别字典翻译 sealTypeFormat (row) { if (row.sealType) { return this.selectDictLabel(this.sealTypeOptions, row.sealType) } else { return '' } }, // 签署类型字典翻译 signTypeFormat (row) { if (row.signType) { return this.selectDictLabel(this.signTypeOptions, row.signType) } else { return '' } }, /** 搜索按钮操作 */ handleQuery () { this.queryParam.pageNum = 1 this.getList() }, /** 重置按钮操作 */ resetQuery () { this.queryParam = { pageNum: 1, pageSize: 10, contractName: undefined, contractId: undefined, organizer: undefined, counterpartContractUnit: undefined } this.handleQuery() }, /** 翻页操作 */ onShowSizeChange (current, pageSize) { this.queryParam.pageSize = pageSize this.getList() }, /** 翻页操作 */ onSizeChange (current, size) { this.queryParam.pageNum = 1 this.queryParam.pageSize = size this.getList() }, /** 翻页操作 */ changeSize (current, pageSize) { this.queryParam.pageNum = current this.queryParam.pageSize = pageSize this.getList() }, /** 翻页操作 */ onSelectChange (selectedRowKeys, selectedRows) { this.selectedRowKeys = selectedRowKeys this.selectedRows = selectedRows this.ids = this.selectedRows.map(item => item.id) this.single = selectedRowKeys.length !== 1 this.multiple = !selectedRowKeys.length }, /** 查询折叠和展开操作 */ toggleAdvanced () { this.advanced = !this.advanced }, handleAdd () { this.showAddModal = true this.$nextTick(() => ( this.$refs.contractmanageAddForm.handleAdd() )) }, //生活导出 handleUpdate1 (record, ids) { this.showLiveModal = true this.$nextTick(() => ( this.$refs.liveEidt.handleUpdate(record, ids) )) }, handleUpdate (record, ids) { this.showEditModal = true this.$nextTick(() => ( this.$refs.contractmanageEditForm.handleUpdate(record, ids) )) }, /** 删除按钮操作 */ handleDelete (row) { var that = this const contractmanageIds = row.id || this.ids this.$confirm({ title: '确认删除所选中数据?', onOk () { return delBtContractsDetailed(contractmanageIds) .then(() => { that.onSelectChange([], []) that.getList() that.$message.success( '删除成功', 3 ) }) }, onCancel () {} }) }, /** 导出按钮操作 */ handleExport () { var that = this this.$confirm({ title: '是否确认导出?', content: '此操作将导出当前条件下所有数据而非选中数据', onOk () { return exportBtContractsDetailed(that.queryParam) .then(response => { that.download(response.msg) that.$message.success( '导出成功', 3 ) }) }, onCancel () {} }) }, handleTableChange (pagination, filters, sorter) { if (sorter.field !== undefined && sorter.field !== null && sorter.field !== '') { this.queryParam.orderByColumn = 'a.' + sorter.field this.queryParam.isAsc = sorter.order } this.getList() } } } </script> 进行修改,我现在的未出库和已出库是存储在客户端,但现在要改成存储到数据库里,/** * 修改合同管理 */ @PreAuthorize("@ss.hasPermi('bt:btOutbound:edit')") @Log(title = "合同管理", businessType = BusinessType.UPDATE) @PutMapping public R edit(@RequestBody @Validated ContractsDetailed btContractsDetailed) { return R.status(btContractsDetailedService.save(btContractsDetailed)); }存储时调用这个接口里的 ecc_transfer varchar(50) DEFAULT NULL COMMENT '传输ECC', 这个字段,直接存储汉字





