🌟 超详细图解:用面向对象(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 会:
- 创建一个全新的空对象 →
{} - 把这个空对象当作
this,传给EditInPlace函数 - 所有
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)和操作(save,convertToText)都包在一个对象里 - 外部不需要知道内部怎么实现,只要会用就行
2️⃣ 复用(Reusability)
- 今天用在“签名”,明天用在“昵称”,后天用在“商品描述”
- 只要引入
edit_in_place.js,一行new EditInPlace(...)就搞定
3️⃣ 模块化(Modularity)
- 一个文件一个功能
- 类的作者和使用者可以是不同的人
- 作者写好注释,使用者照着用,互不干扰
第九步:如果我是“笨蛋”,该怎么理解?
记住这 5 句话:
new EditInPlace(...)就是“造一个智能小盒子”this就是“这个盒子自己”- 所有按钮和输入框都提前做好了,只是“藏起来”
- 点文字 → 把藏的东西“拿出来”;点保存/取消 → “收回去”
- 用箭头函数,是为了让盒子“认得自己是谁”
第十步:你可以动手试试!
- 把代码复制到
edit_in_place.js - 新建一个 HTML 文件,按上面例子写
- 打开浏览器,点文字试试
- 在控制台输入
console.log(myEditor),看看盒子里有什么
你会发现:编程没那么难,只是把现实世界的逻辑搬到电脑里而已。
❤️ 结语:写给每一个觉得自己“笨”的你
你不是笨,你只是还没遇到足够慢、足够细、足够耐心的解释。
面向对象、原型、this、闭包……这些概念听起来高大上,其实都是为了解决现实问题而生的工具。
EditInPlace 这个例子,就是一个小小的起点。
你已经迈出了理解 OOP 的第一步——恭喜你!
如果你还有哪里不明白,比如:
- “为什么不用 innerHTML 直接替换?”
- “能不能支持按回车保存?”
- “怎么加样式让它更好看?”
欢迎随时提问!我会继续用“笨蛋也能懂”的方式,陪你一步步走下去 💪