<!DOCTYPE html>
<html>
<head><title>Mini Vue</title>
</head>
<body><div id="app"><input v-model="message" /><p>{{ message }}</p></div><script>// 1. 响应式系统(上面的代码)function reactive(target) {return new Proxy(target, {get(obj, key) {track(obj, key)return obj[key]},set(obj, key, value) {obj[key] = valuetrigger(obj, key)return true}})}let activeEffect = nullconst targetMap = new WeakMap()function watchEffect(effect) {activeEffect = effecteffect()activeEffect = null}function track(obj, key) {if (!activeEffect) returnlet depsMap = targetMap.get(obj)if (!depsMap) targetMap.set(obj, (depsMap = new Map()))let dep = depsMap.get(key)if (!dep) depsMap.set(key, (dep = new Set()))dep.add(activeEffect)}function trigger(obj, key) {const depsMap = targetMap.get(obj)if (!depsMap) returnconst dep = depsMap.get(key)if (dep) dep.forEach(effect => effect())}// 2. 极简编译:查找 v-model 和 {{ }}function compile(el, data) {// 查找所有子元素const nodes = el.querySelectorAll('*')// 处理 v-modelel.querySelectorAll('[v-model]').forEach(input => {const key = input.getAttribute('v-model')// 初始化 valueinput.value = data[key]// 双向绑定input.addEventListener('input', (e) => {data[key] = e.target.value})// 数据变化时更新 inputwatchEffect(() => {input.value = data[key]})})// 处理 {{ message }}Array.from(el.childNodes).forEach(node => {if (node.nodeType === 3) { // 文本节点const text = node.textContentconst match = text.match(/\{\{(.*)\}\}/)if (match) {const key = match[1].trim()// 初次渲染node.textContent = node.textContent.replace(match[0], data[key])// 响应式更新watchEffect(() => {node.textContent = node.textContent.replace(data[key], data[key])})}}})// 处理子元素中的 {{ }}nodes.forEach(node => {Array.from(node.childNodes).forEach(child => {if (child.nodeType === 3) {const text = child.textContentconst match = text.match(/\{\{(.*)\}\}/)if (match) {const key = match[1].trim()const getValue = () => data[key]watchEffect(() => {child.textContent = text.replace(/\{\{.*\}\}/, getValue())})}}})})}// 3. 启动const obj = { message: 'Hello, Mini Vue!' }const data = reactive(obj)const app = document.getElementById('app')compile(app, data)</script>
</body>
</html>