随着AI技术发展,参差不齐的图文出现,用户体验显得更加重要。本文将通过一个具体的例子——编辑和查看模式的切换,对比传统DOM编程和React编程的不同实现方式,并且用Form对Dom编程进行优化,并探讨如何优化用户体验。
EditInPlace 就地编程
就地编辑(EditInPlace)是一种用户界面设计模式,允许用户直接在页面上修改内容,而无需跳转到单独的编辑页面或打开新的窗口。举个bilibili的栗子
1. 传统DOM编程实现
传统的DOM编程直接操作DOM元素,通过JavaScript来实现页面的动态效果。先上代码:
传统dom设计思路
- DOM节点获取: 使用
document.getElementById获取页面上的DOM节点。 - 状态切换:
convertToText和convertToEdit函数分别用于切换到文本状态和编辑状态。 - 事件监听: 通过
addEventListener为按钮和文本内容添加点击事件,实现状态的切换和内容的更新。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>EditInPlace 哔哩哔哩用户体验打造</title>
</head>
<body>
<div id="app"> // 在页面呈现
<div id="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>
<script>
// 获取DOM节点
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'; // 隐藏文字
}
// 初始化为文本状态
convertToText();
// 点击内容切换到编辑状态
content.addEventListener('click', () => {
convertToEdit();
input.value = content.innerText; // 输入框的值等于文本内容
});
// 点击保存按钮,保存编辑内容
save.addEventListener('click', () => {
content.innerText = input.value;
convertToText();
});
// 点击取消按钮,恢复到文本状态
cancel.addEventListener('click', () => {
convertToText();
});
</script>
</body>
</html>
先用dom进行简单事件实现:点击“save”和“cancel”进行事件处理。“save”按钮,点击对编辑好的内容进行保存,“cancel”取消编辑,保留原来状态。
2. 使用React编程
React是一种用于构建用户界面的JavaScript库,它通过虚拟DOM和组件化的方式简化了UI的开发。React的状态管理和生命周期方法使得管理复杂界面变得更加容易。
react设计思路:
- 状态管理: 使用
useState钩子管理一个状态数组items,每个项目包含id、content和mode属性。 - 模式切换:
switchToViewMode和switchToEditMode函数用于切换项目的模式。 - 内容更改:
handleContentChange函数用于处理文本内容的更改。 - 条件渲染: 根据项目的
mode属性,条件渲染编辑模式或查看模式。
// 导入useState 钩子,用于声明状态变量,让组件保留信息2(比如下面的列表内容content,模式mode)
import React, { useState } from 'react';
// 定义组件APP
function App() {
// 状态变量 items ,存储多个列表项,每个item 有唯一id ,初始状态为view
const [items, setItems] = useState([
{ id: 1, content: '第一条内容', mode: 'view' },
{ id: 2, content: '第二条内容', mode: 'view' },
{ id: 3, content: '第三条内容', mode: 'view' }
]);
// 切换到查看模式 ,设置mode 为view
const switchToViewMode = (id) => {
setItems(items.map(item =>
item.id === id ? { ...item, mode: 'view' } : item
));
};
const switchToEditMode = (id) => {
// 更新setItems ,变量items数组,
setItems(items.map(item =>
item.id === id ? { ...item, mode: 'edit' } : item
));
};
// 处理列表内容变化,编辑状态触发这个函数。负责更新content属性,并且通过setItems更新
// content 用户在textarea 里面输入的新内容
const handleContentChange = (id, content) => {
// items 从useState 钩子 获取 包含多个列表数组
setItems(items.map(item =>
// item.id === id: 检查当前遍历到的列表项的 id 是否与传入的 id 相等
item.id === id ? { ...item, content } : item
));
};
// 渲染列表
return (
<div>
<ul>
{items.map(item => (
// 遍历获取 单个列表id
<li key={item.id}>
{item.mode === 'edit' ? (
<div>
// 多行文本编辑
<textarea
value={item.content}
// onChange 事件处理器,输入框输入内容,调用编辑函数
onChange={(e) => handleContentChange(item.id, e.target.value)}
/>
// 查看模式按钮
<button onClick={() => switchToViewMode(item.id)}>查看模式</button>
</div>
) : (
<div>
<p>{item.content}</p>
<button onClick={() => switchToEditMode(item.id)}>编辑模式</button>
</div>
)}
</li>
))}
</ul>
</div>
);
}
export default App;
对于return 回来的渲染列表
- 如果mode为edit,则显示一个textarea输入框和一个“查看模式”按钮。用户可以在输入框中编辑内容,点击按钮后切换回查看模式。
- 如果mode为view,则显示一段文本和一个“编辑模式”按钮。点击按钮后切换到编辑模式。
值得回味,分析下面代码:
const handleContentChange = (id, content) => {
setItems(items.map(item =>
item.id === id ? { ...item, content } : item
));
};
- item.id === id: 检查当前遍历到的列表项的 id 是否与传入的 id 相等。
- 如果相等,则创建一个新的对象 { ...item, content }:
- { ...item } 表示将当前列表项的所有属性复制到新对象中。
- content 表示将新输入的内容覆盖原来的 content 属性。
- 如果不相等,则直接返回当前的 item 对象,不做任何修改。
3.用户体验优化
为了进一步优化用户体验,我们可以添加一些提示信息和动画效果,使用户操作更加直观和友好。Form表单
(1)传统DOM编程中的用户体验优化
<body>
<div id="app">
</div>
<script src="./editInPlace.js"></script>
<script>
// 流程代码, 走向面向对象封装
new EditInPlace(
'ep1',
document.getElementById('app')
);
new EditInPlace(
'ep2',
document.getElementById('app'),
'好嗨哟'
);
</script>
</body>
代码分析:
- 动画效果: 使用CSS动画为元素添加淡入效果,使用户操作更加平滑。
- 封装类: 使用面向对象的方式封装编辑功能,提高代码的可维护性和复用性。
- 事件监听: 为静态文本、保存按钮和取消按钮添加点击事件,实现模式的切换和内容的更新。 使用封装一个类进行类似登入等,进行编辑和查看事件的切换。
(2) prototype关联封装类
prototype 是一个对象,运行向构造方法添加属性和方法,这样通过这个构造函数创建的所有实例都共享属性和方法,很大程度节省空间,,所有实例都可以访问。 createElement 是document 对象内置方法。“挂载”,可以说是元素添加到父元素,也就是添加得到dom树
function EditInPlace(id, parent, value) {
this.id = id; // 跨函数共享属性
this.parent = parent || document.body;
this.value = value || '这个家伙很懒,什么都没有留下';
this.createElement(this.id);
}
EditInPlace.prototype.createElement = function(id) {
// console.log(id);
// 创建容器元素 div,挂载 id
// <div id="ep1"></div>
this.containerElement = document.createElement('div');
this.containerElement.id = id;
// 将 containerElement 元素添加到 parent 元素中,使其成为 parent 的子元素,方便在页面上显示和布局管理
this.parent.appendChild(this.containerElement);
this.staticElement = document.createElement('span');
this.staticElement.innerText = this.value; // 静态文本等于 value
// 将静态文本 span 添加到 id 为 ep1 的 div 中
this.containerElement.appendChild(this.staticElement);
}
结论
无论是传统DOM编程还是React编程,都能实现编辑和查看模式的切换功能。然而,React通过虚拟DOM和组件化的方式,使得状态管理和界面更新更加简洁和高效。同时,通过添加动画效果和提示信息,可以显著提升用户的操作体验。
在实际开发中,还是要根据项目的需求和技术栈选择合适的开发方式,以实现最佳的用户体验。这样才能体现你的开发水平。