Appearance
gpt简单版
本节目标:理解“gpt简单版”的核心思路,并能把它用于实际开发或面试表达。
1. 响应式系统
问题
- 如何实现响应式数据系统?
- 如何追踪和触发依赖?
步骤
- 使用
Proxy和Reflect实现响应式数据系统。 - 创建一个依赖追踪系统,使用
Dep类来管理依赖。
示例代码
// 定义一个函数,用于将目标对象转换为响应式对象 function reactive(target) { // 定义处理器对象,包含 get 和 set 拦截器 const handler = { // get 拦截器,在读取属性时触发 get(target, key, receiver) { // 使用 Reflect.get 方法读取对象的属性值 const result = Reflect.get(target, key, receiver); // 调用 track 函数进行依赖收集 track(target, key); // 返回属性值 return result; }, // set 拦截器,在写入属性时触发 set(target, key, value, receiver) { // 记录旧值 const oldValue = target[key]; // 使用 Reflect.set 方法设置对象的属性值 const result = Reflect.set(target, key, value, receiver); // 如果新值和旧值不同,则触发依赖 if (oldValue !== result) { // 调用 trigger 函数触发依赖 trigger(target, key); } // 返回设置结果 return result; } }; // 创建并返回一个代理对象,将目标对象和处理器关联起来 return new Proxy(target, handler); }
let activeEffect = null; const targetMap = new WeakMap(); function track(target, key) { if (activeEffect) { let depsMap = targetMap.get(target); if (!depsMap) { targetMap.set(target, (depsMap = new Map())); } let dep = depsMap.get(key); if (!dep) { depsMap.set(key, (dep = new Set())); } dep.add(activeEffect); } } function trigger(target, key) { const depsMap = targetMap.get(target); if (!depsMap) return; const dep = depsMap.get(key); if (dep) { dep.forEach(effect => effect()); } } function effect(eff) { activeEffect = eff; activeEffect(); activeEffect = null; }
2. 模板编译
问题
- 如何解析模板?
- 如何将模板转换为虚拟 DOM?
步骤
- 使用正则表达式解析模板。
- 创建虚拟 DOM 树,包含节点类型和子节点。
示例代码
function compile(template) { const reg = /{{(.+?)}}/g; let match; while ((match = reg.exec(template))) { const key = match[1].trim(); template = template.replace(match[0], " + state.${key} + "); } return new Function('state', return \${template}`); \} const template = <div>{{ message }}</div>`; const render = compile(template);
3. 渲染系统
问题
- 如何将虚拟 DOM 渲染为真实 DOM?
- 如何实现虚拟 DOM 的 diff 算法?
步骤
- 实现一个简单的虚拟 DOM 渲染函数。
- 实现虚拟 DOM diff 算法。
示例代码
function createElement(tag, props, ...children) { return { tag, props, children }; } function render(vnode, container) { if (typeof vnode === 'string') { container.appendChild(document.createTextNode(vnode)); return; } const el = document.createElement(vnode.tag); for (const key in vnode.props) { el.setAttribute(key, vnode.props[key]); } vnode.children.forEach(child => render(child, el)); container.appendChild(el); } const vnode = createElement('div', { id: 'app' }, createElement('span', null, 'Hello, world!')); render(vnode, document.body);
4. 组件系统
问题
- 如何实现组件化?
- 如何在组件中使用响应式数据和模板?
步骤
- 创建一个组件类,包含模板和数据。
- 实现组件的渲染和更新逻辑。
示例代码
class Component { constructor(options) { this.template = options.template; this.data = reactive(options.data()); this.render = compile(this.template); effect(() => this.update()); } update() { const html = this.render(this.data); document.querySelector(options.el).innerHTML = html; } } const app = new Component({ el: '#app', template: \<div\>{{ message }}\</div\>, data() { return { message: 'Hello, Vue!' }; } });
5. 路由系统
问题
- 如何实现前端路由?
- 如何在 URL 变化时更新视图?
步骤
- 使用
historyAPI 实现路由。 - 创建一个路由组件,监听 URL 变化并渲染对应的组件。
示例代码
class Router { constructor(routes) { this.routes = routes; window.addEventListener('popstate', () => this.render()); this.render(); } push(path) { window.history.pushState({}, '', path); this.render(); } render() { const path = window.location.pathname; const route = this.routes.find(route => route.path === path); if (route) { document.querySelector('#app').innerHTML = route.component.template; } } } const Home = { template: '<div>Home</div>' }; const About = { template: '<div>About</div>' }; const router = new Router([ { path: '/', component: Home }, { path: '/about', component: About } ]);
总结
通过一步步回答以上问题和实现代码,你可以构建一个简单的 Vue 3 框架。这个框架包含了响应式数据、模板编译、虚拟 DOM 渲染、组件化和路由系统。每个步骤都可以根据需要进一步扩展和优化。
