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>
相关推荐
刘联其9 分钟前
.net也可以用Electron开发跨平台的桌面程序了
前端·javascript·electron
韩曙亮10 分钟前
【jQuery】jQuery 选择器 ④ ( jQuery 筛选方法 | 方法分类场景 - 向下找后代、向上找祖先、同级找兄弟、范围限定查找 )
前端·javascript·jquery·jquery筛选方法
前端 贾公子10 分钟前
Node.js 如何处理 ES6 模块
前端·node.js·es6
pas13616 分钟前
42-mini-vue 实现 transform 功能
前端·javascript·vue.js
柒.梧.38 分钟前
从零搭建SpringBoot+Vue+Netty+WebSocket+WebRTC视频聊天系统
vue.js·spring boot·websocket
你的代码我的心43 分钟前
微信开发者工具开发网页,不支持tailwindcss v4怎么办?
开发语言·javascript·ecmascript
esmap43 分钟前
OpenClaw与ESMAP AOA定位系统融合技术分析
前端·人工智能·计算机视觉·3d·ai·js
毕设源码-钟学长1 小时前
【开题答辩全过程】以 基于node.js vue的点餐系统的设计与实现为例,包含答辩的问题和答案
前端·vue.js·node.js
努力d小白1 小时前
leetcode438.找到字符串中所有字母异位词
java·javascript·算法
小白路过1 小时前
记录vue-cli-service serve启动本地服务卡住问题
前端·javascript·vue.js