component-编辑数据页面(操作按钮-编辑,保存,取消) Object.assign浅拷贝复制

1.前言

vue3 + ts

支持"查看/编辑"切换表单组件用于展示和修改两个字段,初始化加载模拟数据,点击编辑进入编辑状态,点击保存提交更改并退出编辑,点击取消丢弃更改,恢复原始值;

2.代码

对于表单输入框与文本域样式可根据需求进行调整,编辑的保存和取消关键在于 Object.assign浅拷贝复制,代码如下

javascript 复制代码
<!-- 编辑数据页面 -->
<template>
<div style="background-color: #AAB0B6;">
  <!-- 操作按钮 -->
  <div class="edit-btn">
    <el-button v-if="!isEditing" @click="handleEdit" type="success">编辑</el-button>
    <el-button v-if="isEditing" @click="handleSave" type="success">保存</el-button>
    <el-button v-if="isEditing" @click="handCancel" type="info">取消</el-button>
  </div>

  <!-- 非编辑展示状态 -->
  <div v-if="!isEditing" class="content">
    <el-row
      :gutter="20"
      class="content-one"
    >
      <el-col :span="3">输入框文本:</el-col>
      <el-col :span="17">{{ formData.textInputData || '---' }}</el-col>
    </el-row>
    <el-row
      :gutter="20"
      class="content-one"
    >
      <el-col :span="3">文本描述:</el-col>
      <el-col :span="17">{{ formData.MutailTextInputData || '---' }}</el-col>
    </el-row>
  </div>
      
  <!-- 编辑状态 -->
  <div v-else class="content">
    <el-row
      :gutter="20"
      class="content-one"
    >
      <el-col :span="3">输入框文本:</el-col>
      <el-col :span="17">
        <el-input
          v-model="formData.textInputData"
          placeholder="请输入文本..."
          class="input-text"
        />
      </el-col>
    </el-row>
    <el-row
      :gutter="20"
      class="content-one"
    >
      <el-col :span="3">文本描述:</el-col>
      <el-col :span="17">
        <el-input
          v-model="formData.MutailTextInputData"
          type="textarea"
          :rows="3"
          placeholder="文本描述textarea:..."
          resize="vertical"
          class="content__input"
          maxlength="500"
          show-word-limit
        />
      </el-col>
    </el-row>
  </div>
</div>
</template>

<script setup lang="ts">
import { ref, reactive, onMounted} from 'vue'
import { ElMessage } from 'element-plus'

// 模拟数据
const mockInitialData = {
  textInputData: '文本输入耶耶耶耶耶耶',
  MutailTextInputData: '文本描述性大哥大哥大哥嘟嘟嘟嘟',
}

// 数据类型定义
interface ManagedEntityForm {
  textInputData: string
  MutailTextInputData: string
}

// formData:当前正在展示/编辑的数据(响应式)
const formData = reactive<ManagedEntityForm>({
  textInputData: '',
  MutailTextInputData: '',
})

const isEditing = ref(false)
// originalData:保存进入编辑前的"快照",用于取消时回滚
const originalData = ref<ManagedEntityForm>({ ...formData })

onMounted(() => {
  loadData()
})

// 初始加载
const loadData = () => {
  setTimeout(() => {
    // 将 mock 数据赋值给 formData(触发视图更新)
    Object.assign(formData, mockInitialData)
    // 同时保存一份副本作为"原始值"
    Object.assign(originalData.value, formData)
  }, 200)
}

// 编辑
const handleEdit = () => {
  // 关键:在点击"编辑"时,先保存当前 formData 到 originalData
  // 即使用户中途刷新或多次编辑,取消时总能回到最初进入编辑时的状态
  Object.assign(originalData.value, formData)
  isEditing.value = true
}

// 保存
const handleSave = () => {
  // 保存成功后,将当前 formData 视为新的"原始值"
  Object.assign(originalData.value, formData)
  isEditing.value = false
  ElMessage.success('保存成功')
  // 调用接口保存formData数据
}

// 取消
const handCancel = () => {
  // 将 originalData 的值覆盖回 formData,实现撤销
  Object.assign(formData, originalData.value)
  isEditing.value = false
}
</script>

<style lang="scss" scoped>

$spacing-md: calc(12 / 1080 * 100vh);

// 编辑按钮
.edit-btn {
  display: flex;
  gap: 12px;
  flex-direction: row-reverse;
  padding: 10px;

  &-title {
    font-size: 20px;
    font-weight: bold;
    color: rgba(255, 255, 255, 1);
  }
}

// 自定义输入框样式
.input-text {
  :deep(.el-input__wrapper) {
    height: 100%;
    padding: 0 $spacing-md;
    background: transparent !important;
    border: none !important;
    box-shadow: none !important;
    font-size: 16px;
    font-weight: normal;
    color: #fff;
  }

  :deep(.el-input__inner) {
    font-size: 16px;
    font-weight: normal;
    color: #fff;
    background: none;
    border: 1px solid rgba(255, 255, 255, 0.5);
    box-shadow: none;

    &::placeholder {
      color: rgba(255, 255, 255, 0.5);
    }
  }
}

// 文本域样式
.content {
  display: flex;
  flex: 1;
  flex-direction: column;
  gap: 16px;
  padding: 16px;

  &__input {
    width: 100%;

    :deep(.el-textarea__inner) {
      box-sizing: border-box;
      width: 100%;
      min-height: calc(80 / 1080 * 100vh);
      font-size: 16px;
      color: #fff;
      resize: vertical;
      background: rgba(26, 92, 152, 0.1);
      border: none;
      border-radius: 4px;
      box-shadow: none;
      opacity: 0.9;
      padding: 8px 12px;

      &::placeholder {
        color: rgba(255, 255, 255, 0.5);
      }

      &:focus {
        outline: none;
        border-color: #1890ff;
      }

      &::-webkit-scrollbar {
        width: 4px;
        background: transparent;
      }

      &::-webkit-scrollbar-track {
        background: rgba(54, 148, 255, 0.2);
        border-radius: 2px;
      }

      &::-webkit-scrollbar-thumb {
        background: #3694ff;
        border-radius: 2px;
      }
    }
  }

  .content-one {
    font-size: 16px;
    font-weight: normal;
    color: #fff;

    .el-col {
      display: flex;
      align-items: center;
    }
  }
}

// 文本输入限制字数 右下角样式
.el-textarea :deep(.el-input__count) {
  padding: 2px 6px !important;
  font-size: 12px !important;
  color: #fff !important;
  background-color: rgb(255 255 255 / 0%);
}
</style>
相关推荐
摘星编程2 小时前
React Native for OpenHarmony 实战:Linking 链接处理详解
javascript·react native·react.js
胖者是谁2 小时前
EasyPlayerPro的使用方法
前端·javascript·css
EndingCoder2 小时前
索引类型和 keyof 操作符
linux·运维·前端·javascript·ubuntu·typescript
liux35282 小时前
Web集群管理实战指南:从架构到运维
运维·前端·架构
沛沛老爹2 小时前
Web转AI架构篇 Agent Skills vs MCP:工具箱与标准接口的本质区别
java·开发语言·前端·人工智能·架构·企业开发
摘星编程3 小时前
React Native for OpenHarmony 实战:ImageBackground 背景图片详解
javascript·react native·react.js
小光学长3 小时前
基于Web的长江游轮公共服务系统j225o57w(程序+源码+数据库+调试部署+开发环境)带论文文档1万字以上,文末可获取,系统界面在最后面。
前端·数据库
摘星编程4 小时前
React Native for OpenHarmony 实战:Alert 警告提示详解
javascript·react native·react.js
Joe5564 小时前
vue2 + antDesign 下拉框限制只能选择2个
服务器·前端·javascript
WHS-_-20224 小时前
Tx and Rx IQ Imbalance Compensation for JCAS in 5G NR
javascript·算法·5g