使用DOM实现HTML就地编辑:提升用户体验的利器

23 阅读8分钟

今天要和大家分享一个非常实用的小技巧——如何使用使用DOM(Document Object Model)实现HTML页面的就地编辑功能。如果你是前端开发者或者对提升用户体验感兴趣,那么这篇文章绝对适合你。我们将一步步地讲解如何通过JavaScript操作DOM来实现这个功能。

项目背景

在许多Web应用中,用户需要能够直接在页面上编辑内容,而不需要跳转到专门的编辑页面。这种就地编辑功能可以极大地提升用户体验,使操作更加直观和高效。本教程将教你如何利用JavaScript和DOM来实现这一功能。

准备工作

首先确保你的电脑上已经安装了现代浏览器(如Chrome、Firefox等),并且你有一定的HTML、CSS和JavaScript基础。接下来,我们开始编写代码。

代码详解1

1. HTML结构

 <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <title>就地编辑示例</title>
        <style>
            .editable {
                border: 1px solid #ccc;
                padding: 5px;
                cursor: pointer;
            }
            .editable.editing {
                border-color: #007bff;
                background-color: #f8f9fa;
            }
        </style>
    </head>
    <body>
        <h1>就地编辑示例</h1>
        <div id="content" class="editable" contenteditable="false">
            这是一段可编辑的文字。
        </div>

        <script src="script.js"></script>
    </body>
    </html>

2. JavaScript逻辑

  // script.js
    document.addEventListener('DOMContentLoaded', () => {
        const editableDiv = document.getElementById('content');

        // 添加点击事件监听器
        editableDiv.addEventListener('click', () => {
            if (editableDiv.getAttribute('contenteditable') === 'false') {
                // 切换为可编辑状态
                editableDiv.setAttribute('contenteditable', 'true');
                editableDiv.classList.add('editing');
            } else {
                // 切换为不可编辑状态
                editableDiv.setAttribute('contenteditable', 'false');
                editableDiv.classList.remove('editing');
            }
        });

        // 监听键盘事件,按Enter键保存编辑内容
        editableDiv.addEventListener('keydown', (event) => {
            if (event.key === 'Enter') {
                event.preventDefault(); // 阻止默认行为
                editableDiv.blur(); // 失去焦点
            }
        });

        // 监听失去焦点事件,保存编辑内容
        editableDiv.addEventListener('blur', () => {
            editableDiv.setAttribute('contenteditable', 'false');
            editableDiv.classList.remove('editing');
        });
    });
  1. HTML结构
-   我们创建了一个简单的HTML页面,其中包含一个`<div>`元素,其`id``content`,并添加了`class``editable`
-   `contenteditable`属性设置为`false`,表示初始状态下该元素不可编辑。
-   CSS样式用于美化可编辑区域,当处于编辑状态时,边框颜色和背景色会有所变化。

2. JavaScript逻辑

-`DOMContentLoaded`事件触发后,获取`content`元素。
-`content`元素添加点击事件监听器,当点击时切换`contenteditable`属性,使其在可编辑和不可编辑之间切换,并相应地更新类名。
-   添加键盘事件监听器,当按下`Enter`键时,阻止默认行为并使元素失去焦点,从而保存编辑内容。
-   添加失去焦点事件监听器,当元素失去焦点时,将其设置为不可编辑状态,并移除`editing`类名。

代码解析2

1.HTML结构

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <div class="app">
    </div>
    <script src="./editInPlace.js"></script>
    <script>
        // 流程代码,走向面向对象封装
        new EditInPlace(
            '.ep1',
            document.getElementById('app'),
            '非主流:魢知我爱祢,求证你爱苊。'
        );
    </script>
</body>
</html>

代码解释

new EditInPlace(
    '.ep1',
    document.getElementById('app'),
    '非主流:魢知我爱祢,求证你爱苊。'
);
  1. new EditInPlace(...)

    • 这行代码创建了一个新的 EditInPlace 对象。EditInPlace 是一个构造函数,用于创建就地编辑组件的实例。
  2. 参数解析

    • 第一个参数:.ep1

      • 这是一个字符串,表示要创建的元素的ID选择器。虽然这里的值是 .ep1,但实际上它应该是一个有效的ID(例如 #ep1),因为 id 属性不能以点号开头。假设这里是一个笔误,正确的写法应该是 #ep1
    • 第二个参数:document.getElementById('app')

      • 这是一个DOM元素,表示将要插入新创建的编辑组件的父节点。document.getElementById('app') 获取到页面中ID为 app 的元素(即 <div class="app"></div>)。
    • 第三个参数:'非主流魢知我爱祢,求证你爱苊。'

      • 这是一个字符串,表示默认显示的文本内容。在这个例子中,文本内容是“非主流魢知我爱祢,求证你爱免。”

2.JavaScript代码

/**
 * @func 就地编辑
 * @param {id, parent 父节点, value 默认值}
 * @author xxx
 * @date 2024-12-01
 */

function EditInPlace(id, parent, value) {
    this.id = id; // 跨函数共享属性
    this.parent = parent || document.body; // 如果前面没有传参,默认是body(根节点)
    this.value = value || '这个家伙很懒,什么都没留下';
    this.createElement(this.id);
}

EditInPlace.prototype.createElement = function (id) {
    // console.log(id);
    // <div id="ep1"></div>
    this.containerElement = document.createElement('div');
    this.containerElement.id = this.id;
    this.parent.appendChild(this.containerElement);

    this.staticElement = document.createElement('span');
    this.staticElement.innerText = this.value;
    this.containerElement.appendChild(this.staticElement);
}
  1. 构造函数

    function EditInPlace(id, parent, value) {
        this.id = id; // 跨函数共享属性
        this.parent = parent || document.body; // 如果前面没有传参,默认是body(根节点)
        this.value = value || '这个家伙很懒,什么都没留下';
        this.createElement(this.id);
    }
    
    • this.id:存储传递进来的ID。
    • this.parent:存储传递进来的父节点,默认为document.body
    • this.value:存储传递进来的默认值,默认为“这个家伙很懒,什么都没留下”。
    • this.createElement(this.id):调用createElement方法创建DOM元素。
  2. 原型方法

    EditInPlace.prototype.createElement = function (id) {
        this.containerElement = document.createElement('div');
        this.containerElement.id = this.id;
        this.parent.appendChild(this.containerElement);
    
        this.staticElement = document.createElement('span');
        this.staticElement.innerText = this.value;
        this.containerElement.appendChild(this.staticElement);
    }
    
    • this.containerElement:创建一个<div>元素,并设置其ID为传递进来的ID。
    • this.parent.appendChild(this.containerElement):将containerElement添加到父节点中。
    • this.staticElement:创建一个<span>元素,并设置其文本内容为默认值。
    • this.containerElement.appendChild(this.staticElement):将staticElement添加到containerElement中。

3.代码执行流程

  1. 创建 EditInPlace 实例

    new EditInPlace('.ep1', document.getElementById('app'), '非主流:魢知我爱祢,求证你爱免。');
    
    • id 被设置为 .ep1
    • parent 被设置为 document.getElementById('app'),即页面中的 <div class="app"></div>
    • value 被设置为 '非主流魢知我爱祢,求证你爱免。'
  2. 调用 createElement 方法

    • 在 EditInPlace 构造函数中,调用了 this.createElement(this.id) 方法。
    • createElement 方法创建了一个新的 div 元素,并将其ID设置为 .ep1
    • 将这个 div 元素添加到父节点 <div class="app"></div> 中。
    • 创建了一个 span 元素,并将其文本内容设置为 '非主流:魢知我爱祢,求证你爱免。'
    • 将这个 span 元素添加到 div 容器中。

4.最终效果

在页面中,最终会生成如下的HTML结构:

<div class="app">
    <div id=".ep1">
        <span>非主流:魢知我爱祢,求证你爱免。</span>
    </div>
</div>

代码详解3

HTML结构

<div class="app">
    <div class="ep1">
        <span id="content">个性签名:</span>
        <input type="text" id="input" value="不识庐山真面目,只缘身在此山中。">
        <input type="button" id="save" value="Save">
        <input type="button" id="cancel" value="Cancel">
    </div>
</div>

1. 外层容器 <div class="app">

  • 这是一个外层容器,用于包裹整个编辑组件。
  • 类名 class="app" 可以用于CSS样式或其他JavaScript操作。

2. 编辑组件容器 <div class="ep1">

  • 这是编辑组件的主要容器。
  • 类名 class="ep1" 可以用于CSS样式或其他JavaScript操作。

3. 文本显示区域 <span id="content">个性签名:</span>

  • 这是一个<span>元素,用于显示当前的文本内容。
  • id="content" 用于通过JavaScript来获取和设置这个元素的内容。
  • 初始文本内容为“个性签名:”。

4. 输入框 <input type="text" id="input" value="不识庐山真面目,只缘身在此山中。">

  • 这是一个文本输入框,用户可以在这里输入新的文本内容。
  • id="input" 用于通过JavaScript来获取和设置这个输入框的值。
  • 初始值为“不识庐山真面目,只缘身在此山中。”。

5. 保存按钮 <input type="button" id="save" value="Save">

  • 这是一个按钮,用户点击它可以保存编辑后的内容。
  • id="save" 用于通过JavaScript来添加事件监听器。
  • 按钮的文本为“Save”。

6. 取消按钮 <input type="button" id="cancel" value="Cancel">

  • 这是一个按钮,用户点击它可以取消编辑,恢复到原始状态。
  • id="cancel" 用于通过JavaScript来添加事件监听器。
  • 按钮的文本为“Cancel”。

功能解释

  1. 初始状态

    • 页面加载时,<span id="content"> 显示当前的文本内容“个性签名:”。
    • <input type="text"> 和两个按钮(保存和取消)默认是隐藏的。
  2. 进入编辑状态

    • 当用户点击 <span id="content"> 时,触发一个事件,将 <span> 隐藏,并显示 <input> 和两个按钮。
    • 同时,将 <span> 中的文本内容复制到 <input> 中,以便用户可以直接编辑。
  3. 保存编辑内容

    • 当用户点击保存按钮时,将 <input> 中的内容更新到 <span> 中,并隐藏 <input> 和两个按钮,恢复到初始状态。
  4. 取消编辑

    • 当用户点击取消按钮时,隐藏 <input> 和两个按钮,恢复到初始状态,不保存任何更改。

JavaScript代码

 <script>
        // dom js html 节点对象 动态操作html
        const content = document.getElementById('content');
        const input = document.getElementById('input');
        const save = document.getElementById('save');
        const cancel = document.getElementById('cancel');

        // 文本状态
        function convertToText() {
            input.style.display = 'none';
            save.style.display = 'none';
            cancel.style.display = 'none';
            content.style.display = 'inline';
        }

        // 编辑状态
        function convertToEdit() {
            input.style.display = 'inline';
            save.style.display = 'inline';
            cancel.style.display = 'inline';
            content.style.display = 'none';
        }

        // 点击文本 进入编辑状态
        content.addEventListener('click', function () {
            convertToEdit();
            // 输人框里是最新的签名
            input.value = content.innerText;
        })

        // 点击取消按钮 取消编辑
        cancel.addEventListener('click', function () {
            convertToText();
        })

        // 点击保存按钮 保存编辑内容
        save.addEventListener('click', function () {
            // 保存编辑内容
            content.innerText = input.value;
            convertToText();
        })

    </script>

代码解析

// 获取DOM元素
const content = document.getElementById('content');
const input = document.getElementById('input');
const save = document.getElementById('save');
const cancel = document.getElementById('cancel');
  • 获取DOM元素

    • document.getElementById 方法用于通过ID选择器获取页面中的特定元素。
    • content:获取 <span id="content"> 元素。
    • input:获取 <input type="text" id="input"> 元素。
    • save:获取 <input type="button" id="save"> 元素。
    • cancel:获取 <input type="button" id="cancel"> 元素。

文本状态函数

// 文本状态
function convertToText() {
    input.style.display = 'none';
    save.style.display = 'none';
    cancel.style.display = 'none';
    content.style.display = 'inline';
}
  • convertToText 函数

    • 将输入框、保存按钮和取消按钮隐藏(display: none)。
    • 显示文本内容(<span> 元素),使其可见(display: inline)。

编辑状态函数

// 编辑状态
function convertToEdit() {
    input.style.display = 'inline';
    save.style.display = 'inline';
    cancel.style.display = 'inline';
    content.style.display = 'none';
}
  • convertToEdit 函数

    • 将输入框、保存按钮和取消按钮显示出来(display: inline)。
    • 隐藏文本内容(<span> 元素),使其不可见(display: none)。

事件监听器

// 点击文本 进入编辑状态
content.addEventListener('click', function () {
    convertToEdit();
    // 输入框里是最新的签名
    input.value = content.innerText;
})
  • 点击文本进入编辑状态

    • 为 <span id="content"> 添加一个点击事件监听器。
    • 当用户点击 <span> 时,调用 convertToEdit 函数,切换到编辑状态。
    • 将 <span> 中的文本内容复制到输入框中,以便用户可以直接编辑。
// 点击取消按钮 取消编辑
cancel.addEventListener('click', function () {
    convertToText();
})
  • 点击取消按钮取消编辑

    • 为 <input type="button" id="cancel"> 添加一个点击事件监听器。
    • 当用户点击取消按钮时,调用 convertToText 函数,恢复到文本状态,不保存任何更改。
// 点击保存按钮 保存编辑内容
save.addEventListener('click', function () {
    // 保存编辑内容
    content.innerText = input.value;
    convertToText();
})
  • 点击保存按钮保存编辑内容

    • 为 <input type="button" id="save"> 添加一个点击事件监听器。
    • 当用户点击保存按钮时,将输入框中的内容更新到 <span> 元素中。
    • 调用 convertToText 函数,恢复到文本状态,显示更新后的内容。

效果展示

image.png

image.png

结语

通过以上步骤,我们成功实现了HTML页面的就地编辑功能。这个简单的示例展示了如何使用DOM和JavaScript来提升用户体验。你可以根据实际需求扩展这个功能,例如添加数据存储、验证等功能。 希望这篇教程对你有所帮助!