<style>
.watch-demo { font-family: system-ui; }
.controls { display: flex; gap: 8px; margin-bottom: 16px; flex-wrap: wrap; }
.btn { padding: 8px 16px; border: none; border-radius: 6px; cursor: pointer; font-weight: 500; }
.btn-blue { background: #3b82f6; color: white; }
.btn-green { background: #22c55e; color: white; }
.btn-purple { background: #8b5cf6; color: white; }
.state-bar { display: flex; gap: 20px; background: #1e293b; padding: 12px 16px; border-radius: 8px; margin-bottom: 16px; }
.state-item { color: #94a3b8; }
.state-item span { color: #22c55e; font-weight: bold; }
.logs-container { display: grid; grid-template-columns: 1fr 1fr; gap: 12px; }
.log-panel { background: #0f172a; padding: 12px; border-radius: 8px; }
.log-title { font-size: 12px; color: #64748b; margin-bottom: 8px; padding-bottom: 8px; border-bottom: 1px solid #1e293b; }
.log-title .type { font-weight: bold; }
.log-title .watch { color: #3b82f6; }
.log-title .effect { color: #8b5cf6; }
.log-content { font-family: monospace; font-size: 11px; max-height: 150px; overflow-y: auto; }
.log-entry { padding: 4px 0; color: #94a3b8; border-bottom: 1px solid #1e293b; }
.log-entry:last-child { border-bottom: none; }
.log-entry.new { color: #fbbf24; }
.note { background: #1e3a5f; padding: 10px; border-radius: 6px; margin-top: 12px; font-size: 12px; color: #93c5fd; }
</style>
<div class="watch-demo">
<div class="state-bar">
<div class="state-item">count: <span id="countVal">0</span></div>
<div class="state-item">name: <span id="nameVal">"Vue"</span></div>
</div>
<div class="controls">
<button class="btn btn-blue" onclick="updateCount()">count++</button>
<button class="btn btn-green" onclick="updateName()">切换 name</button>
<button class="btn btn-purple" onclick="updateBoth()">同时修改两个</button>
</div>
<div class="logs-container">
<div class="log-panel">
<div class="log-title"><span class="type watch">watch(count)</span> - 显式依赖</div>
<div class="log-content" id="watchLog">
<div class="log-entry">等待 count 变化...</div>
</div>
</div>
<div class="log-panel">
<div class="log-title"><span class="type effect">watchEffect</span> - 自动收集</div>
<div class="log-content" id="effectLog">
<div class="log-entry new">✅ 立即执行: count=0, name="Vue"</div>
</div>
</div>
</div>
<div class="note">
💡 <b>watch</b>: 只监听 count,有 oldVal/newVal<br>
💡 <b>watchEffect</b>: 自动收集所有访问的依赖,无 oldVal
</div>
</div>
<script>
let count = 0;
let name = 'Vue';
const names = ['Vue', 'React', 'Angular', 'Svelte'];
let nameIdx = 0;
const watchLogs = [];
const effectLogs = ['✅ 立即执行: count=0, name="Vue"'];
function addLog(arr, msg, panelId) {
arr.unshift(msg);
if (arr.length > 6) arr.pop();
document.getElementById(panelId).innerHTML =
arr.map((l, i) => '<div class="log-entry' + (i === 0 ? ' new' : '') + '">' + l + '</div>').join('');
}
function updateState() {
document.getElementById('countVal').textContent = count;
document.getElementById('nameVal').textContent = '"' + name + '"';
}
function updateCount() {
const old = count;
count++;
updateState();
// watch 触发
addLog(watchLogs, 'count: ' + old + ' → ' + count + ' (有 oldVal)', 'watchLog');
// watchEffect 触发
addLog(effectLogs, 'count=' + count + ', name="' + name + '"', 'effectLog');
}
function updateName() {
nameIdx = (nameIdx + 1) % names.length;
name = names[nameIdx];
updateState();
// watch 不触发(只监听 count)
// watchEffect 触发
addLog(effectLogs, 'count=' + count + ', name="' + name + '"', 'effectLog');
}
function updateBoth() {
const oldCount = count;
count++;
nameIdx = (nameIdx + 1) % names.length;
name = names[nameIdx];
updateState();
addLog(watchLogs, 'count: ' + oldCount + ' → ' + count + ' (有 oldVal)', 'watchLog');
addLog(effectLogs, 'count=' + count + ', name="' + name + '"', 'effectLog');
}
</script>