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>
相关推荐
佳瑞Jarrett2 小时前
我用 Vue + SpringBoot + Redis 写了个「文件快取柜」
vue.js·spring boot·redis
bjzhang752 小时前
使用 HTML + JavaScript 实现可编辑表格
前端·javascript·html
GDAL2 小时前
js的markdown js库对比分析
javascript·markdown
指尖跳动的光2 小时前
js如何判空?
前端·javascript
石像鬼₧魂石2 小时前
Fail2ban + Nginx/Apache 防 Web 暴力破解配置清单
前端·nginx·apache
梦6502 小时前
基于Umi 框架(Ant Design Pro 底层框架)的动态路由权限控制实现方案
前端·react
weixin_464307633 小时前
设置程序自启动
前端
小满zs3 小时前
Next.js第十七章(Script脚本)
前端·next.js