文字回應功能實作-這個系統允許讀者選擇文章中的任意文字段落進行評論,並即時顯示評論數量。(此處無法使用網頁程式碼)

更新 發佈閱讀 36 分鐘

請ChatGpt,Gmini,claude協助完成,可惜不是自架站,不然就可以嘗試將回應資料上傳伺服器了 。


這是文章標題


這是一段可以留言的文章內容。你可以選擇其中的任何句子來留言。。

這是另一段文章內容,同樣可以被選取與留言。

這是另一段文章內容,同樣可以被選取與留言。

這是另一段文章內容,同樣可以被選取與留言。

這是另一段文章內容,同樣可以被選取與留言。

這是另一段文章內容,同樣可以被選取與留言。

這是另一段文章內容,同樣可以被選取與留言。

這是另一段文章內容,同樣可以被選取與留言。

這是另一段文章內容,同樣可以被選取與留言。

這是另一段文章內容,同樣可以被選取與留言。

這是另一段文章內容,同樣可以被選取與留言。

這是另一段文章內容,同樣可以被選取與留言。

這是另一段文章內容,同樣可以被選取與留言。

這是另一段文章內容,同樣可以被選取與留言。

這是另一段文章內容,同樣可以被選取與留言。

這是另一段文章內容,同樣可以被選取與留言。

這是另一段文章內容,同樣可以被選取與留言。

這是另一段文章內容,同樣可以被選取與留言。

這是另一段文章內容,同樣可以被選取與留言。

這是另一段文章內容,同樣可以被選取與留言。

這是另一段文章內容,同樣可以被選取與留言。

這是另一段文章內容,同樣可以被選取與留言。

這是另一段文章內容,同樣可以被選取與留言。

這是另一段文章內容,同樣可以被選取與留言。

這是另一段文章內容,同樣可以被選取與留言。

這是另一段文章內容,同樣可以被選取與留言。

這是另一段文章內容,同樣可以被選取與留言。

這是另一段文章內容,同樣可以被選取與留言。

這是另一段文章內容,同樣可以被選取與留言。

這是另一段文章內容,同樣可以被選取與留言。

這是另一段文章內容,同樣可以被選取與留言。

這是另一段文章內容,同樣可以被選取與留言。

這是另一段文章內容,同樣可以被選取與留言。

這是另一段文章內容,同樣可以被選取與留言。


底下是網頁原始檔:

<meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title></title><style type="text/css">* {            margin: 0;            padding: 0;            box-sizing: border-box;        }        body {            font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'PingFang SC', 'Hiragino Sans GB', sans-serif;            line-height: 1.6;            background: #f5f5f5;            color: #333;        }        .container {            max-width: 1200px;            margin: 0 auto;            display: flex;            gap: 20px;            padding: 20px;        }        .article-section {            flex: 2;            background: white;            border-radius: 12px;            box-shadow: 0 2px 12px rgba(0,0,0,0.1);            padding: 40px;        }        .comments-section {            flex: 1;            background: white;            border-radius: 12px;            box-shadow: 0 2px 12px rgba(0,0,0,0.1);            padding: 20px;            height: fit-content;            position: sticky;            top: 20px;        }        .article-title {            font-size: 24px;            font-weight: bold;            margin-bottom: 20px;            color: #1a1a1a;        }        .article-content {            font-size: 16px;            line-height: 1.8;            color: #333;        }        .article-content p {            margin-bottom: 20px;            position: relative;        }        /* 選中文字的樣式 */        .selected-text {            background: linear-gradient(120deg, #a8e6cf 0%, #dcedc1 100%);            padding: 2px 4px;            border-radius: 4px;            position: relative;            cursor: pointer;        }        /* 評論數量標記 */        .comment-count {            display: inline-block;            background: #ff6b6b;            color: white;            font-size: 12px;            padding: 2px 6px;            border-radius: 10px;            margin-left: 5px;            font-weight: bold;            cursor: pointer;            animation: pulse 0.3s ease-in-out;        }        @keyframes pulse {            0% { transform: scale(1); }            50% { transform: scale(1.1); }            100% { transform: scale(1); }        }        /* 評論彈窗 */        .comment-popup {            position: fixed;            background: white;            border: 1px solid #e0e0e0;            border-radius: 8px;            box-shadow: 0 4px 20px rgba(0,0,0,0.15);            padding: 15px;            width: 400px;            z-index: 1000;            display: none;        }        .comment-popup textarea {            width: 100%;            height: 100px;            border: 1px solid #e0e0e0;            border-radius: 6px;            padding: 10px;            font-size: 14px;            resize: vertical;        }        .comment-popup-buttons {            display: flex;            gap: 10px;            margin-top: 10px;            justify-content: flex-end;        }        .btn {            padding: 8px 16px;            border: none;            border-radius: 6px;            cursor: pointer;            font-size: 14px;            transition: all 0.2s;        }        .btn-primary {            background: #4CAF50;            color: white;        }        .btn-primary:hover {            background: #45a049;        }        .btn-secondary {            background: #f5f5f5;            color: #666;        }        .btn-secondary:hover {            background: #e0e0e0;        }        /* 評論區域 */        .comments-header {            font-size: 16px;            font-weight: bold;            margin-bottom: 20px;            color: #1a1a1a;            border-bottom: 2px solid #f0f0f0;            padding-bottom: 10px;        }        .comment-item {            margin-bottom: 20px;            padding: 15px;            background: #f9f9f9;            border-radius: 8px;            border-left: 4px solid #4CAF50;            animation: slideIn 0.3s ease-out;        }        @keyframes slideIn {            from {                opacity: 0;                transform: translateY(20px);            }            to {                opacity: 1;                transform: translateY(0);            }        }        .comment-user {            font-weight: bold;            color: #2c3e50;            margin-bottom: 5px;        }        .comment-quote {            background: white;            padding: 8px 12px;            border-radius: 6px;            font-style: italic;            color: #666;            border-left: 3px solid #ddd;            margin-bottom: 8px;        }        .comment-text {            color: #333;            line-height: 1.5;        }        .comment-time {            font-size: 12px;            color: #999;            margin-top: 8px;        }        /* 使用者登錄區域 */        .user-login {            margin-bottom: 20px;            padding: 15px;            background: #e8f5e8;            border-radius: 8px;        }        .user-login input {            width: 100%;            padding: 8px 12px;            border: 1px solid #ddd;            border-radius: 6px;            font-size: 14px;        }        /* 選擇提示 */        .selection-hint {            position: fixed;            background: #333;            color: white;            padding: 8px 12px;            border-radius: 6px;            font-size: 12px;            z-index: 999;            display: none;            pointer-events: none;        }        /* 回應式設計 */        @media (max-width: 768px) {            .container {                flex-direction: column;                padding: 10px;            }                        .article-section {                padding: 20px;            }                        .comments-section {                position: static;            }        }</style><div class="container"><div class="article-section"><h1 class="article-title">這是文章標題</h1><div class="article-content" id="articleContent"><p>這是一段可以留言的文章內容。你可以選擇其中的任何句子來留言。。</p><p>這是另一段文章內容,同樣可以被選取與留言。</p><p>這是另一段文章內容,同樣可以被選取與留言。</p><p>這是另一段文章內容,同樣可以被選取與留言。</p><p>這是另一段文章內容,同樣可以被選取與留言。</p><p>這是另一段文章內容,同樣可以被選取與留言。</p><p>這是另一段文章內容,同樣可以被選取與留言。</p><p>這是另一段文章內容,同樣可以被選取與留言。</p><p>這是另一段文章內容,同樣可以被選取與留言。</p><p>這是另一段文章內容,同樣可以被選取與留言。</p><p>這是另一段文章內容,同樣可以被選取與留言。</p><p>這是另一段文章內容,同樣可以被選取與留言。</p><p>這是另一段文章內容,同樣可以被選取與留言。</p><p>這是另一段文章內容,同樣可以被選取與留言。</p><p>這是另一段文章內容,同樣可以被選取與留言。</p><p>這是另一段文章內容,同樣可以被選取與留言。</p><p>這是另一段文章內容,同樣可以被選取與留言。</p><p>這是另一段文章內容,同樣可以被選取與留言。</p><p>這是另一段文章內容,同樣可以被選取與留言。</p><p>這是另一段文章內容,同樣可以被選取與留言。</p><p>這是另一段文章內容,同樣可以被選取與留言。</p><p>這是另一段文章內容,同樣可以被選取與留言。</p><p>這是另一段文章內容,同樣可以被選取與留言。</p><p>這是另一段文章內容,同樣可以被選取與留言。</p><p>這是另一段文章內容,同樣可以被選取與留言。</p><p>這是另一段文章內容,同樣可以被選取與留言。</p><p>這是另一段文章內容,同樣可以被選取與留言。</p><p>這是另一段文章內容,同樣可以被選取與留言。</p><p>這是另一段文章內容,同樣可以被選取與留言。</p><p>這是另一段文章內容,同樣可以被選取與留言。</p><p>這是另一段文章內容,同樣可以被選取與留言。</p><p>這是另一段文章內容,同樣可以被選取與留言。</p><p>這是另一段文章內容,同樣可以被選取與留言。</p><p>這是另一段文章內容,同樣可以被選取與留言。</p><p>&nbsp;</p></div></div><div class="comments-section"><div class="user-login"><input id="username" placeholder="請輸入您的用戶名" type="text" value="訪客用戶" /></div><div class="comments-header">評論區 (<span id="commentCount">0</span>)</div><div id="commentsList"><!-- 評論將在這裡顯示 --></div></div></div><!-- 評論彈窗 --><div class="comment-popup" id="commentPopup"><textarea id="commentText" placeholder="寫下你的想法..."></textarea><div class="comment-popup-buttons"><button class="btn btn-secondary">取消</button><button class="btn btn-primary">發表</button></div></div><!-- 選擇提示 --><div class="selection-hint" id="selectionHint">選擇文字後點擊添加評論</div><script>let comments = [];let currentSelection = null;let commentIdCounter = 1;// 初始化window.addEventListener('DOMContentLoaded', () => {    initializeParagraphIds();    initializeTextSelection();    updateCommentCount();});// 為每段文字加上唯一 IDfunction initializeParagraphIds() {    const paragraphs = document.querySelectorAll('#articleContent p');    paragraphs.forEach((p, index) => {        p.setAttribute('data-para-id', index);    });}// 選取文字時處理function initializeTextSelection() {    const articleContent = document.getElementById('articleContent');    articleContent.addEventListener('mouseup', handleTextSelection);    articleContent.addEventListener('touchend', handleTextSelection);    document.addEventListener('click', function(e) {        if (!e.target.closest('.comment-popup') && !e.target.closest('#articleContent')) {            clearSelection();        }    });}function handleTextSelection(e) {    const selection = window.getSelection();    const selectedText = selection.toString().trim();    if (!selectedText) return;    const range = selection.getRangeAt(0);    let para = range.startContainer;    while (para && para.tagName !== 'P') {        para = para.parentNode;    }    if (!para) return;    const paraId = para.dataset.paraId;    currentSelection = { text: selectedText, paraId: paraId };    // 改成智慧浮動定位    showCommentPopupFromSelection();}function showCommentPopupFromSelection() {    const popup = document.getElementById('commentPopup');    const textarea = document.getElementById('commentText');    const width = 600;    const height = 300;    const selection = window.getSelection();    if (selection.rangeCount === 0) return;    const range = selection.getRangeAt(0);    const rect = range.getBoundingClientRect();    if (!rect) return;    // 計算理想彈窗位置    let left = rect.left ;    let top = rect.bottom ;    // 避免超出畫面邊界(右邊與下方)    if (left + width > window.innerWidth + window.scrollX) {        left = window.innerWidth + window.scrollX - width - 20;    }    if (top + height > window.innerHeight + window.scrollY) {        top = rect.top + window.scrollY - height - 10;    }    // 保底:避免超出上方與左邊    if (left < 0) left = 10;    if (top < 0) top = 10;    // 顯示彈窗    popup.style.left = left + 'px';    popup.style.top = top + 'px';    popup.style.display = 'block';    textarea.focus();}function closeCommentPopup() {    document.getElementById('commentPopup').style.display = 'none';    document.getElementById('commentText').value = '';    clearSelection();}function clearSelection() {    window.getSelection().removeAllRanges();    currentSelection = null;}function submitComment() {    const text = document.getElementById('commentText').value.trim();    const user = document.getElementById('username').value.trim() || '匿名使用者';    const { text: quote, paraId } = currentSelection;    if (!text || !quote || paraId == null) return;    const key = `${paraId}::${quote}`;    const comment = {        id: commentIdCounter++,        user: user,        quote: quote,        text: text,        time: new Date().toLocaleString('zh-CN'),        paraId: paraId,        key: key    };    comments.push(comment);    highlightTextInParagraph(paraId, quote, key);    updateCommentsDisplay();    updateCommentCount();    closeCommentPopup();}function highlightTextInParagraph(paraId, quoteText, key) {    const p = document.querySelector(`p[data-para-id="${paraId}"]`);    if (!p) return;    const html = p.innerHTML;    if (html.includes(`data-highlight="${key}"`)) {        const countSpan = p.querySelector(`.selected-text[data-highlight="${key}"] .comment-count`);        if (countSpan) {            const count = parseInt(countSpan.textContent);            countSpan.textContent = count + 1;        }        return;    }    const safeQuote = quoteText.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');    const pattern = new RegExp(`(${safeQuote})`);    const replaced = html.replace(pattern, `<span class="selected-text" data-highlight="${key}">$1 <span class="comment-count">1</span></span>`);    p.innerHTML = replaced;    const span = p.querySelector(`.selected-text[data-highlight="${key}"]`);    if (span) {        span.onclick = () => scrollToComment(commentIdCounter - 1);    }}function updateCommentsDisplay() {    const list = document.getElementById('commentsList');    list.innerHTML = '';    comments.slice().reverse().forEach(comment => {        const item = document.createElement('div');        item.className = 'comment-item';        item.setAttribute('data-comment-id', comment.id);        item.innerHTML = `            <div class="comment-user">${comment.user}</div>            <div class="comment-quote">"${comment.quote}"</div>            <div class="comment-text">${comment.text}</div>            <div class="comment-time">${comment.time}</div>        `;        list.appendChild(item);    });}function scrollToComment(commentId) {    const el = document.querySelector(`.comment-item[data-comment-id="${commentId}"]`);    if (el) {        el.scrollIntoView({ behavior: 'smooth', block: 'center' });        el.style.animation = 'pulse 0.6s ease-in-out';        setTimeout(() => el.style.animation = '', 600);    }}function updateCommentCount() {    document.getElementById('commentCount').textContent = comments.length;}// 快捷鍵支援document.querySelector('.btn-primary').addEventListener('click', submitComment);document.querySelector('.btn-secondary').addEventListener('click', closeCommentPopup);document.addEventListener('keydown', function(e) {    if (e.key === 'Escape') closeCommentPopup();    if (e.ctrlKey && e.key === 'Enter' && document.getElementById('commentPopup').style.display === 'block') submitComment();});</script>


評論區 (0)

取消發表

選擇文字後點擊添加評論

留言
avatar-img
銘記星辰之下的沙龍
10會員
470內容數
2025/06/03
心重行重大於禮,心存邪念亦無光,若行端正道永昌。
2025/06/03
心重行重大於禮,心存邪念亦無光,若行端正道永昌。
2025/06/02
排列組合與機率計算(二十三)機率由排列組合起步,發展至製程管制。平均數,變異數,樣本標準差,常態分布,中心線與控制限,能力指標,Z值與信賴區間。
2025/06/02
排列組合與機率計算(二十三)機率由排列組合起步,發展至製程管制。平均數,變異數,樣本標準差,常態分布,中心線與控制限,能力指標,Z值與信賴區間。
2025/06/01
什麼是說話的語氣?背後可能有什麼 想法或感覺?
2025/06/01
什麼是說話的語氣?背後可能有什麼 想法或感覺?
看更多
你可能也想看
Thumbnail
賽勒布倫尼科夫以流亡處境回望蘇聯電影導演帕拉贊諾夫的舞台作品,以十段寓言式殘篇,重新拼貼記憶、暴力與美學,並將審查、政治犯、戰爭陰影與「形式即政治」的劇場傳統推到台前。本文聚焦於《傳奇:帕拉贊諾夫的十段殘篇》的舞台美術、音樂與多重扮演策略,嘗試解析極權底下不可言說之事,將如何成為可被觀看的公共發聲。
Thumbnail
賽勒布倫尼科夫以流亡處境回望蘇聯電影導演帕拉贊諾夫的舞台作品,以十段寓言式殘篇,重新拼貼記憶、暴力與美學,並將審查、政治犯、戰爭陰影與「形式即政治」的劇場傳統推到台前。本文聚焦於《傳奇:帕拉贊諾夫的十段殘篇》的舞台美術、音樂與多重扮演策略,嘗試解析極權底下不可言說之事,將如何成為可被觀看的公共發聲。
Thumbnail
柏林劇團在 2026 北藝嚴選,再次帶來由布萊希特改編的經典劇目《三便士歌劇》(The Threepenny Opera),導演巴里・柯斯基以舞台結構與舞台調度,重新向「疏離」進行提問。本文將從觀眾慾望作為戲劇內核,藉由沉浸與疏離的辯證,解析此作如何再次照見觀眾自身的位置。
Thumbnail
柏林劇團在 2026 北藝嚴選,再次帶來由布萊希特改編的經典劇目《三便士歌劇》(The Threepenny Opera),導演巴里・柯斯基以舞台結構與舞台調度,重新向「疏離」進行提問。本文將從觀眾慾望作為戲劇內核,藉由沉浸與疏離的辯證,解析此作如何再次照見觀眾自身的位置。
Thumbnail
本文深入解析臺灣劇團「晃晃跨幅町」對易卜生經典劇作《海妲.蓋柏樂》的詮釋,從劇本歷史、聲響與舞臺設計,到演員的主體創作方法,探討此版本如何讓經典劇作在當代劇場語境下煥發新生,滿足現代觀眾的觀看慾望。
Thumbnail
本文深入解析臺灣劇團「晃晃跨幅町」對易卜生經典劇作《海妲.蓋柏樂》的詮釋,從劇本歷史、聲響與舞臺設計,到演員的主體創作方法,探討此版本如何讓經典劇作在當代劇場語境下煥發新生,滿足現代觀眾的觀看慾望。
Thumbnail
《轉轉生》為奈及利亞編舞家庫德斯.奧尼奎庫與 Q 舞團創作的當代舞蹈作品,融合舞蹈、音樂、時尚和視覺藝術,透過身體、服裝與群舞結構,回應殖民歷史、城市經驗與祖靈記憶的交錯。本文將從服裝設計、身體語彙與「輪迴」的「誕生—死亡—重生」結構出發,分析《轉轉生》如何以當代目光,形塑去殖民視角的奈及利亞歷史。
Thumbnail
《轉轉生》為奈及利亞編舞家庫德斯.奧尼奎庫與 Q 舞團創作的當代舞蹈作品,融合舞蹈、音樂、時尚和視覺藝術,透過身體、服裝與群舞結構,回應殖民歷史、城市經驗與祖靈記憶的交錯。本文將從服裝設計、身體語彙與「輪迴」的「誕生—死亡—重生」結構出發,分析《轉轉生》如何以當代目光,形塑去殖民視角的奈及利亞歷史。
Thumbnail
對於文字工作者來說,有合適發揮的平台就試試,尤其是對於日更的創作者來說,可以有更多曝光度的地方都值得努力看看。
Thumbnail
對於文字工作者來說,有合適發揮的平台就試試,尤其是對於日更的創作者來說,可以有更多曝光度的地方都值得努力看看。
Thumbnail
【一天一千字,進化每一次】第七週回覆心得與感謝文 (上)
Thumbnail
【一天一千字,進化每一次】第七週回覆心得與感謝文 (上)
Thumbnail
……你、你要看就看啦……我不管了……
Thumbnail
……你、你要看就看啦……我不管了……
追蹤感興趣的內容從 Google News 追蹤更多 vocus 的最新精選內容追蹤 Google News