react渲染与提交

Posted on 2026-04-09 16:06  打杂滴  阅读(0)  评论(0)    收藏  举报

<!DOCTYPE html>
<html lang="zh-CN">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>React 渲染与提交学习实例</title>
  <script src="https://unpkg.com/react@18/umd/react.development.js"></script>
  <script src="https://unpkg.com/react-dom@18/umd/react-dom.development.js"></script>
  <script src="https://unpkg.com/@babel/standalone/babel.min.js"></script>
  <link href="https://cdn.jsdelivr.net/npm/tailwindcss@2.2.19/dist/tailwind.min.css" rel="stylesheet">
  <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0/css/all.min.css">
</head>
<body class="bg-gradient-to-br from-blue-50 to-indigo-100 min-h-screen">
  <div id="root" class="container mx-auto px-4 py-8"></div>

  <script type="text/babel">
    const { useState, useEffect } = React;

    // 学习记录项组件
    const LearningItem = ({ item, onDelete, onEdit }) => {
      const [isEditing, setIsEditing] = useState(false);
      const [editValue, setEditValue] = useState(item.text);

      const handleSave = () => {
        if (editValue.trim()) {
          onEdit(item.id, editValue);
          setIsEditing(false);
        }
      };

      return (
        <div className="bg-white rounded-xl shadow-md p-4 mb-3 transition-all duration-300 hover:shadow-lg">
          <div className="flex items-start">
            <div className="flex-1">
              {isEditing ? (
                <div className="flex flex-col space-y-2">
                  <input
                    type="text"
                    value={editValue}
                    onChange={(e) => setEditValue(e.target.value)}
                    className="border-b-2 border-indigo-300 focus:border-indigo-500 outline-none pb-1 w-full"
                    autoFocus
                  />
                  <div className="flex space-x-2 pt-2">
                    <button
                      onClick={handleSave}
                      className="px-3 py-1 bg-green-500 text-white rounded-lg text-sm hover:bg-green-600 transition-colors"
                    >
                      保存
                    </button>
                    <button
                      onClick={() => setIsEditing(false)}
                      className="px-3 py-1 bg-gray-300 text-gray-700 rounded-lg text-sm hover:bg-gray-400 transition-colors"
                    >
                      取消
                    </button>
                  </div>
                </div>
              ) : (
                <div>
                  <p className="text-gray-800">{item.text}</p>
                  <p className="text-xs text-gray-500 mt-1">
                    <i className="far fa-clock mr-1"></i>
                    {new Date(item.timestamp).toLocaleString('zh-CN')}
                  </p>
                </div>
              )}
            </div>
            {!isEditing && (
              <div className="flex space-x-2 ml-2">
                <button
                  onClick={() => setIsEditing(true)}
                  className="text-blue-500 hover:text-blue-700 transition-colors"
                  title="编辑"
                >
                  <i className="fas fa-edit"></i>
                </button>
                <button
                  onClick={() => onDelete(item.id)}
                  className="text-red-500 hover:text-red-700 transition-colors"
                  title="删除"
                >
                  <i className="fas fa-trash-alt"></i>
                </button>
              </div>
            )}
          </div>
        </div>
      );
    };

    // 主应用组件
    const App = () => {
      const [inputValue, setInputValue] = useState('');
      const [items, setItems] = useState([]);
      const [filter, setFilter] = useState('all');
      const [searchTerm, setSearchTerm] = useState('');

      // 从本地存储加载数据
      useEffect(() => {
        const savedItems = localStorage.getItem('learningItems');
        if (savedItems) {
          setItems(JSON.parse(savedItems));
        }
      }, []);

      // 保存数据到本地存储
      useEffect(() => {
        localStorage.setItem('learningItems', JSON.stringify(items));
      }, [items]);

      // 提交新学习记录
      const handleSubmit = (e) => {
        e.preventDefault();
        if (inputValue.trim()) {
          const newItem = {
            id: Date.now(),
            text: inputValue.trim(),
            timestamp: new Date().toISOString()
          };
          setItems([newItem, ...items]);
          setInputValue('');
        }
      };

      // 删除学习记录
      const handleDelete = (id) => {
        setItems(items.filter(item => item.id !== id));
      };

      // 编辑学习记录
      const handleEdit = (id, newText) => {
        setItems(items.map(item =>
          item.id === id ? {...item, text: newText} : item
        ));
      };

      // 清空所有记录
      const handleClearAll = () => {
        if (window.confirm('确定要清空所有学习记录吗?')) {
          setItems([]);
        }
      };

      // 过滤和搜索逻辑
      const filteredItems = items.filter(item => {
        const matchesSearch = item.text.toLowerCase().includes(searchTerm.toLowerCase());
        return matchesSearch;
      });

      const completedCount = items.length;
      const todayCount = items.filter(item =>
        new Date(item.timestamp).toDateString() === new Date().toDateString()
      ).length;

      return (
        <div className="max-w-2xl mx-auto">
          {/* 头部 */}
          <header className="text-center mb-10">
            <h1 className="text-4xl font-bold text-indigo-700 mb-2">
              <i className="fas fa-book-reader mr-3"></i>学习记录系统
            </h1>
            <p className="text-gray-600">记录你的每一个学习瞬间</p>
          </header>

          {/* 统计卡片 */}
          <div className="grid grid-cols-1 md:grid-cols-2 gap-4 mb-8">
            <div className="bg-gradient-to-r from-indigo-500 to-purple-600 rounded-xl p-5 text-white shadow-lg">
              <div className="flex items-center">
                <i className="fas fa-tasks text-3xl mr-4"></i>
                <div>
                  <p className="text-sm opacity-80">总计记录</p>
                  <p className="text-3xl font-bold">{completedCount}</p>
                </div>
              </div>
            </div>
            <div className="bg-gradient-to-r from-green-500 to-blue-600 rounded-xl p-5 text-white shadow-lg">
              <div className="flex items-center">
                <i className="fas fa-calendar-day text-3xl mr-4"></i>
                <div>
                  <p className="text-sm opacity-80">今日新增</p>
                  <p className="text-3xl font-bold">{todayCount}</p>
                </div>
              </div>
            </div>
          </div>

          {/* 输入表单 */}
          <div className="bg-white rounded-2xl shadow-xl p-6 mb-8">
            <form onSubmit={handleSubmit} className="space-y-4">
              <div>
                <label htmlFor="learningInput" className="block text-lg font-medium text-gray-700 mb-2">
                  添加新的学习记录
                </label>
                <div className="flex space-x-2">
                  <input
                    id="learningInput"
                    type="text"
                    value={inputValue}
                    onChange={(e) => setInputValue(e.target.value)}
                    placeholder="今天学到了什么?"
                    className="flex-1 px-4 py-3 border-2 border-gray-200 rounded-xl focus:border-indigo-500 focus:outline-none transition-colors"
                  />
                  <button
                    type="submit"
                    disabled={!inputValue.trim()}
                    className={`px-6 py-3 rounded-xl font-semibold transition-all ${
                      inputValue.trim()
                        ? 'bg-indigo-600 text-white hover:bg-indigo-700 transform hover:-translate-y-0.5 shadow-md hover:shadow-lg'
                        : 'bg-gray-300 text-gray-500 cursor-not-allowed'
                    }`}
                  >
                    <i className="fas fa-plus-circle mr-2"></i>提交
                  </button>
                </div>
              </div>
            </form>
          </div>

          {/* 控制面板 */}
          <div className="bg-white rounded-2xl shadow-xl p-6 mb-8">
            <div className="flex flex-col md:flex-row md:items-center md:justify-between space-y-4 md:space-y-0">
              <div className="flex items-center space-x-4">
                <span className="text-gray-700 font-medium">搜索:</span>
                <div className="relative">
                  <input
                    type="text"
                    value={searchTerm}
                    onChange={(e) => setSearchTerm(e.target.value)}
                    placeholder="查找学习记录..."
                    className="pl-10 pr-4 py-2 border-2 border-gray-200 rounded-lg focus:border-indigo-500 focus:outline-none w-full md:w-64"
                  />
                  <i className="fas fa-search absolute left-3 top-3 text-gray-400"></i>
                </div>
              </div>
             
              <div className="flex items-center space-x-4">
                <span className="text-gray-700 font-medium">操作:</span>
                <button
                  onClick={handleClearAll}
                  disabled={items.length === 0}
                  className={`px-4 py-2 rounded-lg flex items-center ${
                    items.length > 0
                      ? 'bg-red-500 text-white hover:bg-red-600'
                      : 'bg-gray-300 text-gray-500 cursor-not-allowed'
                  }`}
                >
                  <i className="fas fa-trash-alt mr-2"></i>清空全部
                </button>
              </div>
            </div>
          </div>

          {/* 学习记录列表 */}
          <div className="bg-white rounded-2xl shadow-xl p-6">
            <div className="flex items-center justify-between mb-6">
              <h2 className="text-2xl font-bold text-gray-800">
                <i className="fas fa-list mr-2"></i>学习记录列表
              </h2>
              <span className="bg-indigo-100 text-indigo-800 px-3 py-1 rounded-full text-sm">
                共 {filteredItems.length} 条记录
              </span>
            </div>

            {filteredItems.length === 0 ? (
              <div className="text-center py-12">
                <i className="fas fa-inbox text-5xl text-gray-300 mb-4"></i>
                <h3 className="text-xl font-medium text-gray-500 mb-2">暂无学习记录</h3>
                <p className="text-gray-400">
                  {items.length === 0
                    ? '开始添加你的第一条学习记录吧!'
                    : '没有找到匹配的记录'}
                </p>
              </div>
            ) : (
              <div className="space-y-3">
                {filteredItems.map(item => (
                  <LearningItem
                    key={item.id}
                    item={item}
                    onDelete={handleDelete}
                    onEdit={handleEdit}
                  />
                ))}
              </div>
            )}
          </div>

          {/* 页脚 */}
          <footer className="mt-12 text-center text-gray-500 text-sm">
            <p>© 2026 学习记录系统 - 记录成长的每一步</p>
          </footer>
        </div>
      );
    };

    const root = ReactDOM.createRoot(document.getElementById('root'));
    root.render(<App />);
  </script>
</body>
</html>
 

image

 

博客园  ©  2004-2026
浙公网安备 33010602011771号 浙ICP备2021040463号-3