点一下就能改字?手把手教你用 JavaScript 做一个“会变身”的智能小盒子!

50 阅读6分钟

🌟 超详细图解:用面向对象(OOP)做一个“点文字就能改”的小工具

目标:让你在网页上看到一段文字,比如 “有了肯德基,生活好滋味”,
点一下它 → 变成输入框 + 保存/取消按钮,
改完点保存 → 文字更新,
点取消 → 回到原来的样子。

这叫 “就地编辑” (Edit In Place)——就像微信里点昵称就能直接改,不用跳页面。

我们不用框架,只用原生 JavaScript,而且用 面向对象(OOP) 的方式来写,让它能重复用、好维护、别人拿来就能用


第一步:先想清楚——我们要造什么?

想象你在搭一个“智能小盒子”:

  • 盒子外面贴着一句话(比如“前端工程师”)

  • 你点这句话,盒子自动弹出:

    • 一个输入框(让你改字)
    • 一个“保存”按钮
    • 一个“取消”按钮
  • 点“保存” → 盒子把新字贴在外面

  • 点“取消” → 盒子关上,还是原来的字

这个“智能小盒子”,就是我们要做的 EditInPlace

类 = 制作这种盒子的图纸
实例 = 按图纸造出来的一个真实盒子


第二步:怎么“造”一个盒子?—— 构造函数

function EditInPlace(id, value, parentElement) {
  // 1. 记住基本信息
  this.id = id;                          // 盒子的名字(比如 "bio-box")
  this.value = value || '这个家伙很懒...'; // 盒子当前显示的文字
  this.parentElement = parentElement;     // 把盒子放在网页的哪个位置(比如 <div id="app">)

  // 2. 先预留5个“零件”的位置(现在是空的)
  this.containerElement = null; // 外层大盒子(<div>)
  this.staticElement = null;    // 显示文字的小标签(<span>)
  this.fieldElement = null;     // 输入框(<input type="text">)
  this.saveButton = null;       // 保存按钮
  this.cancelButton = null;     // 取消按钮

  // 3. 开始组装!
  this.createElement(); // 把5个零件做出来
  this.attachEvent();   // 给零件装上“机关”(点击能动)
}

🔍 重点解释 this 是什么?

当你写:

const myBox = new EditInPlace('slogan', '肯德基真香', document.body);

JavaScript 会:

  1. 创建一个全新的空对象 → {}
  2. 把这个空对象当作 this,传给 EditInPlace 函数
  3. 所有 this.xxx = ... 都是在给这个新对象贴标签

所以 myBox 最后长这样:

{
  id: 'slogan',
  value: '肯德基真香',
  parentElement: <body>,
  containerElement: <div>(后面会创建),
  staticElement: <span>,
  fieldElement: <input>,
  saveButton: <input>,
  cancelButton: <input>
}

this 就是正在被建造的那个盒子本身


第三步:把零件做出来 —— createElement()

EditInPlace.prototype.createElement = function() {
  // 1. 做外层大盒子
  this.containerElement = document.createElement('div');
  this.containerElement.id = this.id; // 给盒子起名字

  // 2. 做“文字标签”
  this.staticElement = document.createElement('span');
  this.staticElement.innerHTML = this.value; // 写上当前文字
  this.containerElement.appendChild(this.staticElement); // 把标签放进大盒子

  // 3. 做“输入框”
  this.fieldElement = document.createElement('input');
  this.fieldElement.type = 'text';
  this.fieldElement.value = this.value; // 默认显示当前文字
  this.containerElement.appendChild(this.fieldElement);

  // 4. 做两个按钮
  this.saveButton = document.createElement('input');
  this.saveButton.type = 'button';
  this.saveButton.value = '保存';
  this.containerElement.appendChild(this.saveButton);

  this.cancelButton = document.createElement('input');
  this.cancelButton.type = 'button';
  this.cancelButton.value = '取消';
  this.containerElement.appendChild(this.cancelButton);

  // 5. 把整个大盒子贴到网页上
  this.parentElement.appendChild(this.containerElement);

  // 6. 默认状态:只显示文字,其他都藏起来
  this.convertToText();
}

📦 此时,网页上多了这样一个结构(但你看不到全部):

<div id="slogan">
  <span>肯德基真香</span>
  <input type="text" value="肯德基真香" style="display:none">
  <input type="button" value="保存" style="display:none">
  <input type="button" value="取消" style="display:none">
</div>

✅ 所有东西都准备好了,只是“看不见”——靠 display: none 隐藏。


第四步:控制谁看得见 —— 状态切换

🔄 convertToText():回到“只读模式”

convertToText: function() {
  this.fieldElement.style.display = 'none';     // 隐藏输入框
  this.saveButton.style.display = 'none';       // 隐藏保存按钮
  this.cancelButton.style.display = 'none';     // 隐藏取消按钮
  this.staticElement.style.display = 'inline';  // 显示文字
}

✏️ convertToField():进入“编辑模式”

convertToField: function() {
  this.staticElement.style.display = 'none';    // 隐藏文字
  this.fieldElement.style.display = 'inline';   // 显示输入框
  this.saveButton.style.display = 'inline';     // 显示保存按钮
  this.cancelButton.style.display = 'inline';   // 显示取消按钮
}

💡 就像遥控器切换电视画面:不是换台,而是切换哪个信号源显示


第五步:让盒子“听得懂话” —— 绑定事件

attachEvent: function() {
  // 机关1:点文字 → 进入编辑
  this.staticElement.addEventListener('click', () => {
    this.convertToField();
  });

  // 机关2:点保存 → 保存并退出
  this.saveButton.addEventListener('click', () => {
    this.save();
  });

  // 机关3:点取消 → 放弃并退出
  this.cancelButton.addEventListener('click', () => {
    this.cancel();
  });
}

❗ 为什么用箭头函数 () => {}

因为:

  • 如果用普通函数 function(){},里面的 this 会变成被点击的元素(比如 <span>
  • 但我们希望 this 是整个盒子(即 EditInPlace 实例)
  • 箭头函数不会创建自己的 this,它会“继承”外层的 this

✅ 这是 JavaScript 中最容易踩坑的地方之一,用箭头函数就安全了。


第六步:真正的“干活”逻辑 —— 保存 or 取消

✅ 点“保存”时:

save: function() {
  var newValue = this.fieldElement.value;      // 拿到新内容
  this.value = newValue;                       // 更新盒子的记忆
  this.staticElement.innerHTML = newValue;     // 更新显示的文字
  this.convertToText();                        // 切回只读模式

  // 未来可以加这行:把新内容发给服务器
  // fetch('/api/update-slogan', { method: 'POST', body: newValue })
}

❌ 点“取消”时:

cancel: function() {
  this.convertToText(); // 直接切回去,不改 this.value
}

✅ 所以“取消”后,下次再编辑,还是上次保存的内容,不会丢失。


第七步:怎么用?—— 三行代码搞定

新建一个 HTML 文件:

<!DOCTYPE html>
<html>
<body>
  <!-- 1. 准备一个“挂盒子的地方” -->
  <div id="app"></div>

  <!-- 2. 引入我们的 EditInPlace 类 -->
  <script src="./edit_in_place.js"></script>

  <!-- 3. 造一个盒子! -->
  <script>
    const myEditor = new EditInPlace(
      'user-slogan',                // 盒子ID
      '有了肯德基,生活好滋味',   // 初始文字
      document.getElementById('app') // 挂到 #app 里
    );
  </script>
</body>
</html>

打开浏览器,你会看到:

  • 页面显示 “有了肯德基,生活好滋味”
  • 点它 → 出现输入框和按钮
  • 改成 “全栈工程师” → 点保存 → 文字变了
  • 再点 → 改成 “摸鱼专家” → 点取消 → 还是 “全栈工程师”

第八步:为什么说这是“面向对象”?三大好处

1️⃣ 封装(Encapsulation)

  • 所有数据(value)和操作(saveconvertToText)都包在一个对象里
  • 外部不需要知道内部怎么实现,只要会用就行

2️⃣ 复用(Reusability)

  • 今天用在“签名”,明天用在“昵称”,后天用在“商品描述”
  • 只要引入 edit_in_place.js,一行 new EditInPlace(...) 就搞定

3️⃣ 模块化(Modularity)

  • 一个文件一个功能
  • 类的作者和使用者可以是不同的人
  • 作者写好注释,使用者照着用,互不干扰

第九步:如果我是“笨蛋”,该怎么理解?

记住这 5 句话:

  1. new EditInPlace(...) 就是“造一个智能小盒子”
  2. this 就是“这个盒子自己”
  3. 所有按钮和输入框都提前做好了,只是“藏起来”
  4. 点文字 → 把藏的东西“拿出来”;点保存/取消 → “收回去”
  5. 用箭头函数,是为了让盒子“认得自己是谁”

第十步:你可以动手试试!

  1. 把代码复制到 edit_in_place.js
  2. 新建一个 HTML 文件,按上面例子写
  3. 打开浏览器,点文字试试
  4. 在控制台输入 console.log(myEditor),看看盒子里有什么

你会发现:编程没那么难,只是把现实世界的逻辑搬到电脑里而已


❤️ 结语:写给每一个觉得自己“笨”的你

你不是笨,你只是还没遇到足够慢、足够细、足够耐心的解释。

面向对象、原型、this、闭包……这些概念听起来高大上,其实都是为了解决现实问题而生的工具。

EditInPlace 这个例子,就是一个小小的起点。
你已经迈出了理解 OOP 的第一步——恭喜你

如果你还有哪里不明白,比如:

  • “为什么不用 innerHTML 直接替换?”
  • “能不能支持按回车保存?”
  • “怎么加样式让它更好看?”

欢迎随时提问!我会继续用“笨蛋也能懂”的方式,陪你一步步走下去 💪