手写Vue3

const App = {
  data: reactive({
    name: "123",
  }),
  template: `<div>我是Vue3<span>我在它里面</span></div>`,
};

function reactive(data) {
  return new Proxy(data, {
    get: (target, key) => {
      if (target.hasOwnProperty(key)) {
        return target[key];
      }
    },
    set: (target, key, value) => {
      target[key] = value;
      render(target);
    },
  });
}

function render(data, documentId) {
  console.log(data.data.name);
  const vnode = compile(data.template)();
  console.log(vnode);
  function createRender(vnode) {
    const el = document.createElement(vnode.tag);
    for (const key in vnode.props) {
      if (key.startsWith("on")) {
        el.addEventListener(key.slice(2), vnode.props[key]);
      }
    }
    vnode.children.forEach((node) => {
      if (typeof node == "string") {
        el.textContent = node;
      } else {
        el.appendChild(createRender(node));
      }
    });
    return el;
  }
  document.getElementById(documentId).appendChild(createRender(vnode));
}

function compile(template) {
  // 1. 将模板字符串转换为 HTML 元素
  const tempDiv = document.createElement("div");
  tempDiv.innerHTML = template;
  const el = tempDiv.firstChild;

  // 2. 递归解析 HTML 元素,生成虚拟 DOM
  function _compile(node) {
    if (node.nodeType === Node.TEXT_NODE) {
      // 处理文本节点
      return node.textContent;
    }

    // 处理元素节点
    const vNode = {
      tag: node.tagName.toLowerCase(),
      props: {},
      children: [],
    };

    // 获取属性
    for (let i = 0; i < node.attributes.length; i++) {
      const attr = node.attributes[i];
      vNode.props[attr.name] = attr.value;
    }

    // 递归处理子节点
    for (let i = 0; i < node.childNodes.length; i++) {
      vNode.children.push(_compile(node.childNodes[i]));
    }

    return vNode;
  }

  // 3. 返回生成虚拟 DOM 的函数
  return () => _compile(el);
}

render(App, "app");

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
Vue3中的`keep-alive`组件用于缓存组件实例,以便在路由切换时重用已渲染的组件,而不是每次都重新创建。这在需要数据持久化或需要避免频繁重新渲染的场景下非常有用。 手写`keep-alive`的基本步骤如下: 1. 安装并引入Vue: ```javascript import { createApp, h } from 'vue'; ``` 2. 创建一个自定义`KeepAlive`组件: ```javascript // keep-alive-custom.js export default { functional: true, render(h, { children, props }) { const ComponentToCache = children.length === 1 ? children // 如果只有一个子组件,直接使用 : null; if (props.include || props.exclude) { // 如果指定了包含或排除规则,则根据当前组件是否匹配规则决定是否缓存 let shouldCache = true; if (props.include && !props.include(ComponentToCache)) { shouldCache = false; } else if (props.exclude && props.exclude(ComponentToCache)) { shouldCache = false; } return shouldCache ? h(ComponentToCache) : null; } return children.length > 1 ? h('div', { key: '__keep-alive' }, children) : null; }, }; ``` 3. 在Vue应用中使用自定义`KeepAlive`: ```javascript // main.js 或 App.vue import { createApp } from 'vue'; import KeepAliveCustom from './keep-alive-custom.js'; const app = createApp(App); app.component('keep-alive-custom', KeepAliveCustom); app.config.globalProperties.$route = new VueRouter(); // 假设你已经配置了路由 app.mount('#app'); // 使用自定义的keep-alive app.use((router) => { router beforeEach((to, from, next) => { // 清除已缓存的组件实例,例如在登录/登出后 router.app.$children.forEach((child) => { if (child.$options.name === 'KeepAliveCustom') { child.$children.forEach((childChild) => { if (childChild.$options.name) { childChild.$destroy(); } }); } }); // 缓存当前路由对应的组件 const ComponentToCache = router.app.$route.meta.keepAliveComponent || to.component; router.app.$nextTick(() => { const keepAlive = router.app.$refs['keep-alive-custom']; if (keepAlive) { keepAlive.renderedChildren.some((child) => { if (child.$options.name === ComponentToCache.name) { child.$forceUpdate(); return true; } }); } }); next(); }); }); ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小小前端--可笑可笑

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值