1️⃣ 需求设定
我想做一个纯前端粘贴板,特点:
通过宝塔部署在自己的服务器上
输入 IP/xxx 就创建一个新的粘贴板页面
页面可以展示和编辑文本
可以保存到服务器,让不同设备访问同一链接时看到同一份内容
样式简洁舒适
2️⃣ 前端初始方案
用一个 单文件 index.html,根据 location.pathname 判断当前粘贴板的名字(slug)
最初版本只保存到 浏览器 localStorage
功能:输入/粘贴文本,自动保存到本地
问题:
只是本地保存,不同设备无法共享
样式简单,视觉效果一般
3️⃣ 添加服务器保存功能
写一个 极简 PHP 后端 paste.php
GET 请求读取 /pastes/{slug}.txt
POST 请求保存到 /pastes/{slug}.txt
前端改成 fetch 调用 PHP 保存/读取内容
任意路径 /xxx 对应 /pastes/xxx.txt
遇到的问题和解决方法:
PHP 语法报错:
原先 $ base/$slug.txt 写法在 PHP 低版本报错
修正为 $file = $base . ‘/’ . $slug . ‘.txt’;
前端 JS 报错:
原先使用复杂正则表达式导致 Invalid regular expression flags
简化 JS,仅用 location.pathname 解析 slug
PHP 无法执行:
宝塔站点 PHP 版本选择只有“静态”和“自定义”
解决:安装 PHP(如 8.1)并绑定到站点
路径/权限问题:
/home/dist/pastes/ 必须可写(权限 775 或 777)
paste.php 必须在站点根目录
4️⃣ 宝塔配置
新建网站:
域名/IP:117.72.99.159
根目录:/home/dist
PHP版本:绑定已安装 PHP 8.1
上传文件:
/home/dist/index.html
/home/dist/paste.php
/home/dist/pastes/ ← 可写
伪静态配置(保证 /xxx 都返回 index.html):
location / {
try_files $uri $uri/ /index.html;
}
location ~ \.php$ {
include fastcgi.conf;
fastcgi_pass unix:/var/run/php/php8.1-fpm.sock;
}
5️⃣ 测试流程
访问 http://117.72.99.159/zqk → 新建粘贴板
修改内容 → 自动保存到 /home/dist/pastes/zqk.txt
切换设备/浏览器 → 打开相同路径 /zqk → 数据同步
✅ 功能成功实现
6️⃣ 样式优化
使用现代卡片风格、圆角阴影
背景柔和,字体易读
文本框宽度自适应,防止超出父容器
状态栏显示保存时间
7️⃣ 最终源码
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>简易粘贴板</title>
<style>
* {margin:0;padding:0;box-sizing:border-box;}
body {
font-family: "Helvetica Neue", Arial, sans-serif;
background: #f0f2f5;
color: #333;
}
.wrap {
max-width: 900px;
margin: 40px auto;
padding: 20px;
background: #fff;
border-radius: 12px;
box-shadow: 0 8px 20px rgba(0,0,0,0.1);
}
h1 {font-size: 22px;margin-bottom:12px;color:#1f2937;}
.slug {font-weight:normal;color:#2563eb;}
textarea {
width: 100%;
box-sizing: border-box;
min-height: 70vh;
resize: vertical;
padding: 14px;
font-size: 16px;
line-height: 1.5;
border: 1px solid #d1d5db;
border-radius: 8px;
outline-color:#2563eb;
background:#f9fafb;
}
.status {
margin-top:10px;
font-size:13px;
color:#6b7280;
text-align:right;
}
</style>
</head>
<body>
<div class="wrap">
<h1>📝 粘贴板:<span class="slug" id="slug"></span></h1>
<textarea id="pad" placeholder="在这里输入或粘贴内容..."></textarea>
<div class="status" id="status">—</div>
</div>
<script>
(async function(){
const slug = decodeURIComponent(location.pathname.replace(/\/$/,'').slice(1) || 'home');
const elSlug = document.getElementById('slug');
const pad = document.getElementById('pad');
const status = document.getElementById('status');
elSlug.textContent = '/' + slug;
function setStatus(text){ status.textContent = text; }
try {
const res = await fetch('/paste.php?slug=' + encodeURIComponent(slug));
if(res.ok){
pad.value = await res.text();
setStatus('已加载服务器内容');
} else {
setStatus('新建空板子');
}
} catch(e){
setStatus('加载失败');
}
let t;
pad.addEventListener('input', ()=>{
clearTimeout(t);
t = setTimeout(async ()=>{
try{
await fetch('/paste.php',{
method:'POST',
headers:{'Content-Type':'application/json'},
body: JSON.stringify({slug, content: pad.value})
});
setStatus('已保存到服务器 ' + new Date().toLocaleTimeString());
} catch(e){
setStatus('保存失败');
}
},500);
});
})();
</script>
</body>
</html>
paste.php
<?php
header('Content-Type: text/plain; charset=utf-8');
$base = __DIR__ . '/pastes';
if (!is_dir($base)) { mkdir($base, 0775, true); }
function safe_slug($s) { return preg_match('/^[A-Za-z0-9_-]{1,128}$/', $s); }
if ($_SERVER['REQUEST_METHOD'] === 'GET') {
$slug = $_GET['slug'] ?? '';
if (!safe_slug($slug)) { http_response_code(400); exit('Bad slug'); }
$file = $base . '/' . $slug . '.txt';
if (!file_exists($file)) { http_response_code(204); exit; }
readfile($file);
exit;
}
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
$raw = file_get_contents('php://input');
$j = json_decode($raw, true);
if (!$j || !isset($j['slug'])) { http_response_code(400); exit('Invalid body'); }
$slug = $j['slug'];
if (!safe_slug($slug)) { http_response_code(400); exit('Bad slug'); }
$content = $j['content'] ?? '';
$file = $base . '/' . $slug . '.txt';
if (file_put_contents($file, $content) === false) { http_response_code(500); exit('Write fail'); }
echo 'OK';
exit;
}
http_response_code(405);
echo 'Method Not Allowed';
这样就完成了