
原本想把軟體上傳到第三方平台,讓大家直接透過網址使用,但怕流量超過產生費用,加上懶得管理維護平台,因此改採教學方式,方便有需要的人使用。
【版本功能,初版】2025/7/14
1. 斷線或關閉後會自動保存內容,下次打開時會自動載入最後編輯內容
2. 首行可自由縮排
3. 可自由增加或減少上下行距
4. 字數統計功能(不含標點符號與空白)
5. 一鍵排版:自動設定首行縮排兩個全形空格,段落行距空一行
6. 支援複製純文字及 HTML 格式內容
7. 可儲存及開啟文字檔案
8. 文字靠左、置中、靠右,可自由切換
9. 粗體、底線、刪除線等文字樣式快捷按鈕
10. 字體大小調整大小
11. 文字搜尋功能
【初版修訂】2025/7/14
新增 一鍵文字併攏功能
【圖為最新版本的版面】

首先,在電腦桌面新增一個「文字文件」。
然後,將本篇最下方提供的程式碼完整複製,貼到這個文字文件裡。 接著點選「檔案」→「另存新檔」,檔名請輸入:index.html
如下圖:存檔類型請選擇「所有檔案」,右下角的編碼選擇「UTF-8」,再按下「儲存」。 完成後,桌面上會出現一個帶有Google圖示的檔案。 點兩下打開它,就能開始使用這個工具囉!假如沒出現Google圖示,代表沒成功。

【複製下方程式碼】
使用本工具所產生的問題,製作方概不負責,也代表您同意,請自行審慎判斷與使用。
<!DOCTYPE html>
<html lang="zh-Hant">
<head>
<meta charset="UTF-8" />
<title>寫作方便排版工具</title>
<style>
body {
background-color: #fff0f5;
color: black;
font-family: "標楷體", "微軟正黑體", Arial, sans-serif;
padding: 20px;
margin: 0;
position: relative;
min-height: 100vh;
}
.disclaimer {
background-color: red;
color: white;
font-size: 18px;
font-weight: bold;
text-align: center;
padding: 15px 10px;
border-radius: 6px;
margin-bottom: 10px;
user-select: none;
}
.search-bar {
text-align: center;
margin-bottom: 20px;
}
.search-bar input {
font-size: 16px;
padding: 6px 10px;
width: 300px;
border-radius: 4px;
border: 1px solid #ccc;
}
.title {
text-align: center;
font-weight: bold;
font-family: "華文行楷", "華文琥珀", "標楷體", serif;
font-size: 44px;
margin-bottom: 6px; /* 主標題和副標題間距 */
user-select: none;
color: #663300;
}
@keyframes rainbowFlash {
0% { color: #e60000; }
14% { color: #ff8c00; }
28% { color: #ffd700; }
42% { color: #008000; }
57% { color: #00bfff; }
71% { color: #4b0082; }
85% { color: #8b00ff; }
100% { color: #e60000; }
}
.title .digit {
display: inline-block;
font-weight: bold;
margin: 0 2px;
animation: rainbowFlash 6s linear infinite;
font-size: 56px;
}
.title .digit:nth-child(2),
.title .digit:nth-child(4),
.title .digit:nth-child(6) {
font-size: 48px;
}
.title .digit:nth-child(3) {
font-size: 44px;
}
.title .text {
font-family: "華文行楷", "華文琥珀", "標楷體", serif;
font-size: 34px;
vertical-align: middle;
margin-left: 12px;
font-weight: normal;
color: #663300;
user-select: none;
}
/* 新增主標題下方版本說明 */
.version-line {
text-align: center;
font-family: "華文行楷", "微軟正黑體", Arial, sans-serif;
font-size: 16px;
color: #6b4c3b;
margin-bottom: 20px;
user-select: none;
font-weight: normal;
}
.controls {
text-align: center;
margin-bottom: 15px;
position: relative;
}
button {
font-size: 15px;
margin: 5px 6px;
padding: 6px 14px;
cursor: pointer;
border: 1px solid #ccc;
display: inline-block;
user-select: none;
white-space: normal;
line-height: 1.2;
}
/* 字數統計按鈕改為咖啡色底白字 */
.coffeeBgWhiteText {
color: white;
background-color: #8B4513; /* 咖啡色 */
border: 1px solid #8B4513;
}
.blueTextWhiteBorder {
color: blue;
background-color: white;
border: 1px solid blue;
cursor: pointer;
width: 100px;
margin: 5px auto;
display: block;
}
.blueBgWhiteText {
color: white;
background-color: blue;
border: 1px solid blue;
cursor: pointer;
width: 100px;
margin: 5px auto;
display: block;
}
.blackBgWhiteText {
color: white;
background-color: black;
border: 1px solid black;
}
.whiteBgBlackText {
color: black;
background-color: white;
border: 1px solid black;
}
.greenBgWhiteText {
color: white;
background-color: green;
border: 1px solid green;
cursor: pointer;
width: 100px;
margin: 5px auto;
display: block;
}
.purpleBgWhiteText {
color: white;
background-color: purple;
border: 1px solid purple;
cursor: pointer;
width: 100px;
margin: 5px auto;
display: block;
}
.whiteBgRedText {
color: red;
background-color: white;
border: 1px solid red;
}
.whiteTextRedBorder {
color: white;
background-color: red;
border: 1px solid red;
}
#textContent {
white-space: pre-wrap;
line-height: 1.6;
border: 1px solid black;
padding: 15px;
min-height: 300px;
outline: none;
background-color: white;
color: black;
user-select: text;
text-align: left;
font-family: "標楷體", "微軟正黑體", Arial, sans-serif;
overflow-y: auto;
max-height: 400px;
}
mark {
background-color: yellow;
color: black;
}
.vertical-group {
display: inline-block;
vertical-align: top;
margin: 0 15px;
text-align: center;
}
.font-style-btn {
width: 60px;
font-weight: bold;
white-space: nowrap;
position: relative;
}
.save-open-container {
display: inline-block;
margin: 0 20px;
text-align: center;
vertical-align: top;
}
.indent-container {
display: inline-block;
margin: 0 20px;
text-align: center;
vertical-align: top;
}
#fontSizeDropdown {
position: absolute;
bottom: 40px;
left: 0;
background: white;
border: 1px solid #ccc;
padding: 5px;
display: none;
z-index: 1000;
box-shadow: 0 2px 5px rgba(0,0,0,0.2);
user-select: none;
font-size: 14px;
}
#fontSizeDropdown select {
font-size: 14px;
padding: 4px;
}
.font-size-wrapper {
position: relative;
display: inline-block;
vertical-align: middle;
margin-left: 6px;
}
</style>
</head>
<body>
<div class="disclaimer">
使用本工具所產生的問題,製作方概不負責,也代表您同意,請自行審慎判斷與使用。
</div>
<h1 class="title">
<span class="digit">1</span>
<span class="digit">9</span>
<span class="digit">8</span>
<span class="digit">5</span>
<span class="digit">3</span>
<span class="digit">2</span>
<span class="digit">7</span>
<span class="text">爸媽青澀小日記</span>
</h1>
<div class="version-line">
縮放自如的寫作小工具 版本:初版 免費使用
</div>
<div class="search-bar">
<input type="text" id="searchInput" placeholder="搜尋文字,會即時高亮顯示..." />
</div>
<div class="controls">
<button class="blackBgWhiteText" onclick="copyContent()">複製內文</button>
<button class="whiteBgBlackText" onclick="restoreContent()">清空文字</button>
<button class="blackBgWhiteText" onclick="quickBestFormat()">一鍵排版</button>
<button class="whiteBgBlackText" onclick="quickMerge()">一鍵併攏</button>
<br /><br />
<div class="save-open-container">
<button class="greenBgWhiteText" onclick="saveFile()">儲存檔案</button>
<button class="purpleBgWhiteText" onclick="openFile()">開啟檔案</button>
</div>
<div class="indent-container">
<button class="blueTextWhiteBorder" onclick="indentBackward()">往後一格</button>
<button class="blueTextWhiteBorder" onclick="indentForward()">往前一格</button>
</div>
<div class="vertical-group">
<button class="blueBgWhiteText" onclick="increaseBlankLines()">增加行距</button>
<button class="blueBgWhiteText" onclick="decreaseBlankLines()">減少行距</button>
</div>
<br /><br />
<button class="whiteBgBlackText" onclick="copyHTML()">複製HTML格式</button>
<button class="coffeeBgWhiteText" onclick="countCharacters()">字數統計</button>
<input type="file" id="fileInput" style="display:none" accept=".txt,.html" />
<button class="whiteTextRedBorder" onclick="alignText('left')">靠左</button>
<button class="whiteTextRedBorder" onclick="alignText('center')">置中</button>
<button class="whiteTextRedBorder" onclick="alignText('right')">靠右</button>
<button class="font-style-btn" onclick="execCommand('bold')" title="粗體">粗體</button>
<button class="font-style-btn" onclick="execCommand('underline')" title="底線">底線</button>
<button class="font-style-btn" onclick="execCommand('strikeThrough')" title="刪除線">刪除線</button>
<div class="font-size-wrapper">
<button id="fontSizeBtn" class="font-style-btn" title="字體大小">字體大小 ▼</button>
<div id="fontSizeDropdown">
<select id="fontSizeSelect" aria-label="字體大小選擇">
<option value="">選擇大小</option>
<option value="1">很小 (1)</option>
<option value="2">小 (2)</option>
<option value="3">中 (3)</option>
<option value="4">稍大 (4)</option>
<option value="5">大 (5)</option>
<option value="6">很大 (6)</option>
<option value="7">超大 (7)</option>
</select>
</div>
</div>
</div>
<div id="textContent" contenteditable="true" spellcheck="false"></div>
<script>
const textEl = document.getElementById("textContent");
const searchInput = document.getElementById("searchInput");
const STORAGE_KEY = "writingToolContent";
setInterval(() => {
localStorage.setItem(STORAGE_KEY, textEl.innerHTML);
}, 2000);
window.onload = () => {
const saved = localStorage.getItem(STORAGE_KEY);
if (saved) {
textEl.innerHTML = saved;
} else {
restoreContent();
}
};
function restoreContent() {
textEl.innerHTML = "";
localStorage.removeItem(STORAGE_KEY);
}
function copyContent() {
const dummy = document.createElement("textarea");
dummy.value = textEl.innerText;
document.body.appendChild(dummy);
dummy.select();
try {
document.execCommand("copy");
alert("內容已複製!");
} catch {
alert("複製失敗!");
}
document.body.removeChild(dummy);
}
function copyHTML() {
const dummy = document.createElement("textarea");
dummy.value = textEl.innerHTML;
document.body.appendChild(dummy);
dummy.select();
try {
document.execCommand("copy");
alert("HTML格式已複製!");
} catch {
alert("複製 HTML 失敗");
}
document.body.removeChild(dummy);
}
function countCharacters() {
const text = textEl.innerText.replace(/[\s\p{P}]/gu, "");
alert("目前純文字字數為:" + text.length + " 字");
}
function alignText(alignType) {
textEl.style.textAlign = alignType;
}
textEl.addEventListener("paste", function (e) {
e.preventDefault();
const pasteData = (e.clipboardData || window.clipboardData).getData("text");
document.execCommand("insertText", false, pasteData);
});
function quickBestFormat() {
const lines = textEl.innerText.split("\n");
const newLines = [];
for (let i = 0; i < lines.length; i++) {
const trimmed = lines[i].replace(/^ +/, "");
newLines.push(" " + trimmed);
if (i < lines.length - 1) newLines.push("");
}
textEl.innerText = newLines.join("\n");
}
// 新增「一鍵併攏」功能
function quickMerge() {
const lines = textEl.innerText.split("\n");
const newLines = [];
for (let i = 0; i < lines.length; i++) {
// 去除每行開頭所有半形空格與全形空格
const trimmed = lines[i].replace(/^[\u3000\s]+/, "");
// 忽略空白行
if (trimmed !== "") {
newLines.push(trimmed);
}
}
// 行間不留空白行,全部緊貼併攏
textEl.innerText = newLines.join("\n");
}
function indentForward() {
const lines = textEl.innerText.split("\n");
textEl.innerText = lines.map(line => " " + line).join("\n");
}
function indentBackward() {
const lines = textEl.innerText.split("\n");
textEl.innerText = lines.map(line => line.replace(/^ /, "")).join("\n");
}
function increaseBlankLines() {
const lines = textEl.innerText.split("\n");
const newLines = [];
for (let i = 0; i < lines.length; i++) {
newLines.push(lines[i]);
if (lines[i].trim() !== "") newLines.push("");
}
textEl.innerText = newLines.join("\n");
}
function decreaseBlankLines() {
const lines = textEl.innerText.split("\n");
const result = [];
for (let i = 0; i < lines.length; i++) {
if (lines[i].trim() === "" && lines[i + 1] && lines[i + 1].trim() !== "") {
continue;
}
result.push(lines[i]);
}
textEl.innerText = result.join("\n");
}
function highlightSearch(text, searchTerm) {
if (!searchTerm) {
return text;
}
const escapedTerm = searchTerm.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
const regex = new RegExp(escapedTerm, 'gi');
return text.replace(regex, match => `<mark>${match}</mark>`);
}
searchInput.addEventListener("input", () => {
const term = searchInput.value.trim();
if (!term) {
const saved = localStorage.getItem(STORAGE_KEY) || "";
textEl.innerHTML = saved;
return;
}
const rawText = textEl.innerText;
textEl.innerHTML = highlightSearch(rawText, term);
});
function execCommand(cmd) {
document.execCommand(cmd, false, null);
}
function saveFile() {
const blob = new Blob([textEl.innerText], {type: "text/plain;charset=utf-8"});
const url = URL.createObjectURL(blob);
const a = document.createElement("a");
a.href = url;
a.download = "writing.txt";
document.body.appendChild(a);
a.click();
setTimeout(() => {
document.body.removeChild(a);
URL.revokeObjectURL(url);
}, 0);
}
function openFile() {
const fileInput = document.getElementById("fileInput");
fileInput.value = null;
fileInput.click();
}
document.getElementById("fileInput").addEventListener("change", function (e) {
const file = e.target.files[0];
if (!file) return;
const reader = new FileReader();
reader.onload = function(evt) {
textEl.innerText = evt.target.result;
localStorage.setItem(STORAGE_KEY, textEl.innerHTML);
searchInput.value = "";
};
reader.readAsText(file, "UTF-8");
});
// 字體大小選單相關事件
const fontSizeBtn = document.getElementById("fontSizeBtn");
const fontSizeDropdown = document.getElementById("fontSizeDropdown");
const fontSizeSelect = document.getElementById("fontSizeSelect");
fontSizeBtn.addEventListener("click", () => {
fontSizeDropdown.style.display = fontSizeDropdown.style.display === "block" ? "none" : "block";
});
fontSizeSelect.addEventListener("change", () => {
const size = fontSizeSelect.value;
if (size) {
document.execCommand("fontSize", false, size);
}
fontSizeDropdown.style.display = "none";
fontSizeSelect.value = "";
});
// 點擊頁面其他地方關閉字體大小選單
document.addEventListener("click", (e) => {
if (!fontSizeBtn.contains(e.target) && !fontSizeDropdown.contains(e.target)) {
fontSizeDropdown.style.display = "none";
}
});
</script>
</body>
</html>
這段程式碼經過多次測試與優化,整理成方便使用的版本,希望對大家有所幫助。
如果你覺得這寫作小工具有用,請留個留言讓我知道有人在用。