第一次嘗試做個人網頁 是高中一年級的電算作業 那個時候網路並不發達 除了家裡的網路是向中央大學申請的免費撥接帳號 整個社會的網路發達程度都還是很低 上課用來寫網頁的 不是會自己亂加語法的frontpage 也不是我一直想要學的dreamweaver 而是windows內建的notepad 一大堆用<>夾起來的文字語法 沒有什麼"所見即所得" 連放個背景圖都要試好幾遍 字的顏色還要一邊存檔一邊修改試色碼 放張圖片還得考慮大小縮放還有容量壓縮 連指向路徑都要一個字母一個字母打出來 學期末的作業是作出一個有兩張圖三個超連結四種字體的網頁 現在學網路的人可能會對這個學期作業嗤之以鼻 不過在當時可是花費了大半個學期 在之間掙扎 最後根本就是大家的照片都是老師用當時超難用的數位相機照兩張 連到學校教育部或是同學的網頁連來連去就交了 一堆"XX的烘焙雞"彷彿每個人都是在做烹飪網頁似的 大學的計概又要再做一網頁 這個課程已經進步到勉強算是所見即所得的frontpage 不過一如微軟其他office軟體一樣 總是會幫你加一些有的沒的語法 讓沒有用過html標籤寫過網頁的同學百思不得其解 用frontpage的壞處當然不只這個 最大的問題是套用內建的格式作起來 大家的網頁看起來都差不多 為了和其他人的網頁有所區別 這時候開始有人使用photoimpact和photoshop 沒有美術細胞的我只好上網去查一些javascript的用法 使用網路的過程中 一直都在練習怎麼做網頁 不過實在是很懶得去學新的東西 所以自己的網頁不管怎麼做總是脫不了簡陋 其實網頁只是一個表現自己的方式 網誌真的很方便喔... 又是一篇虎頭蛇尾的文章 我只是想說... 網誌是簡化版的網頁 這句話真有道理</font></a></p> </font> </font> </font> </p> </p> </p> </span> </span> </span> </table><!-- more --> </div> <!-- /.article-content-inner --> <div class="tag-container-parent"> <div class="tag-container article-keyword" data-version="a"> </div> </div> <!-- /.tag-container-parent --> <div class="author-profile"> <div class="author-profile__header">創作者介紹</div> <div class="author-profile__main" id="mixpanel-author-box"> <a> <img class="author-profile__avatar" src="https://s3.1px.tw/blog/common/avatar/blog_cover_dark.jpg" alt="創作者 悶壞的下午茶 的頭像" loading="lazy" /> </a> <div class="author-profile__content"> <a href="https://www.pixnet.net/pcard/real" class="author-profile__name">Real</a> <p class="author-profile__info">悶壞的下午茶</p> </div> <div class="author-profile__subscribe hoverable"> <button data-follow-state="關注" class="subscribe-btn member"></button> </div> </div> </div> <!-- /.author-profile --> </div> <!-- /.article-content --> <p class="author"> Real 發表在 <a href="https://www.pixnet.net">痞客邦</a> <a href="#comments">留言</a>(2) <span class="author-views">人氣( <span id="BlogArticleCount" data-stats="single" data-post-id="1007641610"> 19 </span> ) </span> </p> <!-- /.author --> <div id="pixnet-ad-content-left-right-wrapper"> <div class="left"></div> <div class="right"></div> </div> <!-- /#pixnet-ad-content-left-right-wrapper --> <div class="article-footer"> <ul class="refer"> <li> 個人分類: <a href="https://real.pixnet.net/blog/categories/1000561337">日記手寫才有感覺</a> </li> </ul> <div class="back-to-top"> <a href="#top" title="back to the top of the page">▲top</a> </div> <div id="post-comment" class="comment-container" x-data="commentComponent({postId: '1007641610', blog_id: '463439'})"> <div class="post-comment__header"> <span x-text="meta.totalCount + ' 則留言'"></span> </div> <div class="post-comment__body"> <ol class="post-comment__list"> <template x-for="comment in comments" :key="comment.id"> <li class="post-comment__item"> <div class="comment-card"> <a href="#" class="comment-card__avatar-link" :aria-label="'查看 ' + comment.commenter.display_name + ' 的個人頁'"> <img class="comment-card__avatar" :src="comment.commenter.avatar" :alt="comment.commenter.display_name" loading="lazy" /> </a> <div class="comment-card__main"> <div class="comment-card__bubble"> <div class="comment-card__author-row"> <a href="#" class="comment-card__author" x-text="comment.commenter.display_name"></a> <span class="comment-card__badge comment-card__badge--author" x-show="comment.commenter.is_author">作者</span> </div> <div class="comment-card__content" x-html="comment.content"></div> </div> <!-- /.comment-card__bubble --> <div class="comment-card__meta"> <time class="comment-card__time" :datetime="comment.datetime" x-text="comment.human_time"></time> <a href="#" class="comment-card__action" x-show="isOwner()" @click.prevent="toggleReply(comment.id)">回覆</a> <a href="#" class="comment-card__action" x-show="isOwner()" :class="{ 'comment-card__action--active': comment.visibility == 1 }" @click.prevent="changeCommentVisibility(comment.id, 'show')">顯示</a> <a href="#" class="comment-card__action" x-show="isOwner()" :class="{ 'comment-card__action--active': comment.visibility == 2 }" @click.prevent="changeCommentVisibility(comment.id, 'hide')">隱藏</a> <a href="#" class="comment-card__action" x-show="isOwner()" @click.prevent="deleteComment(comment.id)">刪除</a> </div> <!-- /.comment-card__meta --> <div class="comment-card__replies"> <ol class="reply-list"> <template x-for="reply in comment.replies"> <li class="reply-list__item"> <div class="comment-card comment-card--reply" :class="{'comment-card--hidden': reply.visibility == 2 && isOwner()}"> <a href="#" class="comment-card__avatar-link" aria-label="查看 Eric 的個人頁"> <img class="comment-card__avatar" :src="reply.replyer.avatar" :alt="reply.replyer.display_name" loading="lazy" /> </a> <div class="comment-card__main"> <div class="comment-card__bubble"> <div class="comment-card__author-row"> <a :href="reply.replyer.card_url" class="comment-card__author" x-text="reply.replyer.display_name"></a> <span class="comment-card__badge comment-card__badge--author" x-show="reply.replyer.is_author">作者</span> </div> <div class="comment-card__content" x-html="reply.content"></div> </div> <div class="comment-card__meta"> <time class="comment-card__time" :datetime="reply.datetime" x-text="reply.human_time"></time> <a href="#" class="comment-card__action" x-show="isOwner()" :class="{ 'comment-card__action--active': reply.visibility == 1 }" @click.prevent="changeReplyVisibility(comment.id, reply.id, 'show')">顯示</a> <a href="#" class="comment-card__action" x-show="isOwner()" :class="{ 'comment-card__action--active': reply.visibility == 2 }" @click.prevent="changeReplyVisibility(comment.id, reply.id, 'hide')">隱藏</a> <a href="#" class="comment-card__action" x-show="isOwner()" @click.prevent="deleteReply(comment.id, reply.id)">刪除</a> </div> <!-- /.comment-card__meta --> </div> </div> </li> </template> </ol> </div> <!-- /.comment-card__replies --> <div class="comment-card__reply-editor" x-show="replyingTo === comment.id && isOwner()"> <div class="reply-editor"> <div class="reply-editor__avatar"> <img src="https://i.pravatar.cc/48?img=5"> </div> <form class="reply-editor__form"> <div class="reply-editor__input-wrap"> <textarea class="reply-editor__textarea" placeholder="寫下你的回覆..." x-model="replyDraft[comment.id].content"></textarea> </div> <div class="reply-editor__footer"> <div class="reply-editor__visibility"> <label> <input type="radio" name="reply_visibility" value="1" x-model="replyDraft[comment.id].visibility" checked> 公開回覆 </label> <label> <input type="radio" name="reply_visibility" value="2" x-model="replyDraft[comment.id].visibility"> 私密回覆 </label> </div> <div class="reply-editor__actions"> <button type="button" class="reply-editor__cancel" @click="replyingTo = null">取消</button> <button type="submit" class="reply-editor__submit" @click.prevent="submitReply(comment.id)">回覆</button> </div> </div> </form> </div> </div> <!-- /.comment-card__reply-editor --> </div> <!-- /.comment-card__main --> </div> </li> </template> <template x-if="comments.length === 0"> <li class="post-comment__item" style="text-align: center; color: #888; padding: 2rem 0;"> 沒有留言,快來搶沙發吧! </li> </template> </ol> <button class="btn-more" x-show="meta.page < meta.pageCount" @click="loadMore">載入更多</button> </div> <!-- /.post-comment__body --> <div class="post-comment__footer"> <div class="comment-editor" x-show="isLoggedIn"> <a href="#" class="comment-editor__avatar-link" aria-label="我的個人頁"> <img class="comment-editor__avatar" :src="user?.avatar" :alt="user?.display_name" loading="lazy" /> </a> <form class="comment-editor__form" action="" method="post"> <label for="comment-message" class="comment-editor__label" x-text="'以 ' + user?.display_name + ' 身份發表留言'"></label> <div class="comment-editor__input-wrap"> <textarea id="comment-message" name="comment" class="comment-editor__textarea" rows="3" placeholder="寫下你的留言..." x-model="newComment.content"></textarea> </div> <div class="comment-editor__footer"> <div class="comment-editor__visibility"> <label class="comment-editor__visibility-option"> <input type="radio" name="visibility" value="1" x-model="newComment.visibility" checked> <span>公開留言</span> </label> <label class="comment-editor__visibility-option"> <input type="radio" name="visibility" value="2" x-model="newComment.visibility"> <span>私密留言</span> </label> </div> <div class="comment-editor__actions"> <button type="submit" class="comment-editor__button comment-editor__button--primary" @click.prevent="submitComment()"> 發佈留言 </button> </div> </div> </form> </div> <div x-show="!isLoggedIn" style="text-align: center; padding: 2rem 0;"> <p style="color: #555;">請先 <a :href="loginUrl" style="color: #007bff; text-decoration: underline;">登入</a> 以發表留言。</p> </div> </div> <!-- /.post-comment__footer --> </div> <script type="text/javascript"> function commentComponent({ postId, blog_id }) { return { postId, blog_id, /* ------------------------- state -------------------------- */ user: null, isLoggedIn: false, isOwner() { return this.isLoggedIn && this.user.is_blogger && this.user.blog.id === this.blog_id }, comments: [], meta: { page: 1, pageSize: 10, pageCount: 1, totalCount: 0 }, loading: false, replyingTo: null, newComment: { content: "", visibility: 1 }, replyDraft: {}, guest: { name: "", contact: "" }, get loginUrl() { return '/auth/authorize?redirect_uri=' + encodeURIComponent(location.href) }, /* ------------------------- init -------------------------- */ async init() { await this.fetchUser() await this.fetchComments() }, /* ------------------------- user -------------------------- */ async fetchUser() { try { const res = await fetch("/auth/me") if (res.status === 401) { this.isLoggedIn = false return } const user = await res.json() this.user = user this.isLoggedIn = true } catch (e) { console.error("auth error", e) } }, /* ------------------------- comments -------------------------- */ async fetchComments(page = 1) { this.loading = true const res = await fetch( `/blog/get-comments?postId=${this.postId}&page=${page}` ) const json = await res.json() this.comments = json.data this.meta = json.meta this.comments.forEach(comment => { if (!this.replyDraft[comment.id]) { this.replyDraft[comment.id] = { content: "", visibility: "1" } } }) this.loading = false }, async loadMore() { if (this.meta.page >= this.meta.pageCount) return const nextPage = this.meta.page + 1 const res = await fetch( `/blog/get-comments?postId=${this.postId}&page=${nextPage}` ) const json = await res.json() this.comments = [...this.comments, ...json.data] this.meta = json.meta }, /* ------------------------- reply editor -------------------------- */ toggleReply(commentId) { if (this.replyingTo === commentId) { this.replyingTo = null } else { this.replyingTo = commentId if (!this.replyDraft[commentId]) { this.replyDraft[commentId] = { content: "", visibility: "public" } } } }, /* ------------------------- submit comment -------------------------- */ async submitComment() { if (!this.newComment.content.trim()) return const payload = { postId: this.postId, content: this.newComment.content, visibility: this.newComment.visibility, commenter: this.isLoggedIn ? this.user.display_name : this.guest.name, contact: this.isLoggedIn ? null : this.guest.contact } const res = await fetch("/blog/post-comment", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify(payload) }) if (!res.ok) { const errorData = await res.json() alert(errorData.message || "留言失敗,請稍後再試") return } const comment = await res.json() this.comments.push(comment) this.newComment.content = "" }, /* ------------------------- submit reply -------------------------- */ async submitReply(commentId) { if (!this.isOwner()) return const draft = this.replyDraft[commentId] if (!draft || !draft.content.trim()) return const payload = { commentId: commentId, content: draft.content, visibility: draft.visibility } try { const res = await fetch("/blog/post-reply", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify(payload) }) if (!res.ok) { const errorData = await res.json() alert(errorData.message || "回覆失敗,請稍後再試") return } const reply = await res.json(); const comment = this.comments.find(c => c.id === commentId) if (!comment.replies) { comment.replies = [] } comment.replies.push(reply) draft.content = "" this.replyingTo = null } catch (e) { console.error("reply error", e) } }, async changeCommentVisibility(commentId, visibility) { try { const res = await fetch("/blog/comments/visibility", { method: "PATCH", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ commentId, visibility: visibility == 'show' ? 1 : 2}) }) const data = await res.json() if (!res.ok) { alert(data.message || "操作失敗") return } const comment = this.comments.find(c => c.id === commentId) if (comment) { comment.visibility = visibility == 'show' ? 1 : 2; } } catch (e) { alert("系統錯誤,請稍後再試") console.error("show comment error", e) } }, async deleteComment(commentId) { if (!confirm("確定要刪除此留言嗎?")) return try { const res = await fetch(`/blog/comments/${commentId}`, { method: "DELETE" }) const data = await res.json() if (!res.ok) { alert(data.message || "操作失敗") return } this.comments = this.comments.filter(c => c.id !== commentId) } catch (e) { console.error("delete comment error", e) } }, async changeReplyVisibility(commentId, replyId, visibility) { try { const res = await fetch("/blog/replies/visibility", { method: "PATCH", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ commentId, replyId, visibility: visibility == 'show' ? 1 : 2 }) }) const data = await res.json() if (!res.ok) { alert(data.message || "操作失敗") return } const comment = this.comments.find(c => c.id === commentId) const reply = comment.replies.find(r => r.id === replyId) if (reply) { reply.visibility = visibility == 'show' ? 1 : 2; } } catch (e) { console.error("change reply visibility error", e) } }, async deleteReply(commentId, replyId) { if (!confirm("確定要刪除此回覆嗎?")) return try { const res = await fetch(`/blog/comments/${commentId}/replies/${replyId}`, { method: "DELETE" }) const data = await res.json() if (!res.ok) { alert(data.message || "操作失敗") return } const comment = this.comments.find(c => c.id === commentId) comment.replies = comment.replies.filter(r => r.id !== replyId) } catch (e) { console.error("delete reply error", e) } }, /* ------------------------- guest avatar -------------------------- */ guestAvatar() { const name = this.guest.name || "Guest" return `https://ui-avatars.com/api/?name=${encodeURIComponent(name)}` } } } </script> <div id="pixnet-ad-after-footer"></div> </div> <!-- /.article-footer --> </div> </div> </div> </div> </div> <div id="links"> <div id="sidebar__inner"> <div id="links-row-1"> <div class="hslice box" data-identifier="cus591618" id="box591618"> <h4 class="box-title entry-title"> </h4> <div class="box-text entry-content"> </div> </div> <div class="hslice box" data-identifier="pixLatestArticle" id="latest-article"> <h4 class="box-title entry-title"> 近期文章 </h4> <div class="box-text entry-content"> <ul id="last-article-box"> </ul> </div> <script> (function () { async function loadLatestArticle() { const box = document.querySelector('.box[data-identifier="pixLatestArticle"]'); if (!box) return; const ul = box.querySelector("#last-article-box"); if (!ul) return; try { const res = await fetch("/blog/get-widget-data?name=pixLatestArticle", { method: "GET", headers: { "Accept": "application/json" } }); const json = await res.json(); if (json.code !== 0 || !Array.isArray(json.data)) return; const data = json.data; const fragment = document.createDocumentFragment(); data.forEach(item => { const li = document.createElement("li"); const a = document.createElement("a"); a.href = item.url; a.textContent = item.title; li.appendChild(a); fragment.appendChild(li); }); ul.appendChild(fragment); } catch (err) { console.error("pixLatestArticle load failed", err); } } if (document.readyState === "loading") { document.addEventListener("DOMContentLoaded", loadLatestArticle); } else { loadLatestArticle(); } })(); </script> </div> <div class="hslice box" data-identifier="pixLatestComment" id="last-comment"> <h4 class="box-title entry-title"> 最新迴響 </h4> <div class="box-text entry-content"> <div class="box-more"></div> <ul id="last-comment-box"> </ul> </div> <script> (function () { function truncate(str, len = 30) { if (!str) return ""; return str.length > len ? str.slice(0, len) + "..." : str; } async function loadLatestComment() { const box = document.querySelector('.box[data-identifier="pixLatestComment"]'); if (!box) return; const ul = box.querySelector("#last-comment-box"); if (!ul) return; if (ul.dataset.loaded) return; ul.dataset.loaded = "1"; try { const res = await fetch("/blog/get-widget-data?name=pixLatestComment"); const json = await res.json(); if (json.code !== 0 || !Array.isArray(json.data)) return; const fragment = document.createDocumentFragment(); json.data.forEach(item => { const li = document.createElement("li"); const a = document.createElement("a"); a.href = item.url; const title = truncate(item.post_title, 25); a.textContent = `[${item.time}] ${item.commenter} 於文章「${title}」`; li.appendChild(a); if (item.visibility === "public") { li.appendChild(document.createTextNode("留言:")); const br = document.createElement("br"); li.appendChild(br); li.appendChild(document.createTextNode(item.content)); } else { li.appendChild( document.createTextNode("發表了一則私密留言") ); } fragment.appendChild(li); }); ul.appendChild(fragment); } catch (err) { console.error("pixLatestComment load failed", err); } } if (document.readyState === "loading") { document.addEventListener("DOMContentLoaded", loadLatestComment); } else { loadLatestComment(); } })(); </script> </div> </div> <div id="links-row-2"> <div id="user-info" class="hslice box"> <h4 class="box-title entry-title">個人頭像</h4> <div class="box-text entry-content"> <a class="user-img" href="#"> <img src="https://s3.1px.tw/blog/common/avatar/blog_cover_dark.jpg" alt="個人頭像" loading="lazy" style="width: 90px; height: 90px;" /> </a> <div class="user-action hoverable"> <button data-follow-state="關注" class="subscribe-btn member" ></button> </div> <dl> <dt>暱稱:</dt> <dd>Real</dd> <dt>分類:</dt> <dd> <a href="#">不設分類</a> </dd> <dt>好友:</dt> <dd> 累積中 <!-- 共75位{" "} <a href="#" id="user-info-open-friends-iframe"> (看全部) </a> --> </dd> <dt>地區:</dt> <dd> </dd> </dl> </div> </div> <div class="hslice box" data-identifier="pixCategory" id="category"> <h4 class="box-title entry-title"> 文章分類 </h4> <div class="box-text entry-content"> <div class="box-more"></div> </div> <script type="text/javascript"> (function () { function formatNumber(num) { return new Intl.NumberFormat().format(num || 0); } function renderFolder(item) { const wrapper = document.createElement("div"); wrapper.className = "inner-box"; const h6 = document.createElement("h6"); h6.style.cursor = "pointer"; const img = document.createElement("img"); img.src = "//s.pixfs.net/blog/images/choc/plus.gif"; img.width = 11; img.height = 11; img.alt = "toggle"; const ul = document.createElement("ul"); ul.className = "category-" + item.id; ul.style.display = "none"; h6.appendChild(img); h6.appendChild(document.createTextNode(" " + item.name + " (" + (item.children?.length || 0) + ")")); h6.addEventListener("click", function () { const isHidden = ul.style.display === "none"; ul.style.display = isHidden ? "block" : "none"; img.src = isHidden ? "//s.pixfs.net/blog/images/choc/minus.gif" : "//s.pixfs.net/blog/images/choc/plus.gif"; }); (item.children || []).forEach(child => { const li = document.createElement("li"); const a = document.createElement("a"); a.href = child.url; a.textContent = child.name + " (" + formatNumber(child.post_count) + ")"; li.appendChild(a); ul.appendChild(li); }); wrapper.appendChild(h6); wrapper.appendChild(ul); return wrapper; } function renderCategoryList(data) { const ul = document.createElement("ul"); data .filter(item => item.type === "category") .forEach(item => { const li = document.createElement("li"); const a = document.createElement("a"); a.href = item.url; a.textContent = item.name + " (" + formatNumber(item.post_count) + ")"; li.appendChild(a); ul.appendChild(li); }); return ul; } async function loadPixCategory() { const box = document.querySelector('.box[data-identifier="pixCategory"]'); if (!box) return; const content = box.querySelector(".box-text.entry-content"); try { const res = await fetch("/blog/get-widget-data?name=pixCategory"); const json = await res.json(); if (json.code !== 0) return; const data = json.data; data.forEach(item => { if (item.type === "folder") { content.appendChild(renderFolder(item)); } }); const categoryList = renderCategoryList(data); content.appendChild(categoryList); } catch (err) { console.error("pixCategory load failed", err); } } if (document.readyState === "loading") { document.addEventListener("DOMContentLoaded", loadPixCategory); } else { loadPixCategory(); } })(); </script> </div> <div class="hslice box" data-identifier="pixHits" id="counter"> <h4 class="box-title entry-title">參觀人氣</h4> <div class="box-text entry-content"> <ul> <li>本日人氣:<span id="blog_hit_daily"></span></li> <li>累積人氣:<span id="blog_hit_total"></span></li> </ul> </div> <script> (function () { async function loadPixHits() { const box = document.querySelector("#counter"); if (!box) return; const dailyEl = box.querySelector("#blog_hit_daily"); const totalEl = box.querySelector("#blog_hit_total"); if (!dailyEl || !totalEl) return; // 避免重複載入 if (box.dataset.loaded) return; box.dataset.loaded = "1"; try { const res = await fetch("/blog/get-widget-data?name=pixHits", { method: "GET", headers: { "Accept": "application/json" } }); const json = await res.json(); if (json.code !== 0 || !json.data) return; const data = json.data; dailyEl.textContent = data.views_today ?? "0"; totalEl.textContent = data.views_total ?? "0"; } catch (err) { console.error("pixHits load failed", err); } } if (document.readyState === "loading") { document.addEventListener("DOMContentLoaded", loadPixHits); } else { loadPixHits(); } })(); </script> </div> <div id="sticky-sidebar-ad"></div> </div> </div> </div> </div> <div id="footer"> </div> <img src="/api/track/pv?postId=1007641610" alt="Blog Stats" width="1" height="1" style="display:none;" /> <script type="text/javascript" async src="https://static.1px.tw/blog/v1p2/js/stats.min.js?v=1776369544"></script> </div> <div id="extradiv11"></div> <div id="extradiv10"></div> <div id="extradiv9"></div> <div id="extradiv8"></div> </div> <div id="extradiv7"></div> <div id="extradiv6"></div> <div id="extradiv5"></div> <div id="extradiv4"></div> </div> <div id="extradiv3"></div> <div id="extradiv2"></div> <div id="extradiv1"></div> <div id="extradiv0"></div> </div> </div> <!-- Google Tag Manager (noscript) --> <noscript><iframe src="https://www.googletagmanager.com/ns.html?id=GTM-TRLQMPKX" height="0" width="0" style="display:none;visibility:hidden"></iframe></noscript> <!-- End Google Tag Manager (noscript) --> <!-- Pixnet SDK --> <script type="text/javascript"> document.addEventListener("DOMContentLoaded", function () { // datalayer push event window.dataLayer = window.dataLayer || []; window.dataLayer.push({ 'event': 'hydration_complete' }) }); </script> <!-- End Pixnet SDK --> <div x-data="adultWarning()" x-init="init()" x-show="visible" x-cloak class="aw-overlay" :class="{ 'mobile': isMobile }" > <div class="aw-modal"> <div class="aw-icon"> ⚠️ </div> <h2 class="aw-title">成人內容提醒</h2> <p class="aw-desc"> 本部落格內容僅限年滿十八歲者瀏覽。<br> 若您未滿十八歲,請立即離開。 </p> <p class="aw-sub"> 已滿十八歲者,亦請勿將內容提供給未成年人士。 </p> <div class="aw-actions"> <button class="aw-btn primary" @click="accept()">我已滿18歲</button> <button class="aw-btn secondary" @click="decline()">離開</button> </div> </div> </div> <script> document.addEventListener('alpine:init', () => { Alpine.data('adultWarning', () => ({ visible: false, isMobile: false, storageKey: 'adult_warning_accepted_at', init() { this.isMobile = window.innerWidth < 768; if (!window.PIXNET?.options?.AdultWarning) return; const ts = localStorage.getItem(this.storageKey); if (ts && Date.now() - parseInt(ts) < 4 * 60 * 60 * 1000) return; this.visible = true; // 🔒 防止背景滾動 document.body.classList.add('modal-open'); }, accept() { localStorage.setItem(this.storageKey, Date.now().toString()); this.close(); }, decline() { window.location.href = 'https://www.pixnet.net/'; // 或其他安全的網站 }, close() { this.visible = false; document.body.classList.remove('modal-open'); } })) }) </script> <!-- end of adult warning --> </body> </html>