鱼C论坛

 找回密码
 立即注册
查看: 22|回复: 1

[其他工具] 2.【Vibe Coding】trea-网页投票工具

[复制链接]
发表于 2 小时前 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能^_^

您需要 登录 才可以下载或查看,没有账号?立即注册

x
本帖最后由 糖逗 于 2026-4-10 11:03 编辑

1. 目标
创建一个网页投票小程序(下面是我生成的效果)
screenshot-20260410-110028.png

2. 操作步骤

①本地创建02_Project_Vote文件夹,用Trae打开
②打开NewChat(`Ctrl+U'(Windows)、``**U`(Mac)),使用内置智能体Builder,输入提示词
③Trae会根据提示词生成程序/代码

提示词如下
  1. 你现在是一名资深网页前端开发工程师,请帮我使用原生 HTML + CSS + JavaScript
  2. 编写一个可直接在浏览器中打开使用的「在线投票程序」,要求如下:
  3. -功能:
  4. 创建投票:输入投票标题,至少含2个选项:支持添加/删除选项
  5. -开始投票:显示选项列表,点击为某一选项投票,实时更新票数与百分比
  6. -防重复投票:同一设备对同一投票仅能投一次(使用lcocalstorage记录)
  7. -结果展示:显示每个选项票数和百分比,提供简单进度条或条形图效果
  8. -数据持久化:投票标题、选项、票数、是否已投状态均使用localStorage保存,刷新后保留
  9. 重置提供"重置投票"按钮,清空数据并重新创建新的投票

  10. -界面与技术:
  11. -风格简洁淡雅(浅灰/浅蓝),居中卡片布局,按钮圆角阴影
  12. -使用CSSFlex或Grid布局;当前日期不需要显示
  13. -不使用任何框架或库;全部代码在同一个HTML文件中
  14. -使用原生JavaScript操作DOM,逻辑清晰,适量注释

  15. -输出格式:
  16. -直接保存为`vote.html`文件,
  17. -代码可直接运行,无需任何依赖
复制代码

学习视频:快速体验Trea


本帖被以下淘专辑推荐:

  • · AIGC|主题: 14, 订阅: 0
小甲鱼最新课程 -> https://ilovefishc.com
回复

使用道具 举报

发表于 2 小时前 | 显示全部楼层
以下是完整的「在线投票程序」代码,保存为 `vote.html` 后可直接在浏览器中打开使用。


  1. <!DOCTYPE html>
  2. <html lang="zh-CN">
  3. <head>
  4.     <meta charset="UTF-8">
  5.     <meta name="viewport" content="width=device-width, initial-scale=1.0">
  6.     <title>在线投票程序</title>
  7.     <style>
  8.         /* 重置默认样式 */
  9.         * {
  10.             margin: 0;
  11.             padding: 0;
  12.             box-sizing: border-box;
  13.             font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
  14.         }

  15.         body {
  16.             background-color: #f5f7fa; /* 浅灰色背景 */
  17.             display: flex;
  18.             justify-content: center;
  19.             align-items: center;
  20.             min-height: 100vh;
  21.             padding: 20px;
  22.         }

  23.         .container {
  24.             width: 100%;
  25.             max-width: 800px;
  26.             background-color: #ffffff; /* 白色卡片 */
  27.             border-radius: 16px; /* 圆角 */
  28.             box-shadow: 0 8px 24px rgba(0, 0, 0, 0.1); /* 阴影 */
  29.             padding: 30px;
  30.             margin: 20px;
  31.         }

  32.         h1 {
  33.             color: #2c3e50;
  34.             text-align: center;
  35.             margin-bottom: 20px;
  36.             font-size: 2.2rem;
  37.         }

  38.         h2 {
  39.             color: #3498db; /* 浅蓝色 */
  40.             margin-top: 30px;
  41.             margin-bottom: 15px;
  42.             font-size: 1.6rem;
  43.             border-bottom: 2px solid #ecf0f1;
  44.             padding-bottom: 8px;
  45.         }

  46.         .section {
  47.             margin-bottom: 25px;
  48.         }

  49.         .input-group {
  50.             display: flex;
  51.             flex-direction: column;
  52.             gap: 12px;
  53.             margin-bottom: 20px;
  54.         }

  55.         input[type="text"] {
  56.             padding: 12px 16px;
  57.             border: 2px solid #dfe6e9;
  58.             border-radius: 10px;
  59.             font-size: 1rem;
  60.             transition: border-color 0.3s;
  61.         }

  62.         input[type="text"]:focus {
  63.             outline: none;
  64.             border-color: #3498db;
  65.         }

  66.         .button-group {
  67.             display: flex;
  68.             flex-wrap: wrap;
  69.             gap: 12px;
  70.             margin-top: 10px;
  71.         }

  72.         button {
  73.             padding: 12px 24px;
  74.             background-color: #3498db; /* 浅蓝色按钮 */
  75.             color: white;
  76.             border: none;
  77.             border-radius: 10px; /* 按钮圆角 */
  78.             font-size: 1rem;
  79.             font-weight: 600;
  80.             cursor: pointer;
  81.             transition: background-color 0.3s, transform 0.2s;
  82.             box-shadow: 0 4px 8px rgba(52, 152, 219, 0.2); /* 按钮阴影 */
  83.         }

  84.         button:hover {
  85.             background-color: #2980b9;
  86.             transform: translateY(-2px);
  87.         }

  88.         button:active {
  89.             transform: translateY(0);
  90.         }

  91.         button.delete-btn {
  92.             background-color: #e74c3c;
  93.             box-shadow: 0 4px 8px rgba(231, 76, 60, 0.2);
  94.         }

  95.         button.delete-btn:hover {
  96.             background-color: #c0392b;
  97.         }

  98.         button.reset-btn {
  99.             background-color: #95a5a6;
  100.             box-shadow: 0 4px 8px rgba(149, 165, 166, 0.2);
  101.         }

  102.         button.reset-btn:hover {
  103.             background-color: #7f8c8d;
  104.         }

  105.         button:disabled {
  106.             background-color: #bdc3c7;
  107.             cursor: not-allowed;
  108.             transform: none;
  109.         }

  110.         .options-list {
  111.             list-style-type: none;
  112.             margin-top: 15px;
  113.         }

  114.         .options-list li {
  115.             display: flex;
  116.             justify-content: space-between;
  117.             align-items: center;
  118.             padding: 12px 16px;
  119.             background-color: #f8f9fa;
  120.             border: 1px solid #dfe6e9;
  121.             border-radius: 8px;
  122.             margin-bottom: 10px;
  123.             transition: background-color 0.3s;
  124.         }

  125.         .options-list li:hover {
  126.             background-color: #ecf0f1;
  127.         }

  128.         .vote-options {
  129.             display: grid;
  130.             gap: 15px;
  131.             margin-top: 15px;
  132.         }

  133.         .vote-option {
  134.             display: flex;
  135.             flex-direction: column;
  136.             padding: 18px;
  137.             background-color: #f8f9fa;
  138.             border: 2px solid #dfe6e9;
  139.             border-radius: 12px;
  140.             cursor: pointer;
  141.             transition: all 0.3s;
  142.         }

  143.         .vote-option:hover {
  144.             border-color: #3498db;
  145.             background-color: #e3f2fd;
  146.         }

  147.         .vote-option.voted {
  148.             border-color: #27ae60;
  149.             background-color: #d5f4e6;
  150.         }

  151.         .vote-header {
  152.             display: flex;
  153.             justify-content: space-between;
  154.             align-items: center;
  155.             margin-bottom: 10px;
  156.         }

  157.         .option-text {
  158.             font-size: 1.1rem;
  159.             font-weight: 600;
  160.             color: #2c3e50;
  161.         }

  162.         .vote-count {
  163.             font-size: 1rem;
  164.             color: #7f8c8d;
  165.         }

  166.         .progress-bar {
  167.             width: 100%;
  168.             height: 12px;
  169.             background-color: #dfe6e9;
  170.             border-radius: 6px;
  171.             overflow: hidden;
  172.             margin-top: 8px;
  173.         }

  174.         .progress-fill {
  175.             height: 100%;
  176.             background-color: #3498db;
  177.             border-radius: 6px;
  178.             width: 0%;
  179.             transition: width 0.5s ease;
  180.         }

  181.         .results {
  182.             margin-top: 30px;
  183.         }

  184.         .result-item {
  185.             margin-bottom: 20px;
  186.         }

  187.         .result-info {
  188.             display: flex;
  189.             justify-content: space-between;
  190.             margin-bottom: 6px;
  191.         }

  192.         .percentage {
  193.             font-weight: 600;
  194.             color: #2c3e50;
  195.         }

  196.         .message {
  197.             padding: 15px;
  198.             border-radius: 10px;
  199.             text-align: center;
  200.             font-weight: 600;
  201.             margin-top: 20px;
  202.         }

  203.         .message.success {
  204.             background-color: #d5f4e6;
  205.             color: #27ae60;
  206.         }

  207.         .message.error {
  208.             background-color: #fadbd8;
  209.             color: #e74c3c;
  210.         }

  211.         .message.info {
  212.             background-color: #d6eaf8;
  213.             color: #3498db;
  214.         }

  215.         .hidden {
  216.             display: none;
  217.         }
  218.     </style>
  219. </head>
  220. <body>
  221.     <div class="container">
  222.         <h1>在线投票程序</h1>

  223.         <!-- 创建投票部分 -->
  224.         <div class="section">
  225.             <h2>创建投票</h2>
  226.             <div class="input-group">
  227.                 <input type="text" id="voteTitle" placeholder="输入投票标题(例如:你最喜欢的编程语言?)" value="你最喜欢的编程语言?">
  228.                 <input type="text" id="newOption" placeholder="输入新选项(例如:Python)">
  229.                 <div class="button-group">
  230.                     <button id="addOptionBtn">添加选项</button>
  231.                     <button id="startVoteBtn" class="hidden">开始投票</button>
  232.                 </div>
  233.             </div>
  234.             <ul id="optionsList" class="options-list">
  235.                 <!-- 选项列表将动态生成 -->
  236.             </ul>
  237.         </div>

  238.         <!-- 投票部分 -->
  239.         <div id="voteSection" class="section hidden">
  240.             <h2 id="voteTitleDisplay">投票标题</h2>
  241.             <div id="voteOptions" class="vote-options">
  242.                 <!-- 投票选项将动态生成 -->
  243.             </div>
  244.             <p id="voteMessage" class="message hidden"></p>
  245.         </div>

  246.         <!-- 结果展示部分 -->
  247.         <div id="resultsSection" class="section hidden">
  248.             <h2>投票结果</h2>
  249.             <div id="results" class="results">
  250.                 <!-- 结果将动态生成 -->
  251.             </div>
  252.         </div>

  253.         <!-- 重置按钮 -->
  254.         <div class="button-group">
  255.             <button id="resetBtn" class="reset-btn">重置投票</button>
  256.         </div>
  257.     </div>

  258.     <script>
  259.         // 全局变量:投票数据键名
  260.         const STORAGE_KEY = 'voteData';

  261.         // 初始化投票数据
  262.         let voteData = {
  263.             title: "你最喜欢的编程语言?",
  264.             options: [
  265.                 { text: "Python", votes: 0 },
  266.                 { text: "JavaScript", votes: 0 },
  267.                 { text: "Java", votes: 0 }
  268.             ],
  269.             hasVoted: false
  270.         };

  271.         // DOM 元素
  272.         const voteTitleInput = document.getElementById('voteTitle');
  273.         const newOptionInput = document.getElementById('newOption');
  274.         const addOptionBtn = document.getElementById('addOptionBtn');
  275.         const startVoteBtn = document.getElementById('startVoteBtn');
  276.         const optionsList = document.getElementById('optionsList');
  277.         const voteSection = document.getElementById('voteSection');
  278.         const voteTitleDisplay = document.getElementById('voteTitleDisplay');
  279.         const voteOptions = document.getElementById('voteOptions');
  280.         const voteMessage = document.getElementById('voteMessage');
  281.         const resultsSection = document.getElementById('resultsSection');
  282.         const results = document.getElementById('results');
  283.         const resetBtn = document.getElementById('resetBtn');

  284.         // 页面加载时初始化
  285.         document.addEventListener('DOMContentLoaded', function() {
  286.             loadVoteData();
  287.             renderCreateSection();
  288.             if (voteData.options.length >= 2) {
  289.                 startVoteBtn.classList.remove('hidden');
  290.             }
  291.         });

  292.         // 从 localStorage 加载投票数据
  293.         function loadVoteData() {
  294.             const savedData = localStorage.getItem(STORAGE_KEY);
  295.             if (savedData) {
  296.                 try {
  297.                     voteData = JSON.parse(savedData);
  298.                 } catch (e) {
  299.                     console.error('加载投票数据失败,使用默认数据');
  300.                 }
  301.             }
  302.         }

  303.         // 保存投票数据到 localStorage
  304.         function saveVoteData() {
  305.             localStorage.setItem(STORAGE_KEY, JSON.stringify(voteData));
  306.         }

  307.         // 渲染创建投票部分
  308.         function renderCreateSection() {
  309.             voteTitleInput.value = voteData.title;
  310.             optionsList.innerHTML = '';
  311.             voteData.options.forEach((option, index) => {
  312.                 const li = document.createElement('li');
  313.                 li.innerHTML = `
  314.                     <span>${option.text}</span>
  315.                     <button class="delete-btn" data-index="${index}">删除</button>
  316.                 `;
  317.                 optionsList.appendChild(li);
  318.             });

  319.             // 更新开始投票按钮状态
  320.             if (voteData.options.length >= 2) {
  321.                 startVoteBtn.classList.remove('hidden');
  322.             } else {
  323.                 startVoteBtn.classList.add('hidden');
  324.             }
  325.         }

  326.         // 渲染投票部分
  327.         function renderVoteSection() {
  328.             voteTitleDisplay.textContent = voteData.title;
  329.             voteOptions.innerHTML = '';
  330.             voteData.options.forEach((option, index) => {
  331.                 const totalVotes = getTotalVotes();
  332.                 const percentage = totalVotes > 0 ? Math.round((option.votes / totalVotes) * 100) : 0;
  333.                 const optionDiv = document.createElement('div');
  334.                 optionDiv.className = 'vote-option';
  335.                 optionDiv.dataset.index = index;
  336.                 optionDiv.innerHTML = `
  337.                     <div class="vote-header">
  338.                         <span class="option-text">${option.text}</span>
  339.                         <span class="vote-count">${option.votes} 票</span>
  340.                     </div>
  341.                     <div class="progress-bar">
  342.                         <div class="progress-fill" style="width: ${percentage}%"></div>
  343.                     </div>
  344.                 `;
  345.                 voteOptions.appendChild(optionDiv);
  346.             });

  347.             // 如果已投票,禁用投票选项
  348.             if (voteData.hasVoted) {
  349.                 document.querySelectorAll('.vote-option').forEach(opt => {
  350.                     opt.classList.add('voted');
  351.                     opt.style.cursor = 'not-allowed';
  352.                 });
  353.                 showMessage('您已经投过票了!', 'info');
  354.             } else {
  355.                 showMessage('请点击选项进行投票', 'info');
  356.             }

  357.             voteSection.classList.remove('hidden');
  358.             renderResults();
  359.         }

  360.         // 渲染结果部分
  361.         function renderResults() {
  362.             results.innerHTML = '';
  363.             const totalVotes = getTotalVotes();
  364.             voteData.options.forEach(option => {
  365.                 const percentage = totalVotes > 0 ? Math.round((option.votes / totalVotes) * 100) : 0;
  366.                 const resultItem = document.createElement('div');
  367.                 resultItem.className = 'result-item';
  368.                 resultItem.innerHTML = `
  369.                     <div class="result-info">
  370.                         <span>${option.text}</span>
  371.                         <span>${option.votes} 票 (<span class="percentage">${percentage}%</span>)</span>
  372.                     </div>
  373.                     <div class="progress-bar">
  374.                         <div class="progress-fill" style="width: ${percentage}%"></div>
  375.                     </div>
  376.                 `;
  377.                 results.appendChild(resultItem);
  378.             });
  379.             resultsSection.classList.remove('hidden');
  380.         }

  381.         // 计算总票数
  382.         function getTotalVotes() {
  383.             return voteData.options.reduce((sum, option) => sum + option.votes, 0);
  384.         }

  385.         // 显示消息
  386.         function showMessage(text, type) {
  387.             voteMessage.textContent = text;
  388.             voteMessage.className = `message ${type}`;
  389.             voteMessage.classList.remove('hidden');
  390.         }

  391.         // 隐藏消息
  392.         function hideMessage() {
  393.             voteMessage.classList.add('hidden');
  394.         }

  395.         // 事件监听:添加选项
  396.         addOptionBtn.addEventListener('click', function() {
  397.             const text = newOptionInput.value.trim();
  398.             if (text === '') {
  399.                 alert('请输入选项内容!');
  400.                 return;
  401.             }
  402.             if (voteData.options.some(opt => opt.text === text)) {
  403.                 alert('该选项已存在!');
  404.                 return;
  405.             }
  406.             voteData.options.push({ text: text, votes: 0 });
  407.             newOptionInput.value = '';
  408.             saveVoteData();
  409.             renderCreateSection();
  410.         });

  411.         // 事件监听:删除选项(使用事件委托)
  412.         optionsList.addEventListener('click', function(e) {
  413.             if (e.target.classList.contains('delete-btn')) {
  414.                 const index = parseInt(e.target.dataset.index);
  415.                 voteData.options.splice(index, 1);
  416.                 saveVoteData();
  417.                 renderCreateSection();
  418.             }
  419.         });

  420.         // 事件监听:开始投票
  421.         startVoteBtn.addEventListener('click', function() {
  422.             voteData.title = voteTitleInput.value.trim();
  423.             if (voteData.title === '') {
  424.                 alert('请输入投票标题!');
  425.                 return;
  426.             }
  427.             if (voteData.options.length < 2) {
  428.                 alert('至少需要两个选项才能开始投票!');
  429.                 return;
  430.             }
  431.             saveVoteData();
  432.             renderVoteSection();
  433.         });

  434.         // 事件监听:投票(使用事件委托)
  435.         voteOptions.addEventListener('click', function(e) {
  436.             if (voteData.hasVoted) {
  437.                 showMessage('您已经投过票了,不能重复投票!', 'error');
  438.                 return;
  439.             }
  440.             const optionDiv = e.target.closest('.vote-option');
  441.             if (!optionDiv) return;
  442.             const index = parseInt(optionDiv.dataset.index);
  443.             voteData.options[index].votes++;
  444.             voteData.hasVoted = true;
  445.             saveVoteData();
  446.             renderVoteSection();
  447.             showMessage('投票成功!感谢您的参与。', 'success');
  448.         });

  449.         // 事件监听:重置投票
  450.         resetBtn.addEventListener('click', function() {
  451.             if (confirm('确定要重置投票吗?所有数据将被清空。')) {
  452.                 voteData = {
  453.                     title: "你最喜欢的编程语言?",
  454.                     options: [
  455.                         { text: "Python", votes: 0 },
  456.                         { text: "JavaScript", votes: 0 },
  457.                         { text: "Java", votes: 0 }
  458.                     ],
  459.                     hasVoted: false
  460.                 };
  461.                 localStorage.removeItem(STORAGE_KEY);
  462.                 voteSection.classList.add('hidden');
  463.                 resultsSection.classList.add('hidden');
  464.                 hideMessage();
  465.                 renderCreateSection();
  466.             }
  467.         });

  468.         // 输入框回车键快捷添加选项
  469.         newOptionInput.addEventListener('keypress', function(e) {
  470.             if (e.key === 'Enter') {
  471.                 addOptionBtn.click();
  472.             }
  473.         });
  474.         voteTitleInput.addEventListener('keypress', function(e) {
  475.             if (e.key === 'Enter') {
  476.                 startVoteBtn.click();
  477.             }
  478.         });
  479.     </script>
  480. </body>
  481. </html>
复制代码


使用说明:
1. 将以上代码复制并保存为 vote.html 文件。
2. 在浏览器中双击打开该文件,即可使用在线投票程序。

功能说明:
- 创建投票:输入投票标题和选项,点击“添加选项”按钮增加选项,选项列表会显示并可删除。
- 开始投票:至少添加两个选项后,点击“开始投票”按钮进入投票界面。
- 投票:点击选项进行投票,系统会实时更新票数和百分比,并用进度条可视化。
- 防重复投票:同一设备只能投票一次,使用 localStorage 记录状态。
- 结果展示:投票后显示每个选项的票数和百分比进度条。
- 数据持久化:所有数据保存在 localStorage 中,刷新页面后数据保留。
- 重置投票:点击“重置投票”按钮可清空所有数据并恢复到初始状态。

界面特点:
- 采用浅灰色背景和白色卡片布局,按钮为浅蓝色圆角设计。
- 使用 Flexbox 进行响应式布局,适应不同屏幕尺寸。
- 代码完全原生,无需任何外部依赖。

如有问题,欢迎在论坛继续讨论!

以上回复来自 FishC AI 小助理,如未能正确解答您的问题,请继续追问。
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|手机版|Archiver|鱼C工作室 ( 粤ICP备18085999号-1 | 粤公网安备 44051102000585号)

GMT+8, 2026-4-10 13:08

Powered by Discuz! X3.4

© 2001-2023 Discuz! Team.

快速回复 返回顶部 返回列表