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>
相关推荐
Csvn17 小时前
性能监控
前端
Highcharts.js17 小时前
Highcharts Gantt使用符号的自定义数据标签开发甘特图示例
javascript·甘特图·highcharts·图表开发·实战代码·响应式图表
Csvn17 小时前
构建工具
前端
FRing0318 小时前
vue2干货总结3(computed计算属性、watch监听器)
开发语言·前端·vue.js·vue2
Java小卷19 小时前
JuanForm vs FormCreate!Vue3 表单引擎联动配置 PK!
vue.js·低代码
kyriewen20 小时前
Skills 榜前 10 我全装了:只有 3 个能直接用
前端·javascript·程序员
IT_陈寒20 小时前
当Java的hashCode遇上Lombok,我的缓存被全清了
前端·人工智能·后端
工控丫丫21 小时前
帆软看板中经常使用的公式函数及经常搭的组合
前端·javascript·数据库
jerrywus21 小时前
我用 GPT-6.1-sol 做了台会讲解的 3D 售货机:60 罐饮料,一口没喝上
前端·agent·claude
孟陬1 天前
Foobar 技术周刊#159:当看不懂代码时,如何高效排障调试。脏页陷阱:一条只读查询,写入数 TB 数据。推测解码:大模型加速利器
前端·人工智能·后端