{"id":5240,"date":"2026-02-27T22:33:54","date_gmt":"2026-02-27T14:33:54","guid":{"rendered":"https:\/\/blog.odjbinail.cn\/?p=5240"},"modified":"2026-02-27T22:33:54","modified_gmt":"2026-02-27T14:33:54","slug":"vue3%e6%ba%90%e7%a0%81%e8%a7%a3%e6%9e%90","status":"publish","type":"post","link":"https:\/\/blog.odjbinail.cn\/?p=5240","title":{"rendered":"Vue3\u6e90\u7801\u89e3\u6790"},"content":{"rendered":"<h2>\u95ee\u9898: .vue \u4e2d\u7684 HTML \u662f\u771f\u5b9e\u7684 html \u5417? \u4e0d\u662f<\/h2>\n<p>\u4e2d\u95f4\u505a\u4e86\u4ec0\u4e48\u4e8b\u60c5, \u8ba9 \u5047\u7684 html \u6807\u7b7e\u8282\u70b9 \u88ab\u6e32\u67d3\u6210\u4e86 \u771f\u5b9e\u7684 html \u6807\u7b7e\u8282\u70b9? <\/p>\n<ul>\n<li>\u7f16\u8bd1\u65f6: compiler<\/li>\n<li>\u8fd0\u884c\u65f6: runtime<\/li>\n<\/ul>\n<h2>\u4ec0\u4e48\u662f\u8fd0\u884c\u65f6?<\/h2>\n<p><a href=\"https:\/\/cn.vuejs.org\/api\/options-rendering.html#render\">https:\/\/cn.vuejs.org\/api\/options-rendering.html#render<\/a><br \/>\nrender: \u7528\u4e8e\u7f16\u7a0b\u5f0f\u5730\u521b\u5efa\u7ec4\u4ef6\u865a\u62df DOM \u6811\u7684\u51fd\u6570\u3002<br \/>\n\u4f5c\u7528: \u4ee3\u66ff template \u6a21\u677f\u6765\u5b8c\u6210 DOM \u7684\u6e32\u67d3<\/p>\n<ul>\n<li>\u4ee5\u4e0b\u662f \u8fd0\u884c\u65f6 \u7684\u4ee3\u7801\u6846\u67b6<br \/>\n<strong>\u8fd0\u884c\u65f6\u53ef\u4ee5\u5229\u7528 render \u628a vnode \u6e32\u67d3\u6210\u771f\u5b9e dom \u8282\u70b9<\/strong><\/li>\n<\/ul>\n<pre class=\"prettyprint linenums\" ><code>&lt;html lang=&quot;en&quot;&gt;\n&lt;head&gt;\n  &lt;meta charset=&quot;UTF-8&quot;&gt;\n  &lt;script src=&quot;https:\/\/cdn.bootcdn.net\/ajax\/libs\/vue\/3.5.22\/vue.global.js&quot;&gt;&lt;\/script&gt;\n&lt;\/head&gt;\n&lt;body&gt;\n  &lt;div id=&quot;app&quot;&gt;\n&lt;!--\u671f\u671b\u76ee\u6807: &lt;div class=&quot;test&quot;&gt;hello render&lt;\/div&gt; --&gt;\n  &lt;\/div&gt;\n&lt;\/body&gt;\n\n&lt;script&gt;\n  const {render,h}=Vue\n  \/\/\u751f\u6210 vnode\n  const vnode=h(&#039;div&#039;,{\n    class:&#039;test&#039;\n  },&#039;hello render&#039;)\n  \/\/\u62ff\u5230\u627f\u8f7d\u7684\u5bb9\u5668\n  const container= document.querySelector(&#039;#app&#039;)\n  \/\/\u6e32\u67d3\n  render(vnode,container)\n&lt;\/script&gt;\n\n&lt;\/html&gt;<\/code><\/pre>\n<pre class=\"prettyprint linenums\" ><code>&lt;html lang=&quot;en&quot;&gt;\n&lt;head&gt;\n  &lt;meta charset=&quot;UTF-8&quot;&gt;\n  &lt;script src=&quot;https:\/\/cdn.bootcdn.net\/ajax\/libs\/vue\/3.5.22\/vue.global.js&quot;&gt;&lt;\/script&gt;\n&lt;\/head&gt;\n&lt;body&gt;\n  &lt;div id=&quot;app&quot;&gt;\n  &lt;\/div&gt;\n&lt;\/body&gt;\n\n&lt;script&gt;\n\/\/\u6839\u636e\u5982\u4e0b\u6570\u636e\u6e32\u67d3\u51fa div\n  const vnode={\n    type:&#039;div&#039;,\n    props:{\n      class:&#039;test&#039;\n    },\n    children:&#039;hello render&#039;\n  }\n  \/\/\u521b\u5efa\u4e00\u4e2a render \u51fd\u6570\n  function render(vnode){\n    const ele=document.createElement(vnode.type)\n    ele.className=vnode.props.class\n    ele.innerText=vnode.children\n    document.body.appendChild(ele)\n  }\n  render(vnode)\n&lt;\/script&gt;\n\n&lt;\/html&gt;<\/code><\/pre>\n<h2>\u4ec0\u4e48\u662f\u7f16\u8bd1\u65f6?<\/h2>\n<p>\u5982\u679c\u53ea\u9760  <strong>\u8fd0\u884c\u65f6<\/strong>  , \u90a3\u4e48\u662f\u6ca1\u6cd5\u901a\u8fc7<strong>HTML \u6807\u7b7e\u7ed3\u6784\u7684\u65b9\u5f0f<\/strong>\uff0c\u6765\u8fdb\u884c\u6e32\u67d3\u89e3\u6790\u7684\uff0c\u5c31\u9700\u8981\u501f\u52a9  <strong>\u7f16\u8bd1\u65f6<\/strong><\/p>\n<ul>\n<li>\u4e3b\u8981\u4f5c\u7528\uff1a\u628a template \u4e2d\u7684 html \u7f16\u8bd1\u6210 render \u51fd\u6570\u3002\u5982\u4f55\u518d\u5229\u7528 \u8fd0\u884c\u65f6 \u901a\u8fc7 render \u6302\u8f7d\u5bf9\u5e94\u7684 dom<\/li>\n<li>\u7f16\u8bd1\u65f6\u53ef\u4ee5\u628a html \u7684\u8282\u70b9, \u7f16\u8bd1\u6210 render \u51fd\u6570<\/li>\n<\/ul>\n<pre class=\"prettyprint linenums\" ><code> &lt;script&gt;\n    const { compile, createApp } = Vue;\n    \/\/\u521b\u5efa\u4e00\u4e2a html \u7ed3\u6784\n    const html = `&lt;div class=&quot;test&quot;&gt;hello compiler &lt;\/div&gt;`;\n    \/\/\u5229\u7528 compile \u51fd\u6570,\u751f\u6210 render \u51fd\u6570\n    const renderFn = compile(html);\n    console.log(renderFn);\n    \/\/\u521b\u5efa\u5b9e\u4f8b\n    const app = createApp({\n      \/\/\u5229\u7528 render \u51fd\u6570\u8fdb\u884c\u6e32\u67d3\n      render: renderFn,\n    });\n    \/\/\u6302\u8f7d\n    app.mount(&quot;#app&quot;);\n  &lt;\/script&gt;<\/code><\/pre>\n<h2>Vue \u662f\u4e00\u4e2a  \u8fd0\u884c\u65f6+\u7f16\u8bd1\u65f6 \u7684\u6846\u67b6<\/h2>\n<ul>\n<li>vue \u901a\u8fc7 compiler \u89e3\u6790 html \u6a21\u677f, \u751f\u6210 render \u51fd\u6570, \u7136\u540e\u901a\u8fc7 runtime \u89e3\u6790 render, \u4ece\u800c\u6302\u8f7d\u771f\u5b9e dom<\/li>\n<\/ul>\n<h3>\u4e3a\u4ec0\u4e48\u8fd9\u6837\u8bbe\u8ba1\u5462?<\/h3>\n<p>\u6211\u4eec\u5c31\u9700\u8981\u77e5\u9053 dom \u6e32\u67d3\u662f\u5982\u4f55\u8fdb\u884c\u7684<\/p>\n<ul>\n<li>\u5bf9\u4e8e dom \u6e32\u67d3\u800c\u8a00, \u53ef\u4ee5\u88ab\u5206\u4e3a\u4e24\u90e8\u5206:\n<ul>\n<li>\u521d\u6b21\u6e32\u67d3\uff0c\u53ef\u4ee5\u53eb\u505a \u6302\u8f7d<\/li>\n<li>\u66f4\u65b0\u6e32\u67d3\uff0c \u53ef\u4ee5\u53eb \u6253\u8865\u4e01<\/li>\n<\/ul>\n<\/li>\n<\/ul>\n<h4>\u521d\u6b21\u6e32\u67d3<\/h4>\n<pre class=\"prettyprint linenums\" ><code>\/\/\u5f53 div \u7684 innerHTML \u4e3a\u7a7a\u65f6\uff0c\n&lt;div id=&quot;app&quot;&gt;&lt;\/div&gt;\n\/\/\u6e32\u67d3\u5982\u4e0b\u8282\u70b9\uff1a\n&lt;ul&gt;\n&lt;li&gt;1&lt;\/li&gt;\n&lt;li&gt;2&lt;\/li&gt;\n&lt;\/ul&gt;<\/code><\/pre>\n<p>\u8fd9\u6837\u5c31\u662f\u521d\u59cb\u6e32\u67d3<\/p>\n<h4>\u66f4\u65b0\u6e32\u67d3<\/h4>\n<p>li -2 \u4e0a\u5347\u5230\u4e86\u7b2c\u4e00\u4f4d, \u90a3\u8fd9\u6837\u6d4f\u89c8\u5668\u5982\u4f55\u66f4\u65b0\u8fd9\u6b21\u6e32\u67d3\u5462?<\/p>\n<p><strong>\u4e24\u79cd\u65b9\u5f0f:<\/strong><\/p>\n<ul>\n<li>\u5220\u9664\u539f\u6709\u7684\u6240\u6709\u8282\u70b9, \u91cd\u65b0\u6e32\u67d3\u65b0\u7684\u8282\u70b9\n<ul>\n<li>\u597d\u5904\u5728\u4e8e\u4e0d\u9700\u8981\u4efb\u4f55\u6bd4\u5bf9,\u9700\u8981\u6267\u884c 6 \u6b21( \u5220\u9664 3 \u6b21, \u91cd\u65b0\u6e32\u67d3 3 \u6b21) dom \u5904\u7406\u5373\u53ef \u3010\u4f1a\u6d89\u53ca\u5230\u66f4\u591a\u7684 dom \u64cd\u4f5c\u3011<\/li>\n<\/ul>\n<\/li>\n<li>\u5220\u9664\u539f\u4f4d\u7f6e\u7684 li-2, \u5728\u65b0\u4f4d\u7f6e\u63d2\u5165 li-2\n<ul>\n<li>\u5bf9\u6bd4 <strong>\u65e7\u8282\u70b9<\/strong> \u548c <strong>\u65b0\u8282\u70b9<\/strong> \u4e4b\u95f4\u7684\u5dee\u5f02<\/li>\n<li>\u6839\u636e\u5dee\u5f02, \u5220\u9664\u4e00\u4e2a\u65e7\u8282\u70b9, \u589e\u52a0\u4e00\u4e2a\u65b0\u8282\u70b9<br \/>\n\u3010\u4f1a\u6d89\u53ca\u5230 js \u8ba1\u7b97+ \u5c11\u91cf\u7684 dom \u64cd\u4f5c\u3011<\/li>\n<\/ul>\n<\/li>\n<\/ul>\n<pre class=\"prettyprint linenums\" ><code>  &lt;script&gt;\n    \/\/\u76f8\u540c\u6570\u91cf\u7684 DOM \u64cd\u4f5c\u548c JS \u8ba1\u7b97\u64cd\u4f5c, \u54ea\u4e00\u4e2a\u66f4\u5feb\n\n    const length = 10000;\n    \/\/\u589e\u52a0\u4e00\u4e07\u4e2a dom \u8282\u70b9, \u67e5\u770b\u8017\u65f6 3.992923...ms\n    console.time(&quot;element&quot;);\n    for (let i = 0; i &lt; length; i++) {\n      const div = document.createElement(&quot;div&quot;);\n      document.body.appendChild(div);\n    }\n    console.timeEnd(&quot;element&quot;);\n 0.\n    \/\/\u589e\u52a0\u4e00\u4e07\u4e2a js \u5bf9\u8c61, \u67e5\u770b\u8017\u65f6 0.402099...ms\n    console.time(&quot;js&quot;);\n    const divList = [];\n    for (let i = 0; i &lt; length; i++) {\n      const ele = {\n        type: &quot;div&quot;\n      };\n      divList.push(ele);\n    }\n\n    console.timeEnd(&quot;js&quot;);\n  &lt;\/script&gt;<\/code><\/pre>\n<ul>\n<li>dom \u64cd\u4f5c\u8981\u6bd4 js \u7684\u64cd\u4f5c\u8017\u65f6\u591a\u7684\u591a, \u5373 dom \u64cd\u4f5c\u6bd4 js \u66f4\u52a0\u8017\u8d39\u6027\u80fd<\/li>\n<\/ul>\n<h3>\u4e3a\u4ec0\u4e48 vue \u8981\u8bbe\u8ba1\u6210\u4e00\u4e2a\u8fd0\u884c\u65f6+\u7f16\u8bd1\u65f6 \u7684\u6846\u67b6\u5462? \u7b54\u6848:<\/h3>\n<p>\u67e5\u770b\u6587\u6863 : <a href=\"https:\/\/cn.vuejs.org\/guide\/extras\/rendering-mechanism.html\">https:\/\/cn.vuejs.org\/guide\/extras\/rendering-mechanism.html<\/a><\/p>\n<ul>\n<li>1.\u9488\u5bf9\u4e8e<strong>\u7eaf\u8fd0\u884c\u65f6<\/strong>\u800c\u8a00:\u56e0\u4e3a\u4e0d\u5b58\u5728\u7f16\u8bd1\u5668\uff0c\u6240\u4ee5\u6211\u4eec\u53ea\u80fd\u591f\u63d0\u4f9b\u4e00\u4e2a\u590d\u6742\u7684 JS \u5bf9\u8c61\u3002<\/li>\n<li>2.\u9488\u5bf9\u4e8e<strong>\u7eaf\u7f16\u8bd1\u65f6<\/strong>\u800c\u8a00:\u56e0\u4e3a\u7f3a\u5c11\u8fd0\u884c\u65f6\uff0c\u6240\u4ee5\u5b83\u53ea\u80fd\u628a\u5206\u6790\u5dee\u5f02\u7684\u64cd\u4f5c\uff0c\u653e\u5230<strong>\u7f16\u8bd1\u65f6<\/strong>\u8fdb\u884c\uff0c\u540c\u6837\u56e0\u4e3a\u7701\u7565\u4e86\u8fd0\u884c\u65f6\uff0c\u6240\u4ee5\u901f\u5ea6\u53ef\u80fd\u4f1a\u66f4\u5feb\u3002\u4f46\u662f\u8fd9\u79cd\u65b9\u5f0f\u8fd9\u5c06\u635f\u5931\u7075\u6d3b\u6027\u3002\u6bd4\u5982 svelte\uff0c\u5b83\u5c31\u662f\u4e00\u4e2a\u7eaf\u7f16\u8bd1\u65f6\u7684\u6846\u67b6\uff0c\u4f46\u662f\u5b83\u7684\u5b9e\u9645\u8fd0\u884c\u901f\u5ea6\u53ef\u80fd\u8fbe\u4e0d\u5230\u7406\u8bba\u4e0a\u7684\u901f\u5ea6\u3002<\/li>\n<li>3.<strong>\u8fd0\u884c\u65f6+\u7f16\u8bd1\u65f6<\/strong>:\u6bd4\u5982 vue \u6216 react \u90fd\u662f\u901a\u8fc7\u8fd9\u79cd\u65b9\u5f0f\u6765\u8fdb\u884c\u6784\u5efa\u7684\uff0c\u4f7f\u5176\u53ef\u4ee5\u5728\u4fdd\u6301\u7075\u6d3b\u6027\u7684\u57fa\u7840\u4e0a\uff0c\u5c3d\u91cf\u7684\u8fdb\u884c\u6027\u80fd\u7684\u4f18\u5316\uff0c\u4ece\u800c\u8fbe\u5230\u4e00\u79cd\u5e73\u8861\u3002<\/li>\n<\/ul>\n<h2>\u4ec0\u4e48\u662f\u526f\u4f5c\u7528?<\/h2>\n<p>\u526f\u4f5c\u7528\u4f1a\u6709\u591a\u4e2a\u5417? \u4f1a\u7684<br \/>\n<img data-original=\"https:\/\/blog.odjbinail.cn\/wp-content\/uploads\/2026\/02\/2026020123113529.png\"  alt=\"\" \/><br \/>\n<noscript><img decoding=\"async\" src=\"https:\/\/blog.odjbinail.cn\/wp-content\/uploads\/2026\/02\/2026020123113529.png\" alt=\"\" \/><br \/><\/noscript>\n<img data-original=\"https:\/\/blog.odjbinail.cn\/wp-content\/uploads\/2026\/02\/2026020123140650.png\"  alt=\"\" \/> <\/p>\n<noscript><img decoding=\"async\" src=\"https:\/\/blog.odjbinail.cn\/wp-content\/uploads\/2026\/02\/2026020123140650.png\" alt=\"\" \/> <\/p><\/noscript>\n<h2>vue3 \u5bf9 ts \u652f\u6301\u53cb\u597d, \u5e76\u4e0d\u662f\u56e0\u4e3a vue3 \u662f ts \u7f16\u5199\u7684<\/h2>\n<h1>\u642d\u5efa\u6846\u67b6\u96cf\u5f62<\/h1>\n<p><img data-original=\"https:\/\/blog.odjbinail.cn\/wp-content\/uploads\/2026\/02\/2026020214552428.png\"  alt=\"\" \/><\/p>\n<noscript><img decoding=\"async\" src=\"https:\/\/blog.odjbinail.cn\/wp-content\/uploads\/2026\/02\/2026020214552428.png\" alt=\"\" \/><\/p><\/noscript>\n<h2>\u4e3a vue \u5f00\u542f sourceMap \u7528\u4e8e debugger<\/h2>\n<ul>\n<li>package.json \u4e2d build \u547d\u4ee4\u52a0-s<br \/>\n&quot;build&quot;: &quot;node scripts\/build.js -s &quot;,<\/li>\n<\/ul>\n<h2>\u5bfc\u5165 ts, prettier<\/h2>\n<p>npm install -g typescript@4.7.4<br \/>\nnpm install --save-dev prettier<\/p>\n<h2>\u6a21\u5757\u6253\u5305\u5668: rollup<\/h2>\n<ul>\n<li>rollup \u662f\u4e00\u4e2a\u6a21\u5757\u6253\u5305\u5668\uff0c\u548c webpack \u4e00\u6837\u53ef\u4ee5\u5c06 JavaScript \u6253\u5305\u4e3a\u6307\u5b9a\u7684\u6a21\u5757\u3002<\/li>\n<li>\u4f46\u662f\u4e0d\u540c\u7684\u662f\uff0c\u5bf9\u4e8e webpack \u800c\u8a00\uff0c\u5b83\u5728\u6253\u5305\u7684\u65f6\u5019\u4f1a\u4ea7\u751f\u8bb8\u591a<strong>\u5197\u4f59\u7684\u4ee3\u7801<\/strong>\uff0c\u8fd9\u6837\u7684\u4e00\u79cd\u60c5\u51b5\u5728\u6211\u4eec\u5f00\u53d1\u5927\u578b\u9879\u76ee\u7684\u65f6\u5019\u6ca1\u6709\u4ec0\u4e48\u5f71\u54cd\uff0c\u4f46\u662f\u5982\u679c\u6211\u4eec\u662f\u5f00\u53d1\u4e00\u4e2a<strong>\u5e93<\/strong>\u7684\u65f6\u5019\uff0c\u90a3\u4e48\u8fd9\u4e9b\u5197\u4f59\u7684\u4ee3\u7801\u5c31\u4f1a\u5927\u5927\u589e\u52a0\u5e93\u4f53\u79ef\uff0c\u8fd9\u5c31\u4e0d\u597d\u7f8e\u597d\u4e86\u3002<\/li>\n<li>\u6240\u4ee5\u8bf4\u6211\u4eec\u9700\u8981\u4e00\u4e2a<strong>\u5c0f\u800c\u7f8e<\/strong>\u7684\u6a21\u5757\u6253\u5305\u5668\uff0c\u8fd9\u5c31\u662f rollup:<\/li>\n<\/ul>\n<pre class=\"prettyprint linenums\" ><code>Rollup \u662f\u4e00\u4e2a JavaScript \u6a21\u5757\u6253\u5305\u5668\uff0c\u53ef\u4ee5\u5c06\u5c0f\u5757\u4ee3\u7801\u7f16\u8bd1\u6210\u5927\u5757\u590d\u6742\u7684\u4ee3\u7801\uff0c\u4f8b\u5982 library \u6216\u5e94\u7528\u7a0b\u5e8f\u3002<\/code><\/pre>\n<ul>\n<li>\n<p>\u5b89\u88c5\u63d2\u4ef6:<br \/>\nnpm i -D @rollup\/plugin-commonjs@22.0.1 @rollup\/plugin-node-resolve@13.3.0 @rollup\/plugin-typescript@8.3.4 <\/p>\n<p>npm i --save-dev tslib@2.4.0 typescript@4.7.4<\/p>\n<\/li>\n<\/ul>\n<h2>\u914d\u7f6e\u8def\u5f84\u6620\u5c04<\/h2>\n<ul>\n<li>tsconfig.json<\/li>\n<\/ul>\n<pre class=\"prettyprint linenums\" ><code> \/\/ \u8bbe\u7f6e\u5feb\u6377\u5bfc\u5165\n    &quot;baseUrl&quot;: &quot;.&quot;,\n    &quot;paths&quot;: {\n      &quot;@vue\/*&quot;: [&quot;packages\/*\/src&quot;]\n    }<\/code><\/pre>\n<h1>\u54cd\u5e94\u7cfb\u7edf<\/h1>\n<h2>\u54cd\u5e94\u7cfb\u7edf\u7684\u6838\u5fc3\u8bbe\u8ba1\u539f\u5219<\/h2>\n<ul>\n<li><strong> \u4f1a\u5f71\u54cd\u89c6\u56fe\u53d8\u5316\u7684\u6570\u636e\u79f0\u4e3a\u54cd\u5e94\u6570\u636e<\/strong>,\u5f53\u54cd\u5e94\u5f0f\u6570\u636e\u53d1\u751f\u53d8\u5316\u65f6, \u89c6\u56fe\u7406\u5e94\u53d1\u751f\u53d8\u5316<\/li>\n<li>\u63d0\u51fa\u95ee\u9898:\n<ul>\n<li>\u90a3\u4e48 Vue \u4e2d\u8fd9\u6837\u7684\u54cd\u5e94\u6027\u6570\u636e\u662f\u5982\u4f55\u8fdb\u884c\u5b9e\u73b0\u7684\u5462?<\/li>\n<li>Vue2 \u548c Vue3 \u4e4b\u95f4\u54cd\u5e94\u6027\u7684\u8bbe\u8ba1\u6709\u4ec0\u4e48\u53d8\u5316\u5417? \u4e3a\u4ec0\u4e48\u4f1a \u4ea7\u751f\u8fd9\u79cd\u53d8\u5316\u5462?<\/li>\n<\/ul>\n<\/li>\n<\/ul>\n<h3>1.JS \u7684\u7a0b\u5e8f\u6027<\/h3>\n<ul>\n<li>JS \u7684\u7a0b\u5e8f\u6027\u662f<strong>\u4e00\u5957\u56fa\u5b9a\u7684, \u4e0d\u4f1a\u53d1\u751f\u53d8\u5316\u7684\u6267\u884c\u6d41\u7a0b, <\/strong> <\/li>\n<li>\u5728\u8fd9\u6837\u7684\u4e00\u4e2a\u7a0b\u5e8f\u6027\u4e4b\u4e0b, \u6211\u4eec\u4e0d\u53ef\u4ee5\u62ff\u5230\u60f3\u8981\u7684 50, \u60f3\u8981\u7a0b\u5e8f\u53d8\u806a\u660e\u5c31\u9700\u8981\u5177\u5907<strong>\u54cd\u5e94\u6027<\/strong><\/li>\n<\/ul>\n<pre class=\"prettyprint linenums\" ><code>  &lt;script&gt;\n      \/\/\u5b9a\u4e49\u4e00\u4e2a\u5546\u54c1\u5bf9\u8c61\n      let product = {\n        price: 10,\n        quantity: 2,\n      };\n      \/\/\u603b\u4ef7\u683c\n      let total = product.price * product.quantity;\n      console.log(&quot;\u603b\u4ef7\u683c:&quot;, total);\/\/20\n      \/\/\u4fee\u6539\u5546\u54c1\u7684\u6570\u91cf\n      product.quantity = 5;\n      console.log(&quot;\u603b\u4ef7\u683c:&quot;, total);\/\/20? \u4e3a\u5565\u4e0d\u662f 50\n    &lt;\/script&gt;<\/code><\/pre>\n<h3>2.\u521d\u6b65\u54cd\u5e94\u6027<\/h3>\n<ul>\n<li>\u5b58\u5728\u95ee\u9898: \u5fc5\u987b\u4e3b\u52a8\u5728\u6570\u91cf\u53d1\u751f\u53d8\u5316\u4e4b\u540e, \u91cd\u65b0\u4e3b\u52a8\u6267\u884c effect \u624d\u53ef\u4ee5\u5f97\u5230\u6211\u4eec\u60f3\u8981\u7684\u7ed3\u679c, \u90a3\u4e48\u8fd9\u6837\u592a\u9ebb\u70e6\u4e86<\/li>\n<\/ul>\n<pre class=\"prettyprint linenums\" ><code>    &lt;script&gt;\n      \/\/\u5b9a\u4e49\u4e00\u4e2a\u5546\u54c1\u5bf9\u8c61\n      let product = {\n        price: 10,\n        quantity: 2,\n      };\n      \/\/\u603b\u4ef7\u683c\n      let total = 0;\n      \/\/\u8ba1\u7b97\u603b\u4ef7\u683c\n      let effect = () =&gt; {\n        total = product.price * product.quantity;\n      };\n      effect();\n      console.log(&quot;\u603b\u4ef7\u683c:&quot;, total); \/\/20\n      \/\/\u4fee\u6539\u5546\u54c1\u7684\u6570\u91cf\n      product.quantity = 5;\n      effect();\n      console.log(&quot;\u603b\u4ef7\u683c:&quot;, total); \/\/20\n    &lt;\/script&gt;<\/code><\/pre>\n<h3>3.\u4f7f\u7528 Vue2 \u7684 Object.defineProperty<\/h3>\n<ul>\n<li>\u4f1a\u76f4\u63a5\u5728\u4e00\u4e2a\u5bf9\u8c61\u5b9a\u4e49\u4e00\u4e2a\u65b0\u5c5e\u6027, \u6216\u8005\u4fee\u6539\u4e00\u4e2a\u5bf9\u8c61\u7684\u73b0\u6709\u5c5e\u6027, \u5e76\u8fd4\u56de\u6b64\u5bf9\u8c61<\/li>\n<\/ul>\n<pre class=\"prettyprint linenums\" ><code> &lt;script&gt;\n      \/\/\u5b9a\u4e49\u4e00\u4e2a\u5546\u54c1\u5bf9\u8c61\n      let quantity = 2;\n      let product = {\n        price: 10,\n        quantity: quantity,\n      };\n      \/\/\u603b\u4ef7\u683c\n      let total = 0;\n      \/\/\u8ba1\u7b97\u603b\u4ef7\u683c\n      let effect = () =&gt; {\n        total = product.price * product.quantity;\n      };\n      \/\/\u7b2c\u4e00\u6b21\u6253\u5370\n      effect();\n      console.log(&quot;\u603b\u4ef7\u683c:&quot;, total); \/\/20\n\n      Object.defineProperty(product, &quot;quantity&quot;, {\n        set(newVal) {\n          console.log(&quot;setter&quot;);\n          quantity=newVal\n          effect()\n        },\n        get() {\n          console.log(&quot;getter&quot;);\n          return quantity\n        },\n      });\n    &lt;\/script&gt;<\/code><\/pre>\n<h4>\u5b58\u5728\u4e00\u4e2a\u81f4\u547d\u7684\u7f3a\u9677<\/h4>\n<p><a href=\"https:\/\/v2.cn.vuejs.org\/v2\/guide\/reactivity.html#%E6%A3%80%E6%B5%8B%E5%8F%98%E5%8C%96%E7%9A%84%E6%B3%A8%E6%84%8F%E4%BA%8B%E9%A1%B9\" title=\"vue2 \u5b98\u7f51\u5b58\u5728\u8fd9\u6837\u4e00\u6bb5\u63cf\u8ff0\">vue2 \u5b98\u7f51\u5b58\u5728\u8fd9\u6837\u4e00\u6bb5\u63cf\u8ff0<\/a><\/p>\n<p><strong>\u7531\u4e8e JavaScript \u7684\u9650\u5236\uff0cVue2 \u4e0d\u80fd\u68c0\u6d4b\u6570\u7ec4\u548c\u5bf9\u8c61\u7684\u53d8\u5316\u3002<\/strong>\u5c3d\u7ba1\u5982\u6b64\u6211\u4eec\u8fd8\u662f\u6709\u4e00\u4e9b\u529e\u6cd5\u6765\u56de\u907f\u8fd9\u4e9b\u9650\u5236\u5e76\u4fdd\u8bc1\u5b83\u4eec\u7684\u54cd\u5e94\u6027\u3002<\/p>\n<p>vue2 \u6709\u4ee5\u4e0b\u54cd\u5e94\u6027\u7684\u9650\u5236: <\/p>\n<ul>\n<li>\u5f53\u4e3a <strong>\u5bf9\u8c61 <\/strong>\u65b0\u589e\u4e00\u4e2a\u6ca1\u6709\u5728 data \u4e2d\u58f0\u660e\u7684\u5c5e\u6027\u65f6\uff0c\u65b0\u589e\u7684\u5c5e\u6027 <strong>\u4e0d\u662f\u54cd\u5e94\u6027\u7684<\/strong><\/li>\n<li>\u5f53\u4e3a <strong>\u6570\u7ec4 <\/strong>\u901a\u8fc7\u4e0b\u6807\u7684\u5f62\u5f0f\u65b0\u589e\u4e00\u4e2a\u5143\u7d20\u65f6\uff0c\u65b0\u589e\u7684\u5143\u7d20<strong>\u4e0d\u662f\u54cd\u5e94\u6027\u7684<\/strong><\/li>\n<\/ul>\n<p>\u60f3\u8981\u641e\u660e\u767d\u8fd9\u4e2a\u539f\u56e0\uff0c\u90a3\u5c31\u9700\u8981\u660e\u767d\u5b98\u7f51\u6240\u8bf4\u7684\u7531\u4e8e JavaScript \u7684\u9650\u5236\u6307\u7684\u662f\u4ec0\u4e48\u610f\u601d\u3002<\/p>\n<p>\u6211\u4eec\u77e5\u9053:<\/p>\n<ul>\n<li>1.vue2 \u662f\u4ee5 Object.defineProperty \u4f5c\u4e3a\u6838\u5fc3 API \u5b9e\u73b0\u7684\u54cd\u5e94\u6027<\/li>\n<li>2.<strong>Object.defineProperty \u53ea\u53ef\u4ee5\u76d1\u542c \u6307\u5b9a\u5bf9\u8c61 \u7684\u6307\u5b9a\u5c5e\u6027\u7684 getter \u548c setter<\/strong><\/li>\n<li>3.\u88ab\u76d1\u542c\u4e86 getter \u548c setter \u7684\u5c5e\u6027, \u5c31\u88ab\u53eb\u505a \u8be5\u5c5e\u6027\u5177\u5907\u4e86\u54cd\u5e94\u6027<\/li>\n<\/ul>\n<p>\u90a3\u4e48\u8fd9\u5c31\u610f\u5473\u7740\uff1a\u6211\u4eec <strong>\u5fc5\u987b\u8981\u77e5\u9053\u6307\u5b9a\u5bf9\u8c61\u4e2d\u5b58\u5728\u8be5\u5c5e\u6027<\/strong>\uff0c\u624d\u53ef\u4ee5\u4e3a\u8be5\u5c5e\u6027\u6307\u5b9a\u54cd\u5e94\u6027\u3002<\/p>\n<p>\u4f46\u662f <strong>\u7531\u4e8e JavaScript \u7684\u9650\u5236<\/strong>\uff0c\u6211\u4eec\u6ca1\u6709\u529e\u6cd5\u76d1\u542c\u5230  <strong>\u6307\u5b9a\u5bf9\u8c61\u65b0\u589e\u4e86\u4e00\u4e2a\u5c5e\u6027<\/strong>\uff0c\u6240\u4ee5\u65b0\u589e\u7684\u5c5e\u6027\u5c31\u6ca1\u6709\u529e\u6cd5\u901a\u8fc7 Object.defineProperty \u6765\u76d1\u542c getter \u548c setter\uff0c\u6240\u4ee5<strong>\u65b0\u589e\u7684\u5c5e\u6027\u5c06\u5931\u53bb\u54cd\u5e94\u6027<\/strong><br \/>\n\uff08\u90a3\u4e48\u5982\u679c\u60f3\u8981\u589e\u52a0\u5177\u5907\u54cd\u5e94\u6027\u7684\u65b0\u5c5e\u6027\uff0c\u90a3\u4e48\u53ef\u4ee5\u901a\u8fc7 Vue.set \u65b9\u6cd5\u5b9e\u73b0\uff09<\/p>\n<h2>Vue3 \u7684\u54cd\u5e94\u6027\u6838\u5fc3 API: proxy<\/h2>\n<p>Proxy \u548c Object.defineProperty \u5b58\u5728\u4e00\u4e2a\u975e\u5e38\u5927\u7684\u533a\u522b, \u90a3\u5c31\u662f:<\/p>\n<p>proxy<\/p>\n<ul>\n<li>1.proxy \u5c06\u4ee3\u7406\u4e00\u4e2a\u5bf9\u8c61\uff08\u88ab\u4ee3\u7406\u5bf9\u8c61\uff09\uff0c\u5f97\u5230\u4e00\u4e2a\u65b0\u7684\u5bf9\u8c61\uff08\u4ee3\u7406\u5bf9\u8c61\uff09\uff0c\u540c\u65f6\u62e5\u6709\u88ab\u4ee3\u7406\u5bf9\u8c61\u4e2d\u6240\u6709\u7684\u5c5e\u6027\u3002<\/li>\n<li>2.\u5f53\u60f3\u8981\u4fee\u6539\u5bf9\u8c61\u7684\u6307\u5b9a\u5c5e\u6027\u65f6,\u6211\u4eec\u5e94\u8be5\u4f7f\u7528<strong>\u4ee3\u7406\u5bf9\u8c61<\/strong>\u8fdb\u884c\u4fee\u6539<\/li>\n<li>3.<strong>\u4ee3\u7406\u5bf9\u8c61<\/strong>\u7684\u4efb\u4f55\u4e00\u4e2a\u5c5e\u6027\u90fd\u53ef\u4ee5\u89e6\u53d1 handler \u7684 getter \u548c setter<\/li>\n<\/ul>\n<p>Object.defineProperty<\/p>\n<ul>\n<li>1.Object.defineProperty \u4e3a <strong>\u6307\u5b9a\u5bf9\u8c61\u7684\u6307\u5b9a\u5c5e\u6027<\/strong> \u8bbe\u7f6e<strong>\u5c5e\u6027\u63cf\u8ff0\u7b26<\/strong><\/li>\n<li>2.\u5f53\u60f3\u8981\u4fee\u6539\u5bf9\u8c61\u7684\u6307\u5b9a\u5c5e\u6027\u65f6, \u53ef\u4ee5\u4f7f\u7528\u539f\u5bf9\u8c61\u8fdb\u884c\u4fee\u6539<\/li>\n<li>3.\u901a\u8fc7\u5c5e\u6027\u63cf\u8ff0\u7b26, \u53ea\u6709 <strong>\u88ab\u76d1\u542c<\/strong> \u7684\u6307\u5b9a\u5c5e\u6027, \u624d\u53ef\u4ee5\u89e6\u53d1 getter \u548c setter<\/li>\n<\/ul>\n<p>\u6240\u4ee5\u5f53 Vue3 \u901a\u8fc7 Proxy \u5b9e\u73b0\u54cd\u5e94\u6027\u6838\u5fc3 API \u4e4b\u540e, vue3 \u5c06 <strong>\u4e0d\u4f1a<\/strong> \u518d\u5b58\u5728\u65b0\u589e\u5c5e\u6027\u65f6\u5931\u53bb\u54cd\u5e94\u6027\u7684\u95ee\u9898<\/p>\n<pre class=\"prettyprint linenums\" ><code>   &lt;script&gt;\n      \/\/\u5b9a\u4e49\u4e00\u4e2a\u5546\u54c1\u5bf9\u8c61\n      let product = {\n        price: 10,\n        quantity: 2,\n      };\n      \/\/product: \u88ab\u4ee3\u7406\u5bf9\u8c61\n      \/\/proxyProduct: \u4ee3\u7406\u5bf9\u8c61 (\u53ea\u6709\u4ee3\u7406\u5bf9\u8c61\u624d\u4f1a\u89e6\u53d1 setter, getter)\n      const proxyProduct = new Proxy(product, {\n        set(target ,key, newVal,receiver) {\n          \/\/ console.log(target ,key, newVal,receiver);\n          \/\/ console.log(&quot;setter&quot;);\n          target[key]=newVal\n          effect()\n          return true\n        },\n        get(target ,key, receiver) {\n          \/\/ console.log(target ,key, receiver,);\n          \/\/ console.log(&quot;getter&quot;);\n          return target[key]\n        },\n      });\n\n      \/\/\u603b\u4ef7\u683c\n      let total = 0;\n      \/\/\u8ba1\u7b97\u603b\u4ef7\u683c\n      let effect = () =&gt; {\n        total = proxyProduct.price * proxyProduct.quantity;\n      };\n      effect();\n      console.log(&quot;\u603b\u4ef7\u683c:&quot;, total); \/\/20\n    &lt;\/script&gt;<\/code><\/pre>\n<p><img data-original=\"https:\/\/blog.odjbinail.cn\/wp-content\/uploads\/2026\/02\/2026020222275218.png\"  alt=\"\" \/><\/p>\n<noscript><img decoding=\"async\" src=\"https:\/\/blog.odjbinail.cn\/wp-content\/uploads\/2026\/02\/2026020222275218.png\" alt=\"\" \/><\/p><\/noscript>\n<h3>proxy \u7684\u6700\u4f73\u62cd\u6863\uff1aReflect---\u62e6\u622a js \u5bf9\u8c61\u64cd\u4f5c<\/h3>\n<ul>\n<li>&quot;\u4f34\u751f\u5bf9\u8c61&quot; : <a href=\"https:\/\/developer.mozilla.org\/zh-CN\/docs\/Web\/JavaScript\/Reference\/Global_Objects\/Reflect\" title=\"reflect\">Reflect<\/a><\/li>\n<\/ul>\n<p>Reflect \u5c5e\u6027, \u591a\u6570\u65f6\u5019\u4f1a\u4e0e proxy \u914d\u5408\u8fdb\u884c\u4f7f\u7528\u5728 MDN  Proxy \u7684\u4f8b\u5b50\u4e2d, Reflect \u4e5f\u6709\u5bf9\u6b64\u51fa\u73b0\u3002<\/p>\n<pre class=\"prettyprint linenums\" ><code>      const odj = {\n        name: &quot;\u5f20&quot;,\n      };\n      console.log(obj.name)\/\/\u5f20\u4e09\n      console.log(Reflect.get(obj,&#039;name&#039;))\/\/\u5f20\u4e09<\/code><\/pre>\n<p>\u7531\u4ee5\u4e0a\u4ee3\u7801\u53ef\u4ee5\u53d1\u73b0\uff0c\u4e24\u6b21\u6253\u5370\u7684\u7ed3\u679c\u662f\u76f8\u540c\u7684\u3002\u8fd9\u5176\u5b9e\u4e5f\u5c31\u8bf4\u660e\u4e86<br \/>\nReflect.get(obj,'name')  \u672c\u8d28\u4e0a \u548c obj.name \u7684\u4f5c\u7528\u76f8\u540c\u3002<\/p>\n<p>\u90a3\u4e3a\u5565\u8fd8\u9700\u8981 Reflect \u5462? \u5176\u8fd8\u6709\u7b2c\u4e09\u4e2a\u53c2\u6570 receiver, \u5b98\u7f51\u4ecb\u7ecd\uff1a<strong>\u5982\u679c target \u5bf9\u8c61\u4e2d\u6307\u5b9a\u4e86 getter\uff0creceiver \u5219\u4e3a getter \u8c03\u7528\u65f6\u7684 this \u503c\u3002<\/strong>\uff08Reflect \u53ef\u4ee5\u4fee\u6539 this \u6307\u5411\uff09<\/p>\n<pre class=\"prettyprint linenums\" ><code>    &lt;script&gt;\n      const p1 = {\n        lastName: &quot;\u5f20&quot;,\n        firstName: &quot;\u4e09&quot;,\n        \/\/\u901a\u8fc7 get \u6807\u8bc6\u7b26\u6807\u8bb0, \u53ef\u4ee5\u8ba9\u65b9\u6cd5\u7684\u8c03\u7528\u50cf\u5c5e\u6027\u7684\u8c03\u7528\u4e00\u6837\n        get fullName() {\n          return this.lastName + this.firstName;\n        },\n      };\n\n      const p2 = {\n        lastName: &quot;\u674e&quot;,\n        firstName: &quot;\u56db&quot;,\n        get fullName() {\n          return this.lastName + this.firstName; \/\/  \u2193---\u89e6\u53d1 2 \u6b21\n        },\n      };\n      \/**\n       * \u7b2c\u4e09\u4e2a\u53c2\u6570 receiver \u5728\u5bf9\u8c61\u6307\u5b9a\u4e86 getter \u65f6\u8868\u793a\u4e3a this\n       * \u5229\u7528 p2 \u4f5c\u4e3a\u7b2c\u4e09\u4e2a\u53c2\u6570 receiver, \u4ee5\u6b64\u6765\u4fee\u6539 fullName \u7684\u6253\u5370\u7ed3\u679c\u3002\n       * \u5373\uff1a\u6b64\u65f6\u89e6\u53d1\u7684 fullName \u4e0d\u662f p1 \u7684\u800c\u662f p2 \u7684\n       * *\/\n      console.log(Reflect.get(p1, &quot;name&quot;, p2)); \/\/\u674e\u56db\n\n      const proxy = new Proxy(p1, {\n        \/\/target:\u88ab\u4ee3\u7406\u5bf9\u8c61    receiver:\u4ee3\u7406\u5bf9\u8c61\n        get(target, key, receiver) {\n          console.log(&quot;getter \u884c\u4e3a\u88ab\u89e6\u53d1&quot;);\n          \/\/ return target[key];\/\/1 \u6b21\n          return Reflect.get(target, key, receiver); \/\/\u89e6\u53d1 3 \u6b21\n        },\n      });\n      console.log(proxy.fullName); \/\/\u5f20\u4e09  ---\u2191\u89e6\u53d1 1 \u6b21\n      \/\/\u601d\u8003:\u4f7f\u7528 return target[key]; getter \u884c\u4e3a\u5e94\u8be5\u88ab\u89e6\u53d1\u51e0\u6b21? 3 \u6b21, \u5b9e\u9645\u89e6\u53d1\u4e00\u6b21\n    &lt;\/script&gt;<\/code><\/pre>\n<h4>\u603b\u7ed3<\/h4>\n<p>\u5f53\u6211\u4eec\u671f\u671b\u76d1\u542c\u4ee3\u7406\u5bf9\u8c61\u7684 getter \u548c setter \u65f6, <strong>\u4e0d\u5e94\u8be5\u4f7f\u7528 target[key]<\/strong>, \u56e0\u4e3a\u5b83\u5728\u67d0\u4e9b\u65f6\u523b(\u6bd4\u5982 fullName) \u4e0b\u662f\u4e0d\u53ef\u9760\u7684\u3002\u5e94\u8be5\u4f7f\u7528 Reflect, \u501f\u52a9\u5b83\u7684 get \u548c set \u65b9\u6cd5, \u4f7f\u7528 receiver ( proxy \u5b9e\u4f8b ) \u4f5c\u4e3a this, \u5df2\u8fbe\u5230\u671f\u671b\u7684\u7ed3\u679c\uff08\u89e6\u53d1\u4e09\u6b21 getter\uff09<\/p>\n<h2>\u521d\u89c1 reactivity \u6a21\u5757<\/h2>\n<h3>\u9605\u8bfb\u6e90\u7801????<\/h3>\n<h3>\u6784\u5efa reactive \u51fd\u6570, \u83b7\u53d6 proxy \u5b9e\u4f8b<\/h3>\n<ul>\n<li>\u6574\u4e2a reactive \u51fd\u6570\uff0c\u672c\u8d28\u4e0a\u662f\u8fd4\u56de\u4e86\u4e00\u4e2a proxy \u5b9e\u4f8b<br \/>\n1.\u521b\u5efa packages\/reactivity\/src\/reactive.ts \u6a21\u5757<\/li>\n<\/ul>\n<pre class=\"prettyprint linenums\" ><code>import { mutableHandlers } from &#039;.\/baseHandlers&#039;\n\n\/**\n * \u54cd\u5e94\u6027 Map \u7f13\u5b58\u5bf9\u8c61\n * key:target\n * val:proxy\n *\/\nexport const reactiveMap = new WeakMap&lt;object, any&gt;()\n\n\/**\n * \u4e3a\u590d\u6742\u6570\u636e\u7c7b\u578b, \u521b\u5efa\u54cd\u5e94\u5f0f\u5bf9\u8c61\n * @param target \u88ab\u4ee3\u7406\u7684\u5bf9\u8c61\n * @returns \u4ee3\u7406\u5bf9\u8c61\n *\/\nexport function reactive(target: object) {\n  return createReactiveObject(target, mutableHandlers, reactiveMap)\n}\n\n\/**\n * \u521b\u5efa\u54cd\u5e94\u5f0f\u5bf9\u8c61\n * @param target \u88ab\u4ee3\u7406\u5bf9\u8c61\n * @param baseHandlers handler\n * @param proxyMap\n *\/\nfunction createReactiveObject(\n  target: object,\n  baseHandlers: ProxyHandler&lt;any&gt;,\n  proxyMap: WeakMap&lt;object, any&gt;\n) {\n  \/\/\u5982\u679c\u8be5\u5b9e\u4f8b\u5df2\u7ecf\u88ab\u4ee3\u7406, \u5219\u76f4\u63a5\u8bfb\u53d6\u5373\u53ef\n  const existingProxy = proxyMap.get(target)\n  if (existingProxy) {\n    return existingProxy\n  }\n  \/\/\u672a\u88ab\u4ee3\u7406\u5219\u751f\u6210 proxy \u5b9e\u4f8b\n  const proxy = new Proxy(target, baseHandlers)\n\n  \/\/\u7f13\u5b58\u4ee3\u7406\u5bf9\u8c61\n  proxyMap.set(target, proxy)\n  return proxy\n}\n<\/code><\/pre>\n<p>2.\u521b\u5efa packages\/reactivity\/src\/baseHandlers.ts<\/p>\n<pre class=\"prettyprint linenums\" ><code>\/**\n * \u54cd\u5e94\u6027\u7684 handler\n *\/\nexport const mutableHandlers: ProxyHandler&lt;object&gt; = {}<\/code><\/pre>\n<p>3.\u521b\u5efa packages\/reactivity\/src\/index.ts ,\u4f5c\u4e3a reactivity \u7684\u5165\u53e3\u6a21\u5757<\/p>\n<pre class=\"prettyprint linenums\" ><code>export { reactive } from &#039;.\/reactive&#039;<\/code><\/pre>\n<p>4.\u521b\u5efa packages\/vue\/src\/index.ts ,\u5bfc\u5165 reactivity \u6a21\u5757<\/p>\n<pre class=\"prettyprint linenums\" ><code>export { reactive } from &#039;@vue\/reactivity&#039;<\/code><\/pre>\n<p>5.\u6267\u884c build \u6253\u5305, \u751f\u6210 vue.js<br \/>\n6.\u521b\u5efa\u6d4b\u8bd5\u7528\u4f8b<\/p>\n<h3>WeakMap \u548c Map \u6709\u4ec0\u4e48\u533a\u522b?<\/h3>\n<p>\u6838\u5fc3\u5171\u540c\u70b9\uff1a\u90fd\u662f{key,value}\u7684\u7ed3\u6784\u5bf9\u8c61<\/p>\n<p>\u5bf9\u4e8e WeakMap \u800c\u8a00,<\/p>\n<ul>\n<li>key \u5fc5\u987b\u662f\u5bf9\u8c61<\/li>\n<li>key \u662f\u5f31\u5f15\u7528\u7684<\/li>\n<\/ul>\n<p>\u5f31\u5f15\u7528\uff1a\u4e0d\u4f1a\u5f71\u54cd\u5783\u573e\u56de\u6536\u673a\u5236\u3002\u5373\uff1aWeakMap \u7684 key <strong>\u4e0d\u518d\u5b58\u5728\u4efb\u4f55\u5f15\u7528\u65f6<\/strong>, \u4f1a\u88ab\u76f4\u63a5\u56de\u6536<br \/>\n\u5f3a\u5f15\u7528\uff1a\u4f1a\u5f71\u54cd\u5783\u573e\u56de\u6536\u673a\u5236\u3002\u5b58\u5728\u5f3a\u5e94\u7528\u7684\u5bf9\u8c61\u6c38\u8fdc<strong>\u4e0d\u4f1a<\/strong>\u88ab\u56de\u6536<\/p>\n<h3>\u521b\u5efa createGettter \u548c createSetter<\/h3>\n<p>packages\/reactivity\/src\/baseHandlers.ts<\/p>\n<pre class=\"prettyprint linenums\" ><code>\/**\n * \u54cd\u5e94\u6027\u7684 handler\n *\/\nimport { track, trigger } from &#039;.\/effect&#039;\n\nconst get = createGetter()\nfunction createGetter() {\n  return function get(target: object, key: string | symbol, receiver: object) {\n    const res = Reflect.get(target, key, receiver)\n    track(target, key)\n    return res\n  }\n}\n\nconst set = createSetter()\nfunction createSetter() {\n  return function set(\n    target: object,\n    key: string | symbol,\n    value: unknown,\n    receiver: object\n  ) {\n    const result = Reflect.set(target, key, value, receiver)\n    trigger(target, key, value)\n    return result\n  }\n}\n\nexport const mutableHandlers: ProxyHandler&lt;object&gt; = {\n  get,\n  set\n}<\/code><\/pre>\n<h3>\u8bbe\u7f6e\u70ed\u66f4\u65b0<\/h3>\n<p>&quot;dev&quot;: &quot;rollup -c -w&quot;,<\/p>\n<h3>\u6784\u5efa effect \u51fd\u6570, \u751f\u6210 ReactiveEffect<\/h3>\n<pre class=\"prettyprint linenums\" ><code>export function effect&lt;T = any&gt;(fn: () =&gt; T) {\n  const _effect = new ReactiveEffect(fn)\n  _effect.run()\n}\n\nexport let activeEffect: ReactiveEffect | undefined\n\nexport class ReactiveEffect&lt;T = any&gt; {\n  constructor(public fn: () =&gt; T) {}\n  run() {\n   \/\/\u5f53\u524d\u88ab\u6fc0\u6d3b\u7684 effect \u5b9e\u4f8b\n    activeEffect = this\n    return this.fn() \/\/\u5b8c\u6210\u7b2c\u4e00\u6b21 getter \u884c\u4e3a\u7684\u89e6\u53d1\n  }\n}<\/code><\/pre>\n<ul>\n<li>\u6210\u529f\u6e32\u67d3\u4e86\u6570\u636e\u5230 html \u4e2d<\/li>\n<\/ul>\n<pre class=\"prettyprint linenums\" ><code>&lt;body&gt;\n&lt;div id=&quot;app&quot;&gt;&lt;\/div&gt;\n&lt;\/body&gt;\n&lt;script&gt;\n    const { reactive,effect } = Vue\n    const obj=reactive({\n        name:&#039;\u5f20\u4e09&#039;\n    })\n    effect(()=&gt;{\n        document.querySelector(&#039;#app&#039;).innerText=obj.name\n    })\n&lt;\/script&gt;<\/code><\/pre>\n<h3>track \u548c trigger<\/h3>\n<p>\u7531 baseHandlers.ts \u4e2d\u4ee3\u7801\u53ef\u77e5: \u5f53\u89e6\u53d1 getter \u884c\u4e3a\u65f6, \u5176\u5b9e\u6211\u4eec\u4f1a\u89e6\u53d1 track \u65b9\u6cd5, \u8fdb\u884c<strong>\u4f9d\u8d56\u6536\u96c6<\/strong>, \u5f53\u89e6\u53d1 setter \u884c\u4e3a\u65f6, \u4f1a\u89e6\u53d1 trigger \u65b9\u6cd5, \u6765<strong>\u89e6\u53d1\u4f9d\u8d56<\/strong><\/p>\n<ul>\n<li>\u54cd\u5e94\u6027\u6307\u7684\u662f: \u5f53\u54cd\u5e94\u6027\u6570\u636e\u89e6\u53d1 setter \u65f6\u6267\u884c fn \u51fd\u6570, <\/li>\n<li>\u60f3\u8981\u8fbe\u5230\u8fd9\u6837\u7684\u76ee\u7684, \u5c31\u5fc5\u987b\u5728<strong>getter \u65f6\u80fd\u591f\u6536\u96c6\u5f53\u524d\u7684 fn \u51fd\u6570<\/strong>, \u4ee5\u4fbf setter \u7684\u65f6\u5019\u53ef\u4ee5\u6267\u884c\u5bf9\u5e94\u7684 fn \u51fd\u6570<\/li>\n<\/ul>\n<p>\u4f46\u662f\u5bf9\u4e8e\u6536\u96c6\u800c\u8a00, \u5982\u679c\u4ec5\u4ec5\u662f\u628a fn \u5b58\u8d77\u6765\u8fd8\u662f\u4e0d\u591f\u7684, \u6211\u4eec\u8fd8\u9700\u8981\u77e5\u9053, \u5f53\u524d\u7684\u8fd9\u4e2a fn \u662f<strong>\u54ea\u4e2a\u54cd\u5e94\u5f0f\u6570\u636e\u5bf9\u8c61<\/strong>\u7684<strong>\u54ea\u4e2a\u5c5e\u6027<\/strong>\u5bf9\u5e94\u7684, \u53ea\u6709\u8fd9\u6837, \u6211\u4eec\u624d\u53ef\u4ee5\u5728 <strong>\u8be5\u5c5e\u6027<\/strong>\u89e6\u53d1 setter \u7684\u65f6\u5019, \u51c6\u786e\u7684\u6267\u884c\u54cd\u5e94\u6027<\/p>\n<h4>\u5982\u4f55\u8fdb\u884c\u4f9d\u8d56\u6536\u96c6<\/h4>\n<p>WeakMap :<br \/>\nkey: \u54cd\u5e94\u6027\u5bf9\u8c61<br \/>\nvalue: Map \u5bf9\u8c61<br \/>\nkey: \u54cd\u5e94\u6027\u5bf9\u8c61\u7684\u6307\u5b9a\u5c5e\u6027<br \/>\nvalue:\u6307\u5b9a\u5bf9\u8c61\u7684\u6307\u5b9a\u5c5e\u6027\u7684\u6267\u884c\u51fd\u6570<\/p>\n<p><img data-original=\"https:\/\/blog.odjbinail.cn\/wp-content\/uploads\/2026\/02\/2026020322555426.png\"  alt=\"\" \/><\/p>\n<noscript><img decoding=\"async\" src=\"https:\/\/blog.odjbinail.cn\/wp-content\/uploads\/2026\/02\/2026020322555426.png\" alt=\"\" \/><\/p><\/noscript>\n<pre class=\"prettyprint linenums\" ><code>\/\/effect.ts\ntype KeyToDepMap = Map&lt;any, ReactiveEffect&gt;\n\/**\n * \u6536\u96c6\u6240\u6709\u4f9d\u8d56\u7684 WeakMap \u5b9e\u4f8b\n * key: \u54cd\u5e94\u6027\u5bf9\u8c61\n * value: Map \u5bf9\u8c61\n *    key: \u54cd\u5e94\u6027\u5bf9\u8c61\u7684\u6307\u5b9a\u5c5e\u6027\n *      value:\u6307\u5b9a\u5bf9\u8c61\u7684\u6307\u5b9a\u5c5e\u6027\u7684\u6267\u884c\u51fd\u6570\n *\/\nconst targetMap = new WeakMap&lt;any, KeyToDepMap&gt;()\n\n\/**\n * \u6536\u96c6\u4f9d\u8d56\n * @param target WeakMap \u7684 key\n * @param key key \u4ee3\u7406\u5bf9\u8c61\u7684 key, \u5f53\u4f9d\u8d56\u88ab\u89e6\u53d1\u65f6,\u9700\u8981\u6839\u636e\u8be5 key \u83b7\u53d6\n *\/\nexport function track(target: object, key: unknown) {\n  if (!activeEffect) return\n  \/\/\u5c1d\u8bd5\u4ece targetMap \u4e2d, \u6839\u636e target \u83b7\u53d6 map\n  let depsMap = targetMap.get(target)\n  \/\/\u5982\u679c\u83b7\u53d6\u5230\u7684 map \u4e0d\u5b58\u5728,\u5219\u751f\u6210\u65b0\u7684 map \u5bf9\u8c61, \u5e76\u628a\u8be5\u5bf9\u8c61\u8d4b\u503c\u7ed9\u5bf9\u5e94\u7684 value\n  if (!depsMap) {\n    targetMap.set(target, (depsMap = new Map()))\n  }\n  \/\/\u4e3a\u6307\u5b9a map, \u6307\u5b9a key, \u8bbe\u7f6e\u56de\u8c03\u51fd\u6570\n  depsMap.set(key, activeEffect)\n  console.log(targetMap)\n}<\/code><\/pre>\n<p><img data-original=\"https:\/\/blog.odjbinail.cn\/wp-content\/uploads\/2026\/02\/20260203230849100.png\"  alt=\"\" \/><\/p>\n<noscript><img decoding=\"async\" src=\"https:\/\/blog.odjbinail.cn\/wp-content\/uploads\/2026\/02\/20260203230849100.png\" alt=\"\" \/><\/p><\/noscript>\n<h4>trigger \u89e6\u53d1\u4f9d\u8d56<\/h4>\n<pre class=\"prettyprint linenums\" ><code>\/**\n * \u89e6\u53d1\u4f9d\u8d56\n * @param target WeakMap \u7684 key\n * @param key key \u4ee3\u7406\u5bf9\u8c61\u7684 key, \u5f53\u4f9d\u8d56\u88ab\u89e6\u53d1\u65f6,\u9700\u8981\u6839\u636e\u8be5 key \u83b7\u53d6\n *\/\nexport function trigger(target: object, key: unknown, newValue: unknown) {\n  \/\/\u4f9d\u636e target \u83b7\u53d6\u5b58\u50a8\u7684 map \u5b9e\u4f8b\n  const depsMap = targetMap.get(target)\n  if (!depsMap) {\n    return\n  }\n  \/\/\u4f9d\u636e key, \u4ece depsMap \u4e2d\u53d6\u51fa value, \u8be5 value \u662f\u4e00\u4e2a ReactiveEffect \u7c7b\u578b\u7684\u6570\u636e\n  const effect = depsMap.get(key) as ReactiveEffect\n  if (!effect) {\n    return\n  }\n  \/\/\u6267\u884c effect \u4e2d\u4fdd\u5b58\u7684 fn \u51fd\u6570\n  effect.fn()\n}<\/code><\/pre>\n<ul>\n<li>\u8fd9\u6837\u5c31\u53ef\u4ee5\u89e6\u53d1 setter \u65f6, \u6267\u884c\u4fdd\u5b58\u7684 fn \u51fd\u6570\u4e86<\/li>\n<\/ul>\n<h3>\u6784\u5efa Dep \u6a21\u5757, \u5904\u7406\u4e00\u5bf9\u591a\u7684\u4f9d\u8d56\u5173\u7cfb<\/h3>\n<pre class=\"prettyprint linenums\" ><code> &lt;div id=&quot;app&quot;&gt;\n    &lt;p id=&quot;p1&quot;&gt;&lt;\/p&gt;\n    &lt;p id=&quot;p2&quot;&gt;&lt;\/p&gt;\n&lt;\/div&gt;\n effect(()=&gt;{\n    document.querySelector(&#039;#p1&#039;).innerText=obj.name\n    })\n    effect(()=&gt;{\n    document.querySelector(&#039;#p2&#039;).innerText=obj.name\n    })<\/code><\/pre>\n<p>name \u5c5e\u6027\u5bf9\u5e94\u4e24\u4e2a DOM \u7684\u53d8\u5316, \u4f46\u662f p1 \u7684\u66f4\u65b0\u6e32\u67d3\u662f\u65e0\u6548\u7684<br \/>\n\u6211\u4eec\u671f\u671b: \u4e00\u4e2a key \u53ef\u4ee5\u5bf9\u5e94\u591a\u4e2a\u6709\u6548\u7684 effect \u51fd\u6570\u7684\u8bdd, \u5e94\u8be5\u53ef\u4ee5\u6784\u5efa\u4e00\u4e2a Set \u7c7b\u578b\u7684\u5bf9\u8c61, \u4f5c\u4e3a Map \u7684 value<\/p>\n<h4>reactive('\u5f20\u4e09')\u4e0d\u80fd\u63a5\u6536\u7b80\u5355\u6570\u636e\u7c7b\u578b<\/h4>\n<p><img data-original=\"https:\/\/blog.odjbinail.cn\/wp-content\/uploads\/2026\/02\/2026020517010190.png\"  alt=\"\" \/><\/p>\n<noscript><img decoding=\"async\" src=\"https:\/\/blog.odjbinail.cn\/wp-content\/uploads\/2026\/02\/2026020517010190.png\" alt=\"\" \/><\/p><\/noscript>\n<ul>\n<li>\u5bf9\u4e8e\u6211\u4eec reactive \u7684 effect \u800c\u8a00, \u6700\u7ec8\u751f\u6210\u4e00\u4e2a proxy \u5b9e\u4f8b, \u5176\u4e2d\u7b2c\u4e00\u4e2a\u53c2\u6570\u5fc5\u987b\u662f\u4e00\u4e2a\u5bf9\u8c61(\u88ab\u4ee3\u7406\u5bf9\u8c61), \u5982\u679c\u662f\u7b80\u5355\u6570\u636e\u7c7b\u578b, \u662f\u6ca1\u6cd5\u4ee3\u7406\u7684<\/li>\n<\/ul>\n<h3>\u5bf9 reactive \u7684\u5c5e\u6027\u8fdb\u884c\u89e3\u6784, \u4e0d\u4f1a\u5177\u5907\u54cd\u5e94\u6027<\/h3>\n<pre class=\"prettyprint linenums\" ><code>&lt;script&gt;\n    const { reactive,effect } = Vue\n    const obj=reactive({\n        name:&#039;\u5f20\u4e09&#039;\n    })\n    let {name}=obj\n    console.log(&#039;name&#039;,name);\n\n    effect(()=&gt;{\n        document.querySelector(&#039;#app&#039;).innerText=name\n    })\n    setTimeout(()=&gt;{\n        obj.name=&#039;\u674e\u56db&#039;\n\n    console.log(&#039;obj&#039;,obj);\n    },2000)\n&lt;\/script&gt;<\/code><\/pre>\n<h2>reactive \u603b\u7ed3<\/h2>\n<p>\u5bf9\u4e8e reactive \u7684\u54cd\u5e94\u6027\u51fd\u6570\u800c\u8a00, <\/p>\n<ul>\n<li>1.\u662f\u901a\u8fc7 proxy \u7684 setter \u548c getter \u6765\u5b9e\u73b0\u7684\u6570\u636e\u76d1\u542c<\/li>\n<li>2.\u9700\u8981\u914d\u5408 effect \u51fd\u6570\u8fdb\u884c\u4f7f\u7528<\/li>\n<li>3.\u57fa\u4e8e WeakMap \u5b8c\u6210\u7684\u4f9d\u8d56\u6536\u96c6\u548c\u5904\u7406<\/li>\n<li>4.\u53ef\u4ee5\u5b58\u5728\u4e00\u5bf9\u591a\u7684\u4f9d\u8d56\u5173\u7cfb<\/li>\n<\/ul>\n<p>\u540c\u65f6\u6211\u4eec\u4e5f\u4e86\u89e3\u4e86 reactive \u51fd\u6570\u7684\u4e0d\u8db3:<\/p>\n<ul>\n<li>1.reactive \u53ea\u80fd\u5bf9<strong>\u590d\u6742\u6570\u636e<\/strong>\u7c7b\u578b\u8fdb\u884c\u4f7f\u7528<\/li>\n<li>2.reactive \u7684\u54cd\u5e94\u6027\u6570\u636e\uff0c\u4e0d\u53ef\u4ee5\u8fdb\u884c\u89e3\u6784<\/li>\n<\/ul>\n<p>\u56e0\u4e3a reactive \u7684\u4e0d\u8db3\uff0c\u6240\u4ee5 vue3 \u53c8\u4e3a\u6211\u4eec\u63d0\u4f9b\u4e86 ref \u51fd\u6570\u6784\u5efa\u54cd\u5e94\u6027\uff0c\u90a3\u4e48:<\/p>\n<ul>\n<li>1.ref \u51fd\u6570\u7684\u5185\u5bb9\u662f\u5982\u4f55\u8fdb\u884c\u5b9e\u73b0\u7684\u5462?<\/li>\n<li>2.ref \u53ef\u4ee5\u6784\u5efa\u7b80\u5355\u6570\u636e\u7c7b\u578b\u7684\u54cd\u5e94\u6027\u5417?<\/li>\n<li>3.\u4e3a\u4ec0\u4e48 ref \u7c7b\u578b\u7684\u6570\u636e\uff0c\u5fc5\u987b\u8981\u901a\u8fc7.value \u8bbf\u95ee\u503c\u5462?<\/li>\n<\/ul>\n<h2>ref \u7684\u54cd\u5e94\u6027<\/h2>\n<p>\u5982\u679c ref \u4f20\u9012\u8fc7\u6765\u7684 value \u662f\u4e00\u4e2a\u5bf9\u8c61, \u90a3\u4e48\u5f53\u524d ref \u7684\u54cd\u5e94\u6027\u672c\u8d28\u4e0a\u662f\u901a\u8fc7 reactive \u5b9e\u73b0\u7684; \u5982\u679c\u4e0d\u662f\u5bf9\u8c61, \u5219\u539f\u6837\u5c06 value \u8fd4\u56de<\/p>\n<h3>\u6e90\u7801\u9605\u8bfb<\/h3>\n<p><img data-original=\"https:\/\/blog.odjbinail.cn\/wp-content\/uploads\/2026\/02\/2026020521183580.png\"  alt=\"\" \/><br \/>\n<noscript><img decoding=\"async\" src=\"https:\/\/blog.odjbinail.cn\/wp-content\/uploads\/2026\/02\/2026020521183580.png\" alt=\"\" \/><br \/><\/noscript>\n<img decoding=\"async\" src=\"https:\/\/blog.odjbinail.cn\/wp-content\/uploads\/2026\/02\/2026020521194047.png\" alt=\"\" \/><img data-original=\"https:\/\/blog.odjbinail.cn\/wp-content\/uploads\/2026\/02\/2026020521222717.png\"  alt=\"\" \/><\/p>\n<noscript><img decoding=\"async\" src=\"https:\/\/blog.odjbinail.cn\/wp-content\/uploads\/2026\/02\/2026020521194047.png\" alt=\"\" \/><img decoding=\"async\" src=\"https:\/\/blog.odjbinail.cn\/wp-content\/uploads\/2026\/02\/2026020521222717.png\" alt=\"\" \/><\/p><\/noscript>\n<p><img data-original=\"https:\/\/blog.odjbinail.cn\/wp-content\/uploads\/2026\/02\/2026020521265022.png\"  alt=\"\" \/><\/p>\n<noscript><img decoding=\"async\" src=\"https:\/\/blog.odjbinail.cn\/wp-content\/uploads\/2026\/02\/2026020521265022.png\" alt=\"\" \/><\/p><\/noscript>\n<h3>\u6784\u5efa ref \u7b80\u5355\u6570\u636e\u7c7b\u578b\u54cd\u5e94\u6027<\/h3>\n<p>\u8be6\u60c5\u770b\u4ee3\u7801\u5b9e\u73b0<\/p>\n<pre class=\"prettyprint linenums\" ><code>class RefImpl&lt;T&gt; {\n  private _value: T\n  private _rawValue: T\n  ...\n  constructor(\n    value: T,\n    public readonly __v_isShallow: boolean\n  ) {\n  ...\n    \/\/\u539f\u59cb\u6570\u636e\n    this._rawValue = value\n  }\n...\n  \/**\n   * newValue \u65b0\u6570\u636e\n   * this._rawValue \u4e3a\u65e7\u6570\u636e(\u539f\u59cb\u6570\u636e)\n   * \u5bf9\u6bd4\u4e24\u4e2a\u6570\u636e\u662f\u5426\u53d1\u751f\u6539\u53d8\n   *\/\n  set value(newValue) {\n    if (hasChanged(newValue, this._rawValue)) {\n      \/\/\u66f4\u65b0\u539f\u59cb\u6570\u636e\n      this._rawValue = newValue\n      \/\/\u66f4\u65b0 .value \u7684\u503c\n      this._value = toReactive(newValue)\n      \/\/\u89e6\u53d1\u4f9d\u8d56\n      triggerRefValue(this)\n    }\n  }\n}\n\/\/\u4e3a ref \u7684 value \u8fdb\u884c\u89e6\u53d1\u4f9d\u8d56\u5de5\u4f5c\nexport function triggerRefValue(ref) {\n  if (ref.dep) {\n    triggerEffects(ref.dep)\n  }\n}<\/code><\/pre>\n<ul>\n<li>2.\u5728 packages\/shared\/src\/index.ts \u4e2d,\u65b0\u589e hasChanged \u65b9\u6cd5<\/li>\n<\/ul>\n<pre class=\"prettyprint linenums\" ><code>\/**\n * \u5bf9\u6bd4\u4e24\u4e2a\u6570\u636e\u662f\u5426\u53d1\u751f\u6539\u53d8, \u5982\u679c\u53d1\u751f\u6539\u53d8\u5219\u8fd4\u56de true\n *\/\nexport const hasChanged = (value: any, oldValue: any): boolean =&gt;\n  !Object.is(value, oldValue)<\/code><\/pre>\n<h2>ref \u603b\u7ed3<\/h2>\n<ul>\n<li>\n<p>\u7b80\u5355\u6570\u636e\u7c7b\u578b, <strong>\u4e0d\u5177\u5907\u6570\u636e\u76d1\u542c<\/strong>\u7684\u6982\u5ff5, \u5373\u672c\u8eab\u5e76\u4e0d\u662f\u54cd\u5e94\u6027\u7684\u3002\u53ea\u662f\u56e0\u4e3a vue \u901a\u8fc7\u4e86 set value()\u7684\u8bed\u6cd5\uff0c\u628a \u51fd\u6570\u8c03\u7528\u53d8\u6210\u4e86\u5c5e\u6027\u8c03\u7528\u7684\u5f62\u5f0f\uff0c\u8ba9\u6211\u4eec\u901a\u8fc7\u4e3b\u52a8\u8c03\u7528\u8be5\u51fd\u6570\uff0c \u6765\u5b8c\u6210\u4e86\u4e00\u4e2a\u201c\u7c7b\u4f3c\u4e8e\u201d\u54cd\u5e94\u6027\u7684\u7ed3\u679c\u3002<\/p>\n<\/li>\n<li>\n<p>1.ref \u51fd\u6570\u7684\u5185\u5bb9\u662f\u5982\u4f55\u8fdb\u884c\u5b9e\u73b0\u7684\u5462?<br \/>\n\u7b54\uff1aref \u51fd\u6570\u672c\u8d28\u4e0a\u662f\u751f\u6210\u4e86\u4e00\u4e2a RefImpl \u7c7b\u578b\u7684\u5b9e\u4f8b\u5bf9\u8c61\uff0c\u901a\u8fc7 get \u548c set \u6807\u8bb0\u5904\u7406\u4e86 value \u51fd\u6570<\/p>\n<\/li>\n<li>\n<p>2.ref \u53ef\u4ee5\u6784\u5efa\u7b80\u5355\u6570\u636e\u7c7b\u578b\u7684\u54cd\u5e94\u6027\u5417?<br \/>\n\u7b54\uff1a\u662f\u7684\u3002ref \u53ef\u4ee5\u6784\u5efa\u7b80\u5355\u6570\u636e\u7c7b\u578b\u7684\u54cd\u5e94\u6027<\/p>\n<\/li>\n<li>\n<p>3.\u4e3a\u4ec0\u4e48 ref \u7c7b\u578b\u7684\u6570\u636e\uff0c\u5fc5\u987b\u8981\u901a\u8fc7.value \u8bbf\u95ee\u503c\u5462?<br \/>\n\u7b54\uff1a1.\u56e0\u4e3a ref \u9700\u8981\u5904\u7406\u7b80\u5355\u6570\u636e\u7c7b\u578b\u7684\u54cd\u5e94\u6027, \u4f46\u662f\u5bf9\u4e8e\u7b80\u5355\u6570\u636e\u7c7b\u578b\u800c\u8a00\uff0c\u5b83\u65e0\u6cd5\u901a\u8fc7 proxy \u5efa\u7acb\u4ee3\u7406\u3002<br \/>\n2.\u6240\u4ee5 vue \u901a\u8fc7 get value()\u548c set value()\u5b9a\u4e49\u4e86\u4e24\u4e2a\u5c5e\u6027\u51fd\u6570\uff0c\u901a\u8fc7<strong>\u4e3b\u52a8\u89e6\u53d1<\/strong>\u8fd9\u4e24\u4e2a\u51fd\u6570\uff08\u5c5e\u6027\u8c03\u7528\uff09\u7684\u5f62\u5f0f\u6765\u8fdb\u884c<strong>\u4f9d\u8d56\u6536\u96c6<\/strong>\u548c<strong>\u89e6\u53d1\u4f9d\u8d56<\/strong><br \/>\n3.\u6240\u4ee5\u6211\u4eec\u5fc5\u987b\u901a\u8fc7.value \u6765\u4fdd\u8bc1\u54cd\u5e94\u6027<\/p>\n<\/li>\n<\/ul>\n<h2>watch \u548c computed  \u3010\u590d\u6742\uff01\uff01\uff01\u3011<\/h2>\n<h3>\u8ba1\u7b97\u5c5e\u6027 computed<\/h3>\n<ul>\n<li>\u4f1a<strong>\u57fa\u4e8e\u5176\u54cd\u5e94\u5f0f\u4f9d\u8d56\u88ab\u7f13\u5b58<\/strong>\uff0c\u5e76\u4e14\u5728\u4f9d\u8d56\u7684\u54cd\u5e94\u5f0f\u6570\u636e\u53d1\u751f\u53d8\u5316\u65f6 <strong>\u91cd\u65b0\u8ba1\u7b97<\/strong><\/li>\n<\/ul>\n<pre class=\"prettyprint linenums\" ><code>&lt;script&gt;\n  const { reactive,effect,computed } = Vue\n  const obj=reactive({\n    name:&#039;\u5f20\u4e09&#039;\n  })\n  const computedObj= computed(()=&gt;{\n    return &#039;\u59d3\u540d:&#039;+obj.name\n  })\n  effect(()=&gt;{\n    document.querySelector(&#039;#app&#039;).innerText=computedObj.value\n  })\n  setTimeout(()=&gt;{\n    obj.name=&#039;\u674e\u56db&#039;\n  },2000)\n&lt;\/script&gt;<\/code><\/pre>\n<p>\u5728\u4ee5\u4e0a\u6d4b\u8bd5\u5b9e\u4f8b\u4e2d\uff0c\u7a0b\u5e8f\u4e3b\u8981\u6267\u884c\u4e86 5 \u4e2a\u6b65\u9aa4\uff1a<\/p>\n<ul>\n<li>1.\u4f7f\u7528 reactive \u521b\u5efa\u54cd\u5e94\u6027\u6570\u636e<\/li>\n<li>2.\u901a\u8fc7 computed \u521b\u5efa\u8ba1\u7b97\u5c5e\u6027 computedObj\uff0c\u5e76\u4e14\u89e6\u53d1\u4e86 obj \u7684 getter<\/li>\n<li>3.\u901a\u8fc7 effect \u65b9\u6cd5\u521b\u5efa fn \u51fd\u6570<\/li>\n<li>4.\u5728 fn \u51fd\u6570\u4e2d, \u89e6\u53d1\u4e86 computed \u7684 getter<\/li>\n<li>5.\u5ef6\u8fdf\u89e6\u53d1\u4e86 obj \u7684 setter<\/li>\n<\/ul>\n<p>computed \u7684\u4ee3\u7801\u5728 packages\/reactivity\/src\/computed.ts \u4e2d, \u6211\u4eec\u53ef\u4ee5\u5728\u8fd9\u91cc\u4e3a computed \u51fd\u6570\u589e\u52a0\u65ad\u70b9.<\/p>\n<ul>\n<li>\n<p>1.\u4ee3\u7801\u8fdb\u5165 computed \u51fd\u6570<\/p>\n<\/li>\n<li>\n<p>2.\u6267\u884c const onlyGetter=isFunction(getterOrOptions)\u65b9\u6cd5:<\/p>\n<ul>\n<li>getterOrOptions \u4e3a\u4f20\u5165\u7684\u7b2c\u4e00\u4e2a\u53c2\u6570, \u56e0\u4e3a\u6211\u4eec\u4f20\u5165\u7684\u4e3a\u51fd\u6570, \u6240\u4ee5 onlyGetter=true<\/li>\n<\/ul>\n<\/li>\n<li>\n<p>3.\u6267\u884c: getter=getterOrOptions, \u5373: getter \u4e3a\u6211\u4eec\u4f20\u5165\u7684\u51fd\u6570<\/p>\n<\/li>\n<li>\n<p>4.\u6267\u884c: setter=NOOP, NOOP \u4e3a()=&gt;{}<\/p>\n<\/li>\n<li>\n<p>5.\u6267\u884c: new ComputedRefImpl\uff0c<strong>\u521b\u5efa ComputedRefImpl \u5b9e\u4f8b<\/strong>\u3002 \u90a3\u4e48\u8fd9\u91cc\u7684 ComputedRefImpl \u662f\u4ec0\u4e48\u5462?<\/p>\n<\/li>\n<li>\n<p>6.\u8fdb\u5165 ComputedRefImpl<\/p>\n<ul>\n<li>\n<p>a.\u5728\u6784\u9020\u51fd\u6570\u4e2d\uff0c\u53ef\u4ee5\u770b\u5230: <strong>\u521b\u5efa\u4e86 ReactiveEffect \u5b9e\u4f8b<\/strong>\uff0c\u5e76\u4e14\u4f20\u5165\u4e86\u4e24\u4e2a\u53c2\u6570:<\/p>\n<pre class=\"prettyprint linenums\" ><code>\/\/1.getter:\u89e6\u53d1 computed \u51fd\u6570\u65f6\uff0c\u4f20\u5165\u7684\u7b2c\u4e00\u4e2a\u53c2\u6570\n\/\/2.\u533f\u540d\u51fd\u6570: \u5f53 this._dirty \u4e3a false \u65f6\uff0c\u4f1a\u89e6\u53d1 triggerRefValue\uff0c\u6211\u4eec\u77e5\u9053 triggerRefValue \u4f1a **\u4f9d\u6b21\u89e6\u53d1\u4f9d\u8d56**\n()=&gt;{\n\/\/_dirty \u8868\u793a&quot;\u810f&quot;\u7684\u610f\u601d, \u8fd9\u91cc\u53ef\u4ee5\u7406\u89e3\u4e3a: \u4f9d\u8d56\u7684\u54cd\u5e94\u6027\u6570\u636e\u53d1\u751f\u4e86\u53d8\u5316, \u8ba1\u7b97\u5c5e\u6027\u9700\u8981\u91cd\u65b0\u8ba1\u7b97\u4e86\nif(!this._dirty){\n    this._dirty=true\n    triggerRefValue(this)\n}\n}<\/code><\/pre>\n<\/li>\n<li>\n<p>b.\u800c\u5bf9\u4e8e ReactiveEffect \u800c\u8a00\uff0c<\/p>\n<ul>\n<li>1.\u5b83\u4f4d\u4e8e packages\/reactivity\/src\/effect.ts \u6587\u4ef6\u4e2d<\/li>\n<li>2.\u63d0\u4f9b\u4e86\u4e00\u4e2a run \u65b9\u6cd5\u548c\u4e00\u4e2a stop \u65b9\u6cd5:<br \/>\nrun \u65b9\u6cd5: \u89e6\u53d1 fn, \u5373\u4f20\u5165\u7684\u7b2c\u4e00\u4e2a\u53c2\u6570<br \/>\nstop \u65b9\u6cd5: \u8bed\u4e49\u4e0a\u4e3a\u505c\u6b62\u7684\u610f\u601d<\/li>\n<li>3.\u751f\u6210\u7684\u5b9e\u4f8b, \u6211\u4eec\u4e00\u822c\u53eb\u505a effect<\/li>\n<\/ul>\n<\/li>\n<li>\n<p>c.\u6267\u884c this.effect.computed=this, \u5373<strong>effect \u5b9e\u4f8b<\/strong> \u88ab\u6302\u8f7d\u4e86\u4e00\u4e2a\u65b0\u7684\u5c5e\u6027 computed \u4e3a\u5f53\u524d\u7684 ComputedRefImpl \u7684\u5b9e\u4f8b.<\/p>\n<\/li>\n<li>\n<p>d.ReactiveEffect<strong>\u6784\u9020\u51fd\u6570\u6267\u884c\u5b8c\u6210<\/strong><\/p>\n<\/li>\n<\/ul>\n<\/li>\n<li>\n<p>7.\u5728 computed \u4e2d\u8fd4\u56de\u4e86 ComputedRefImpl \u5b9e\u4f8b<\/p>\n<\/li>\n<\/ul>\n<p><strong>\u7531\u4ee5\u4e0a\u4ee3\u7801\u53ef\u77e5, \u5f53\u6211\u4eec\u5728\u6267\u884c computed \u51fd\u6570\u65f6:<\/strong><\/p>\n<ul>\n<li>1.\u5b9a\u4e49\u53d8\u91cf getter \u4e3a\u6211\u4eec\u4f20\u5165\u7684\u56de\u8c03\u51fd\u6570<\/li>\n<li>2.\u751f\u6210\u4e86 ComputedRefImpl \u5b9e\u4f8b, \u4f5c\u4e3a computed \u51fd\u6570\u7684\u8fd4\u56de\u503c<\/li>\n<li>3.ComputedRefImpl \u5185\u90e8, \u5229\u7528\u4e86 ReactiveEffect \u51fd\u6570, \u5e76\u4e14\u4f20\u5165\u4e86 <strong>\u7b2c\u4e8c\u4e2a\u53c2\u6570<\/strong><\/li>\n<\/ul>\n<h4>computed \u7684 getter<\/h4>\n<p>\u5f53 computed \u4ee3\u7801\u6267\u884c\u5b8c\u6210\u4e4b\u540e, \u6211\u4eec\u5728 effect \u4e2d\u89e6\u53d1\u4e86 computed \u7684 getter:<\/p>\n<pre class=\"prettyprint linenums\" ><code>computedObj.value<\/code><\/pre>\n<p>\u6839\u636e\u6211\u4eec\u4e4b\u524d\u5728\u5b66\u4e60 ref \u7684\u65f6\u5019\u53ef\u77e5\uff0c.value \u5c5e\u6027\u7684\u8c03\u7528\u672c\u8d28\u4e0a\u662f\u4e00\u4e2a<strong>get value \u7684\u51fd\u6570\u8c03\u7528<\/strong>\uff0c\u800c computedObj \u4f5c\u4e3a computed \u7684\u8fd4\u56de\u503c\uff0c\u672c\u8d28\u4e0a\u662f ComputedRefImpl \u7684\u5b9e\u4f8b\uff0c \u6240\u4ee5\u6b64\u65f6\u4f1a\u89e6\u53d1 ComputedRefImpl \u4e0b\u7684 get value \u51fd\u6570\u3002<\/p>\n<ul>\n<li>\n<p>1.\u8fdb\u5165 ComputedRefImpl \u4e0b\u7684 get value \u51fd\u6570<\/p>\n<\/li>\n<li>\n<p>2.\u6267\u884c trackRefValue(self)\uff0c\u8be5\u65b9\u6cd5\u6211\u4eec\u662f\u6709\u8fc7\u4e86\u89e3\u7684\uff0c\u77e5\u9053\u5b83\u7684\u4f5c\u7528\u662f: <strong>\u6536\u96c6\u4f9d\u8d56<\/strong>\uff0c\u5b83\u63a5\u6536\u4e2a ref \u4f5c\u4e3a\u53c2\u6570\uff0c\u8be5 ref \u672c\u8d28\u4e0a\u5c31\u662f ComputedRefImpl \u7684\u5b9e\u4f8b:<br \/>\n<img data-original=\"https:\/\/blog.odjbinail.cn\/wp-content\/uploads\/2026\/02\/2026020816470762.png\"  alt=\"\" \/><\/p>\n<noscript><img decoding=\"async\" src=\"https:\/\/blog.odjbinail.cn\/wp-content\/uploads\/2026\/02\/2026020816470762.png\" alt=\"\" \/><\/p><\/noscript>\n<\/li>\n<li>\n<p>3.\u6267\u884c self._dirty=false\uff0c\u6211\u4eec\u77e5\u9053 _dirty \u662f <strong>\u810f<\/strong> \u7684\u610f\u601d\uff0c\u5982\u679c _dirty = true \u5219\u4f1a<strong>\u89e6\u53d1\u6267\u884c\u4f9d\u8d56<\/strong>\u3002\u5728<strong>\u5f53\u524d(\u6807\u8bb0\u4e3a false \u4e4b\u524d)<\/strong>\uff0cself._dirty=true<\/p>\n<\/li>\n<li>\n<p>4.\u6240\u4ee5\u63a5\u4e0b\u6765\u6267\u884c self.effect.run()!\uff0c\u6267\u884c\u4e86 run \u65b9\u6cd5\uff0c\u6211\u4eec\u77e5\u9053 run \u65b9\u6cd5\u5185\u90e8\u5176\u5b9e\u4f1a\u89e6\u53d1 fn \u51fd\u6570\uff0c\u5373: <strong>computed \u63a5\u6536\u7684\u7b2c\u4e00\u4e2a\u53c2\u6570<\/strong><\/p>\n<\/li>\n<li>\n<p>5.\u63a5\u4e0b\u6765\u628a self._value = self.effect.run()!, \u6b64\u65f6 self._value \u7684\u503c\u4e3a computed \u7b2c\u4e00\u4e2a\u53c2\u6570(fn \u51fd\u6570)\u7684\u8fd4\u56de\u503c\uff0c\u5373\u4e3a: <strong>\u8ba1\u7b97\u5c5e\u6027\u8ba1\u7b97\u4e4b\u540e\u7684\u503c<\/strong><\/p>\n<\/li>\n<li>\n<p>6.\u6700\u540e\u6267\u884c return self._value\uff0c\u8fd4\u56de\u8ba1\u7b97\u7684\u503c<\/p>\n<\/li>\n<\/ul>\n<p><strong>\u7531\u4ee5\u4e0a\u4ee3\u7801\u53ef\u77e5:<\/strong><\/p>\n<ul>\n<li>1.ComputedRefImpl \u5b9e\u4f8b\u672c\u8eab\u5c31\u6ca1\u6709 <strong>\u4ee3\u7406\u76d1\u542c<\/strong> , \u5b83\u672c\u8d28\u4e0a\u662f\u4e00\u4e2a get value \u548c set value \u7684\u89e6\u53d1<\/li>\n<li>2.\u5728\u6bcf\u4e00\u6b21 get value \u88ab\u89e6\u53d1\u65f6, \u90fd\u4f1a\u4e3b\u52a8\u89e6\u53d1\u4e00\u6b21 <strong>\u4f9d\u8d56\u6536\u96c6<\/strong><\/li>\n<li>3.\u6839\u636e _dirty \u548c _cacheable \u7684\u72b6\u6001\u5224\u65ad, \u662f\u5426\u9700\u8981\u89e6\u53d1 run \u51fd\u6570<\/li>\n<li>4.computed \u7684\u8fd4\u56de\u503c, \u5176\u5b9e\u662f run \u51fd\u6570\u6267\u884c\u4e4b\u540e\u7684\u8fd4\u56de\u503c<\/li>\n<\/ul>\n<h4>ReactiveEffect \u7684 scheduler<\/h4>\n<p>\u521d\u6b65\u5206\u6790\u5b8c\u6210\u4e86 computed \u7684\u6e90\u7801\u6267\u884c\u903b\u8f91, \u8fd8\u5b58\u5728\u4e00\u4e9b\u95ee\u9898\u3002<br \/>\n\u6211\u4eec\u77e5\u9053\u5bf9\u4e8e\u8ba1\u7b97\u5c5e\u6027\u800c\u8a00\uff0c \u5f53\u5b83\u4f9d\u8d56\u7684\u54cd\u5e94\u5f0f\u6570\u636e\u53d1\u751f\u53d8\u5316\u65f6\uff0c \u5b83\u5c06\u91cd\u65b0\u8ba1\u7b97\u3002\u6362\u53e5\u8bdd\u8bf4\uff1a<strong>\u5f53\u54cd\u5e94\u6027\u6570\u636e\u89e6\u53d1 setter \u65f6, \u8ba1\u7b97\u5c5e\u6027\u9700\u8981\u89e6\u53d1\u4f9d\u8d56.<\/strong><\/p>\n<p>\u5728\u4e0a\u9762\u7684\u4ee3\u7801\u4e2d\uff0c\u6211\u4eec\u77e5\u9053\uff0c\u5f53\u300a\u6bcf\u4e00\u6b21 getvalue \u88ab\u89e6\u53d1\u65f6\uff0c\u90fd\u4f1a\u4e3b\u52a8\u89e6\u53d1\u4e00\u6b21<strong>\u4f9d\u8d56\u6536\u96c6<\/strong>\u300b\uff0c\u4f46\u662f<strong>\u89e6\u53d1\u4f9d\u8d56<\/strong>\u7684\u5730\u65b9\u5728\u54ea\u5462?<\/p>\n<p>\u6839\u636e\u4ee5\u4e0a\u4ee3\u7801\u53ef\u77e5: \u5728 ComputedRefImpl \u7684\u6784\u9020\u51fd\u6570\u4e2d\uff0c\u6211\u4eec\u521b\u5efa\u4e86 ReactiveEffect \u5b9e\u4f8b\uff0c\u5e76\u4e14\u4f20\u9012\u4e86\u7b2c\u4e8c\u4e2a\u53c2\u6570\uff0c\u8be5\u53c2\u6570\u4e3a\u4e00\u4e2a\u56de\u8c03\u51fd\u6570\uff0c\u5728\u8fd9\u4e2a\u56de\u8c03\u51fd\u6570\u4e2d: \u6211\u4eec\u4f1a\u6839\u636e<strong>\u810f<\/strong>\u7684\u72b6\u6001\u6765\u6267\u884c triggerRefValue\uff0c\u5373<strong>\u89e6\u53d1\u4f9d\u8d56<\/strong>\uff0c\u91cd\u65b0\u8ba1\u7b97\u3002<\/p>\n<p>\u90a3\u4e48\u8fd9\u4e2a ReactiveEffect <strong>\u7b2c\u4e8c\u4e2a\u53c2\u6570<\/strong>\u662f\u4ec0\u4e48\u5462?\u5b83\u4f1a\u5728\u4ec0\u4e48\u65f6\u5019\u88ab\u89e6\u53d1\uff0c\u4ee5<strong>\u89e6\u53d1\u4f9d\u8d56<\/strong>\u5462?<\/p>\n<p><strong>\u6211\u4eec\u6765\u770b\u4e00\u4e0b:<\/strong><\/p>\n<ul>\n<li>1.\u8fdb\u5165 packages\/reactivity\/src\/effect.ts \u4e2d<\/li>\n<li>2.\u67e5\u770b ReactiveEffect \u7684\u6784\u9020\u51fd\u6570\uff0c\u53ef\u4ee5\u7b2c\u4e8c\u4e2a\u53c2\u6570\u4e3a scheduler<\/li>\n<li>3.scheduler \u8868\u793a \u8c03\u5ea6\u5668 \u7684\u610f\u601d, \u6211\u4eec\u67e5\u770b packages\/reactivity\/src\/effect.ts \u4e2d triggerEffect \u65b9\u6cd5, \u53ef\u4ee5\u53d1\u73b0\u8fd9\u91cc\u8fdb\u884c\u4e86\u8c03\u5ea6\u5668\u7684\u5224\u5b9a:\n<pre class=\"prettyprint linenums\" ><code>function triggerEffect(...){\n...\nif(effect.scheduler){\neffect.scheduler()\n}\n}<\/code><\/pre>\n<\/li>\n<\/ul>\n<p><strong>\u8ddf\u8e2a\u4ee3\u7801<\/strong><\/p>\n<p>\u6211\u4eec\u77e5\u9053<strong>\u5ef6\u8fdf\u4e24\u79d2\u4e4b\u540e<\/strong>\uff0c\u4f1a\u89e6\u53d1 obj.name<br \/>\n\u5373 reactive \u7684 setter \u884c\u4e3a.<br \/>\n\u6240\u4ee5\u6211\u4eec\u53ef\u4ee5\u5728<br \/>\npackaaes\/reactivity\/src\/baseHandlers.ts \u4e2d\u4e3a set \u589e\u52a0\u4e00\u4e2a\u65ad\u70b9:<\/p>\n<ul>\n<li>1.\u8fdb\u5165 reactive \u7684 setter (\u6ce8\u610f: \u8fd9\u91cc\u662f\u5ef6\u8fdf\u4e24\u79d2\u4e4b\u540e setter \u884c\u4e3a)<\/li>\n<li>2.\u8df3\u8fc7\u4e4b\u524d\u7684\u76f8\u540c\u903b\u8f91\u4e4b\u540e\uff0c\u53ef\u77e5\uff0c\u6700\u540e\u4f1a\u89e6\u53d1:trigger(target\uff0cTriggerOpTypes.SET\uff0ckey,<br \/>\nvalue,oldValue)\u65b9\u6cd5<\/li>\n<li>3.\u8fdb\u5165 trigger \u65b9\u6cd5:<\/li>\n<li>4.\u540c\u6837\u8df3\u8fc7\u4e4b\u524d\u76f8\u540c\u903b\u8f91\uff0c\u53ef\u77e5\uff0c\u6700\u540e\u4f1a\u89e6\u53d1:triggerEffects(deps[0]\uff0ceventInfo)\u65b9\u6cd5<\/li>\n<li>5.\u8fdb\u5165 triggerEffects \u65b9\u6cd5:<\/li>\n<li>6.<br \/>\n<img data-original=\"https:\/\/blog.odjbinail.cn\/wp-content\/uploads\/2026\/02\/2026020818480787.png\"  alt=\"\" \/><br \/>\n<noscript><img decoding=\"async\" src=\"https:\/\/blog.odjbinail.cn\/wp-content\/uploads\/2026\/02\/2026020818480787.png\" alt=\"\" \/><br \/><\/noscript>\n<img data-original=\"https:\/\/blog.odjbinail.cn\/wp-content\/uploads\/2026\/02\/2026020818482832.png\"  alt=\"\" \/><br \/>\n<noscript><img decoding=\"async\" src=\"https:\/\/blog.odjbinail.cn\/wp-content\/uploads\/2026\/02\/2026020818482832.png\" alt=\"\" \/><br \/><\/noscript>\n<img data-original=\"https:\/\/blog.odjbinail.cn\/wp-content\/uploads\/2026\/02\/2026020818484978.png\"  alt=\"\" \/><br \/>\n<noscript><img decoding=\"async\" src=\"https:\/\/blog.odjbinail.cn\/wp-content\/uploads\/2026\/02\/2026020818484978.png\" alt=\"\" \/><br \/><\/noscript>\n<img data-original=\"https:\/\/blog.odjbinail.cn\/wp-content\/uploads\/2026\/02\/202602081849327.png\"  alt=\"\" \/><\/li>\n<noscript><img decoding=\"async\" src=\"https:\/\/blog.odjbinail.cn\/wp-content\/uploads\/2026\/02\/202602081849327.png\" alt=\"\" \/><\/li><\/noscript>\n<\/ul>\n<h4>\u6784\u5efa ComputedRefImpl\uff0c\u8bfb\u53d6\u8ba1\u7b97\u5c5e\u6027<\/h4>\n<p>packages\/reactivity\/src\/computed.ts<\/p>\n<ul>\n<li>\u6784\u5efa ComputedRefImpl \u7c7b, \u521b\u5efa\u51fa computed \u65b9\u6cd5, \u5e76\u4e14\u80fd\u591f\u8bfb\u53d6\u503c<\/li>\n<\/ul>\n<h4>computed \u7684\u54cd\u5e94\u6027: \u521d\u89c1\u8c03\u5ea6\u5668, \u5904\u7406\u810f\u7684\u72b6\u6001<\/h4>\n<p>\u5982\u679c\u60f3\u8981\u5b9e\u73b0\u54cd\u5e94\u6027, \u5fc5\u987b\u5177\u5907\u4e24\u4e2a\u6761\u4ef6: <\/p>\n<ul>\n<li>1.\u6536\u96c6\u4f9d\u8d56: \u5df2\u5728 get value \u4e2d\u8fdb\u884c<\/li>\n<li>2.\u89e6\u53d1\u4f9d\u8d56: <\/li>\n<\/ul>\n<h5>\u8c03\u5ea6\u5668<\/h5>\n<ul>\n<li>\u8c03\u5ea6\u5668 scheduler \u662f\u4e00\u4e2a\u76f8\u5bf9\u6bd4\u8f83\u590d\u6742\u7684\u6982\u5ff5\uff0c\u5b83\u5728 computed \u548c watch \u4e2d\u90fd\u6709\u6d89\u53ca, \u4f46\u662f\u5728\u5f53\u524d\u7684 computed \u5b9e\u73b0\u4e2d, \u5b83\u7684\u4f5c\u7528\u8fd8\u7b97\u6bd4\u8f83\u6e05\u6670\u3002<\/li>\n<li>\u6240\u4ee5\u6839\u636e\u6211\u4eec\u79c9\u627f\u7684 <strong>\u6ca1\u6709\u4f7f\u7528\u5c31\u5f53\u505a\u4e0d\u5b58\u5728<\/strong> \u7684\u7406\u5ff5\uff0c\u6211\u4eec\u53ea\u9700\u8981\u641e\u6e05\u695a\uff0c\u5b83\u5728\u5f53\u524d\u7684\u4f5c\u7528\u5373\u53ef\u3002<\/li>\n<li>\u6b64\u65f6\u7684 scheduler \u5c31\u76f8\u5f53\u4e8e\u4e00\u4e2a<strong>\u56de\u8c03\u51fd\u6570<\/strong>.<\/li>\n<li>\u5728 triggerEffect \u53ea\u8981 effect \u5b58\u5728 scheduler\uff0c\u5219\u5c31\u4f1a\u6267\u884c\u8be5\u51fd\u6570\u3002<\/li>\n<\/ul>\n<h5>_dirty \u810f<\/h5>\n<p>\u5b83\u53ea\u662f\u4e00\u4e2a\u53d8\u91cf, \u6211\u4eec\u53ea\u9700\u8981\u77e5\u9053: <strong>\u5b83\u4e3a false \u65f6, \u8868\u793a\u9700\u8981\u89e6\u53d1\u4f9d\u8d56\u3002\u4e3a true \u65f6\u8868\u793a\u9700\u8981\u91cd\u65b0\u6267\u884c run \u65b9\u6cd5, \u83b7\u53d6\u6570\u636e<\/strong> \u5373\u53ef<\/p>\n<h4>computed \u7684\u7f13\u5b58\u6027<\/h4>\n<p>computed \u533a\u522b\u4e8e function \u6700\u5927\u7684\u5730\u65b9\u5c31\u662f: computed \u5177\u5907\u7f13\u5b58\uff0c\u5f53\u591a\u6b21\u89e6\u53d1\u8ba1\u7b97\u5b9e\u884c\u65f6\uff0c\u90a3\u4e48\u8ba1\u7b97\u5c5e\u6027\u53ea\u4f1a\u8ba1\u7b97\u4e00\u6b21<\/p>\n<h5><strong>\u6b7b\u5faa\u73af<\/strong> \u7684\u95ee\u9898<\/h5>\n<pre class=\"prettyprint linenums\" ><code>&lt;script&gt;\n  const { reactive,effect,computed } = Vue\n  const obj=reactive({\n    name:&#039;\u5f20\u4e09&#039;\n  })\n  const computedObj= computed(()=&gt;{\n    console.log(&#039;\u8ba1\u7b97\u5c5e\u6027\u6267\u884c&#039;)\n    return &#039;\u59d3\u540d:&#039;+obj.name\n  })\n  effect(()=&gt;{\n    document.querySelector(&#039;#app&#039;).innerText=computedObj.value\n    document.querySelector(&#039;#app&#039;).innerText=computedObj.value\n  })\n  setTimeout(()=&gt;{\n    obj.name=&#039;\u674e\u56db&#039;\n  },2000)\n&lt;\/script&gt;<\/code><\/pre>\n<p><img data-original=\"https:\/\/blog.odjbinail.cn\/wp-content\/uploads\/2026\/02\/2026020820374713.png\"  alt=\"\" \/><\/p>\n<noscript><img decoding=\"async\" src=\"https:\/\/blog.odjbinail.cn\/wp-content\/uploads\/2026\/02\/2026020820374713.png\" alt=\"\" \/><\/p><\/noscript>\n<p>\u8fd0\u884c\u5230\u6d4f\u89c8\u5668\uff0c\u51fa\u73b0\u4e86 <strong>\u6b7b\u5faa\u73af<\/strong> \u7684\u95ee\u9898<\/p>\n<p>\u8fd9\u4e2a\u6b7b\u5faa\u73af\u662f\u5728 \u5ef6\u8fdf\u4e24\u79d2\u540e \u51fa\u73b0\u7684\uff0c\u800c\u5ef6\u8fdf\u4e24\u79d2\u4e4b\u540e\u662f obj.name \u7684\u8c03\u7528, \u5373: reactive \u7684 getter \u884c\u4e3a\u88ab\u89e6\u53d1, \u4e5f\u5c31\u662f trigger \u65b9\u6cd5\u89e6\u53d1\u65f6:<\/p>\n<p>1.\u4e3a packages\/reactivity\/src\/effect.ts \u4e2d\u7684 trigger \u65b9\u6cd5\u589e\u52a0\u65ad\u70b9, \u5ef6\u8fdf\u4e24\u79d2\u4e4b\u540e\uff0c\u8fdb\u5165\u65ad\u70b9\uff1a<br \/>\n2.\u6b64\u65f6\u6267\u884c\u7684\u4ee3\u7801\u662f obj.name='\u674e\u56db', \u6240\u4ee5\u5728 target \u4e3a{name:'\u674e\u56db'}<br \/>\n3.\u4f46\u662f\u8981\u6ce8\u610f, \u6b64\u65f6 targetMap \u4e2d, \u5df2\u7ecf\u5728 \u6536\u96c6\u8fc7 effect \u4e86, \u6b64\u65f6\u7684 dep \u4e2d\u5305\u542b\u4e00\u4e2a\u8ba1\u7b97\u5c5e\u6027\u7684 effect: <\/p>\n<p><img data-original=\"https:\/\/blog.odjbinail.cn\/wp-content\/uploads\/2026\/02\/2026020821530335.png\"  alt=\"\" \/><br \/>\n<noscript><img decoding=\"async\" src=\"https:\/\/blog.odjbinail.cn\/wp-content\/uploads\/2026\/02\/2026020821530335.png\" alt=\"\" \/><br \/><\/noscript>\n4.\u8fdb\u5165\u5230 triggerEffects(dep)\u65b9\u6cd5<\/p>\n<p><img data-original=\"https:\/\/blog.odjbinail.cn\/wp-content\/uploads\/2026\/02\/2026020822122740.png\"  alt=\"\" \/><\/p>\n<noscript><img decoding=\"async\" src=\"https:\/\/blog.odjbinail.cn\/wp-content\/uploads\/2026\/02\/2026020822122740.png\" alt=\"\" \/><\/p><\/noscript>\n<h6><strong>\u6b7b\u5faa\u73af<\/strong> \u7684\u95ee\u9898---\u89e3\u51b3\u65b9\u6cd5<\/h6>\n<ul>\n<li>packages\/reactivity\/src\/effect.ts<\/li>\n<\/ul>\n<pre class=\"prettyprint linenums\" ><code>\/**\n * \u89e6\u53d1 dep \u4e2d\u4fdd\u5b58\u7684\u4f9d\u8d56\n * @param dep\n *\/\nexport function triggerEffects(dep: Dep) {\n  \/\/\u628a dep \u6784\u5efa\u4e3a\u4e00\u4e2a\u6570\u7ec4\n  const effects = isArray(dep) ? dep : [...dep]\n  \/\/\u4e0d\u518d\u4f9d\u6b21\u89e6\u53d1\u4f9d\u8d56\n  \/\/ for (const effect of effects) {\n  \/\/     triggerEffect(effect)\n  \/\/ }\n  \/\/\u800c\u662f\u5148\u89e6\u53d1\u6240\u6709\u7684\u8ba1\u7b97\u5c5e\u6027\u4f9d\u8d56, \u518d\u89e6\u53d1\u6240\u6709\u7684\u975e\u8ba1\u7b97\u5c5e\u6027\u4f9d\u8d56\n  for (const effect of effects) {\n    if (effect.computed) {\n      triggerEffect(effect)\n    }\n  }\n  for (const effect of effects) {\n    if (!effect.computed) {\n      triggerEffect(effect)\n    }\n  }\n}<\/code><\/pre>\n<p><img data-original=\"https:\/\/blog.odjbinail.cn\/wp-content\/uploads\/2026\/02\/2026020822304365.png\"  alt=\"\" \/><\/p>\n<noscript><img decoding=\"async\" src=\"https:\/\/blog.odjbinail.cn\/wp-content\/uploads\/2026\/02\/2026020822304365.png\" alt=\"\" \/><\/p><\/noscript>\n<h3>\u603b\u7ed3---\u8ba1\u7b97\u5c5e\u6027 computed<\/h3>\n<p>1.\u8ba1\u7b97\u5c5e\u6027\u7684\u5b9e\u4f8b\uff0c\u672c\u8d28\u4e0a\u662f\u4e00\u4e2a ComputedRefImpl \u7684\u5b9e\u4f8b<br \/>\n2.ComputedRefImpl \u4e2d\u901a\u8fc7 dirty \u53d8\u91cf\u6765\u63a7\u5236 run \u7684\u6267\u884c\u548c triggerRefValue \u7684\u89e6\u53d1<br \/>\n3.\u60f3\u8981\u8bbf\u95ee\u8ba1\u7b97\u5c5e\u6027\u7684\u503c\uff0c\u5fc5\u987b\u901a\u8fc7.value\uff0c\u56e0\u4e3a\u5b83\u5185\u90e8\u548c ref \u4e00\u6837\u662f\u901a\u8fc7 get value \u6765\u8fdb\u884c\u5b9e\u73b0\u7684<br \/>\n4.\u6bcf\u6b21.value \u65f6\u90fd\u4f1a\u89e6\u53d1 trackRefValue \u5373:\u6536\u96c6\u4f9d\u8d56<br \/>\n5.\u5728\u4f9d\u8d56\u89e6\u53d1\u65f6\uff0c\u9700\u8981\u8c28\u8bb0\uff0c\u5148\u89e6\u53d1 computed \u7684 effect\uff0c\u518d\u89e6\u53d1\u975e computed \u7684 effect<\/p>\n<h3>\u54cd\u5e94\u6027\u7684\u6570\u636e\u76d1\u542c\u5668 watch<\/h3>\n<p><a href=\"https:\/\/cn.vuejs.org\/guide\/essentials\/watchers.html\" title=\"vue \u5b98\u65b9\u6587\u6863\">vue \u5b98\u65b9\u6587\u6863<\/a><br \/>\nwatch \u53ef\u4ee5\u76d1\u542c\u54cd\u5e94\u5f0f\u6570\u636e\u7684\u53d8\u5316, \u4ece\u800c\u89e6\u53d1\u6307\u5b9a\u7684\u51fd\u6570<\/p>\n<ul>\n<li>\u6e90\u7801\u9605\u8bfb<\/li>\n<\/ul>\n<pre class=\"prettyprint linenums\" ><code>&lt;script&gt;\n  const { reactive,watch} =Vue\n  const obj=reactive({\n    name:&#039;\u5f20\u4e09&#039;\n  })\n\n  watch(obj,(value,oldValue)=&gt;{\n    document.querySelector(&#039;#app&#039;).innerHTML=obj.name\n  })\n  setTimeout(()=&gt;{\n    obj.name=&#039;\u674e\u56db&#039;\n  },2000)\n&lt;\/script&gt;<\/code><\/pre>\n<p><img data-original=\"https:\/\/blog.odjbinail.cn\/wp-content\/uploads\/2026\/02\/2026020916110876.png\"  alt=\"\" \/><\/p>\n<noscript><img decoding=\"async\" src=\"https:\/\/blog.odjbinail.cn\/wp-content\/uploads\/2026\/02\/2026020916110876.png\" alt=\"\" \/><\/p><\/noscript>\n<p><a href=\"https:\/\/developer.mozilla.org\/zh-CN\/docs\/Web\/API\/HTML_DOM_API\/Microtask_guide\" title=\"\u5f02\u6b65\u7684\u5fae\u4efb\u52a1\">\u5f02\u6b65\u7684\u5fae\u4efb\u52a1<\/a><\/p>\n<p><a href=\"https:\/\/developer.mozilla.org\/zh-TW\/docs\/Web\/JavaScript\/Reference\/Global_Objects\/Promise\" title=\"Promise\">Promise<\/a><\/p>\n<p><img data-original=\"https:\/\/blog.odjbinail.cn\/wp-content\/uploads\/2026\/02\/2026020916364786.png\"  alt=\"\" \/><\/p>\n<noscript><img decoding=\"async\" src=\"https:\/\/blog.odjbinail.cn\/wp-content\/uploads\/2026\/02\/2026020916364786.png\" alt=\"\" \/><\/p><\/noscript>\n<ul>\n<li>\n<p>\u540c\u65f6\u56e0\u4e3a\u63a5\u4e0b\u6765 <strong>\u540c\u6b65\u4efb\u52a1\u5df2\u7ecf\u6267\u884c\u5b8c\u6210<\/strong>, \u6240\u4ee5 <strong>\u5f02\u6b65\u7684\u5fae\u4efb\u52a1<\/strong> \u9a6c\u4e0a\u5c31\u8981\u5f00\u59cb\u6267\u884c, \u5373\u63a5\u4e0b\u6765\u6211\u4eec\u5c06\u4f1a\u8fdb\u5165 flushJobs \u4e2d<\/p>\n<\/li>\n<li>\n<p>watch \u6574\u4f53\u5206\u4e3a\u4e86\u56db\u5927\u5757:<\/p>\n<ul>\n<li>watch \u51fd\u6570\u672c\u8eab<\/li>\n<li>reactive \u7684 setter<\/li>\n<li>flushJobs<\/li>\n<li>job<\/li>\n<\/ul>\n<\/li>\n<li>\n<p>\u6574\u4e2a watch \u8fd8\u662f\u6bd4\u8f83\u590d\u6742\u7684\uff0c\u4e3b\u8981\u662f\u56e0\u4e3a vue \u5728\u5185\u90e8\u8fdb\u884c\u4e86\u5f88\u591a\u7684 <strong>\u517c\u5bb9\u6027\u5904\u7406<\/strong>\uff0c\u4f7f\u4ee3\u7801\u7684\u590d\u6742\u5ea6\u4e0a\u5347\u4e86\u597d\u51e0\u4e2a\u53f0\u9636\uff0c\u6211\u4eec\u81ea\u5df1\u53bb\u5b9e\u73b0\u7684\u65f6\u5019\u4f1a\u7b80\u5355\u5f88\u591a\u7684\u3002<\/p>\n<\/li>\n<\/ul>\n<h3>\u6df1\u5165 scheduler \u8c03\u5ea6\u7cfb\u7edf\u5b9e\u73b0\u673a\u5236<\/h3>\n<p>\u6574\u4e2a\u8c03\u5ea6\u7cfb\u7edf\u5176\u5b9e\u5305\u542b\u4e24\u90e8\u5206\u5b9e\u73b0:<\/p>\n<ul>\n<li>1.lazy: \u61d2\u6267\u884c<\/li>\n<\/ul>\n<pre class=\"prettyprint linenums\" ><code>\/\/packages\/reactivity\/src\/effect.ts\n\nexport interface ReactiveEffectOptions {\n  lazy?: boolean\n  scheduler?: EffectScheduler\n}\n\nexport function effect&lt;T = any&gt;(fn: () =&gt; T, options?: ReactiveEffectOptions) {\n  const _effect = new ReactiveEffect(fn)\n  if (!options || !options.lazy) {\n    _effect.run()\n  }\n}<\/code><\/pre>\n<ul>\n<li>2.scheduler: \u8c03\u5ea6\u5668 [\u7a0d\u5fae\u590d\u6742\u4e00\u4e9b]\n<ul>\n<li>\u63a7\u5236\u6267\u884c\u987a\u5e8f<\/li>\n<\/ul>\n<\/li>\n<\/ul>\n<pre class=\"prettyprint linenums\" ><code>&lt;script&gt;\n    const { reactive,effect } = Vue\n    const obj=reactive({\n       count:1\n    })\n\n    effect(()=&gt;{\n        console.log(obj.count)\n    },{\n        scheduler(){\n            setTimeout(()=&gt;{\n                console.log(obj.count)\n            })\n        }\n    })\n    obj.count=2\n\n    console.log(&#039;\u4ee3\u7801\u8fd0\u884c\u7ed3\u675f&#039;);\n&lt;\/script&gt;\n\/\/1  \n\/\/\u4ee3\u7801\u7ed3\u675f..\n\/\/2<\/code><\/pre>\n<ul>\n<li>\u63a7\u5236\u6267\u884c\u89c4\u5219\n<ul>\n<li>packages\/runtime-core\/src\/scheduler.ts<\/li>\n<\/ul>\n<\/li>\n<\/ul>\n<pre class=\"prettyprint linenums\" ><code>let isFlushPending = false\n\nconst resolvedPromise = Promise.resolve() as Promise&lt;any&gt;\n\nlet currentFlushPromise: Promise&lt;void&gt; | null = null\n\nconst pendingPreFlushCbs: Function[] = []\nexport function queuePreFlushCb(cb: Function) {\n  queueCb(cb, pendingPreFlushCbs)\n}\nfunction queueCb(cb: Function, pendingQueue: Function[]) {\n  pendingQueue.push(cb)\n  queueFlush()\n}\n\nfunction queueFlush() {\n  if (!isFlushPending) {\n    isFlushPending = true\n    currentFlushPromise = resolvedPromise.then(flushJobs)\n  }\n}\nfunction flushJobs() {\n  isFlushPending = false\n  flushPreFlushCbs()\n}\nexport function flushPreFlushCbs() {\n  if (pendingPreFlushCbs.length) {\n    \/\/\u62f7\u8d1d\u53bb\u91cd,\u7c7b\u4f3c\u6df1\u62f7\u8d1d\n    let activePreFlushCbs = [...new Set(pendingPreFlushCbs)]\n    pendingPreFlushCbs.length = 0\n    for (let i = 0; i &lt; activePreFlushCbs.length; i++) {\n      activePreFlushCbs[i]()\n    }\n  }\n}\n<\/code><\/pre>\n<pre class=\"prettyprint linenums\" ><code>&lt;script&gt;\n    const { reactive,effect,queuePreFlushCb } = Vue\n    const obj=reactive({\n        count:1\n    })\n\n    effect(()=&gt;{\n        console.log(obj.count)\n    },{\n        scheduler(){\n            queuePreFlushCb(()=&gt;console.log(obj.count));\n\n        }\n    })\n    obj.count=2\n    obj.count=3\n&lt;\/script&gt;<\/code><\/pre>\n<p><img data-original=\"https:\/\/blog.odjbinail.cn\/wp-content\/uploads\/2026\/02\/2026022422053274.png\"  alt=\"\" \/><\/p>\n<noscript><img decoding=\"async\" src=\"https:\/\/blog.odjbinail.cn\/wp-content\/uploads\/2026\/02\/2026022422053274.png\" alt=\"\" \/><\/p><\/noscript>\n<h3>watch \u6570\u636e\u76d1\u542c\u5668<\/h3>\n<p>packages\/runtime-core\/src\/apiWatch.ts<\/p>\n<h4>watch \u6570\u636e\u76d1\u542c\u5668\u7684\u4f9d\u8d56\u6536\u96c6<\/h4>\n<ul>\n<li>\u89e3\u51b3\u95ee\u9898---&quot;\u54cd\u5e94\u5f0f\u6570\u636e\u7684\u6539\u53d8\u5e76\u4e0d\u4f1a\u5f15\u8d77 watch \u7684\u89e6\u53d1&quot;<\/li>\n<\/ul>\n<pre class=\"prettyprint linenums\" ><code>\/**\n * \u672c\u8d28\u4e0a\u662f\u62ff value, \u51fa\u53d1\u4e00\u6b21 getter \u884c\u4e3a\n * @param value\n *\/\nexport function traverse(value: unknown) {\n  if (!isObject(value)) {\n    return value\n  }\n  for (const key in value as object) {\n    traverse((value as object)[key])\n  }\n  return value\n}\n<\/code><\/pre>\n<h1>runtime \u8fd0\u884c\u65f6<\/h1>\n<ul>\n<li>\u8fd0\u884c\u65f6: \u5373\u628a VNode \u6e32\u67d3\u5230\u9875\u9762\u4e2d\u3002<\/li>\n<\/ul>\n<h2>\u8fd0\u884c\u65f6\u6838\u5fc3\u8bbe\u8ba1\u539f\u5219<\/h2>\n<h3>HTML DOM \u8282\u70b9\u6811\u4e0e\u865a\u62df DOM \u6811<\/h3>\n<p><a href=\"https:\/\/zh.javascript.info\/dom-nodes\" title=\"DOM \u6811\">DOM \u6811<\/a><\/p>\n<p><a href=\"https:\/\/cn.vuejs.org\/guide\/extras\/rendering-mechanism.html\" title=\"\u865a\u62df DOM\">\u865a\u62df DOM<\/a><\/p>\n<ul>\n<li><strong>\u865a\u62df DOM \u662f\u4e00\u79cd\u7f16\u7a0b\u6982\u5ff5<\/strong>\uff0c\u610f\u4e3a\u5c06\u76ee\u6807\u6240\u9700\u7684 UI \u901a\u8fc7\u6570\u636e\u7ed3\u6784\u201c\u865a\u62df\u201d\u5730\u8868\u793a\u51fa\u6765\uff0c\u4fdd\u5b58\u5728\u5185\u5b58\u4e2d\uff0c\u7136\u540e\u5c06\u771f\u5b9e\u7684 DOM \u4e0e\u4e4b\u4fdd\u6301\u540c\u6b65\u3002\u8fd9\u4e2a\u6982\u5ff5\u662f\u7531 React \u7387\u5148\u5f00\u62d3, \u968f\u540e\u5728\u8bb8\u591a\u4e0d\u540c\u7684\u6846\u67b6\u4e2d\u90fd\u6709\u4e0d\u540c\u7684\u5b9e\u73b0, \u5f53\u7136\u4e5f\u5305\u62ec Vue<\/li>\n<li>\u5728\u8fd0\u884c\u65f6 <strong>runtime<\/strong>, \u6e32\u67d3\u5668<strong>renderer<\/strong>\u4f1a\u904d\u5386\u6574\u4e2a\u865a\u62df DOM \u6811, \u5e76\u636e\u6b64\u6784\u5efa\u771f\u5b9e\u7684 DOM \u6811, \u8fd9\u4e2a\u8fc7\u7a0b\u53ef\u4ee5\u53eb\u505a<strong> \u6302\u8f7d mount<\/strong><\/li>\n<li>\u5f53\u8fd9\u4e2a VNode \u5bf9\u8c61\u53d1\u751f\u53d8\u5316\u65f6, \u90a3\u4e48\u6211\u4eec\u4f1a\u5bf9\u6bd4 \u65e7\u7684 VNode \u548c\u65b0\u7684 VNode \u4e4b\u95f4\u7684\u533a\u522b, \u627e\u51fa\u5b83\u4eec\u4e4b\u95f4\u7684\u533a\u522b, \u5e76\u5e94\u7528\u8fd9\u5176\u4e2d\u7684\u53d8\u5316\u5230\u771f\u5b9e\u7684 DOM \u4e0a. \u8fd9\u4e2a\u8fc7\u7a0b\u88ab\u79f0\u4e3a<strong>\u66f4\u65b0 patch<\/strong><\/li>\n<\/ul>\n<h3>\u6302\u8f7d\u548c\u66f4\u65b0<\/h3>\n<ul>\n<li>\u6302\u8f7d\u6848\u4f8b<\/li>\n<\/ul>\n<pre class=\"prettyprint linenums\" ><code>&lt;body&gt;\n  &lt;div id=&quot;app&quot;&gt;&lt;\/div&gt;\n&lt;\/body&gt;\n&lt;script&gt;\n  \/\/ &lt;div&gt;hello render&lt;\/div&gt;\n  const vnode = {\n    type: &#039;div&#039;,\n    children: &#039;hello render&#039;\n  }\n  function render(oldVNode, newVNode, container) {\n    if (!oldVNode) {\n      mount(newVNode, container)\n    }\n  }\n  \/\/\u6302\u8f7d\u51fd\u6570\n  function mount(vnode, container) {\n    \/\/\u6839\u636e type \u751f\u6210 element\n    const ele = document.createElement(vnode.type)\n    \/\/\u628a children \u8d4b\u503c\u7ed9 ele \u7684 innerText\n    ele.innerText = vnode.children\n    \/\/\u628a ele \u4f5c\u4e3a\u5b50\u8282\u70b9\u63d2\u5165 body \u4e2d\n    container.appendChild(ele)\n  }\n  render(null, vnode, document.querySelector(&#039;#app&#039;))\n&lt;\/script&gt;<\/code><\/pre>\n<ul>\n<li>\u66f4\u65b0\u6848\u4f8b<\/li>\n<li>\u5728 patch \u51fd\u6570\u4e2d, \u6211\u4eec\u5148 \u5220\u9664\u4e86\u65e7\u7684 VNode, \u7136\u540e\u521b\u5efa\u4e86\u4e00\u4e2a\u65b0\u7684 vnode, <\/li>\n<\/ul>\n<pre class=\"prettyprint linenums\" ><code>&lt;script&gt;\n  \/\/ &lt;div&gt;hello render&lt;\/div&gt;\n  const vnode = {\n    type: &#039;div&#039;,\n    children: &#039;hello render&#039;\n  }\n  \/\/ &lt;div&gt;patch render&lt;\/div&gt;\n  const vnode2 = {\n    type: &#039;div&#039;,\n    children: &#039;patch render&#039;\n  }\n  function render(oldVNode, newVNode, container) {\n    if (!oldVNode) {\n      mount(newVNode, container)\n    } else {\n      patch(oldVNode, newVNode, container)\n    }\n  }\n  function mount(vnode, container) {\n    const ele = document.createElement(vnode.type)\n    ele.innerText = vnode.children\n    container.appendChild(ele)\n  }\n  \/\/\u5c06\u4e4b\u524d\u5185\u5bb9\u6e05\u7a7a\n  function unmount(container) {\n    container.innerHTML = &#039;&#039;\n  }\n  function patch(oldVNode, newVNode, container) {\n    unmount(container)\n    const ele = document.createElement(newVNode.type)\n    ele.innerText = newVNode.children\n    container.appendChild(ele)\n  }\n  render(null, vnode, document.querySelector(&#039;#app&#039;))\n\n  setTimeout(() =&gt; {\n    render(vnode, vnode2, document.querySelector(&#039;#app&#039;))\n  }, 2000);\n&lt;\/script&gt;<\/code><\/pre>\n<h4>\u603b\u7ed3<\/h4>\n<p><a href=\"https:\/\/cn.vuejs.org\/guide\/extras\/rendering-mechanism.html\" title=\"\u865a\u62df DOM\">\u865a\u62df DOM<\/a><\/p>\n<ul>\n<li>\u6302\u8f7d: \u8fd0\u884c\u65f6\u6e32\u67d3\u5668\u8c03\u7528\u6e32\u67d3\u51fd\u6570, \u904d\u5386\u8fd4\u56de\u7684\u865a\u62df DOM \u6811, \u5e76\u57fa\u4e8e\u5b83\u521b\u5efa\u5b9e\u9645\u7684 DOM \u8282\u70b9.<\/li>\n<li>\u66f4\u65b0: \u5f53\u4e00\u4e2a\u4f9d\u8d56\u53d1\u751f\u53d8\u5316\u540e, \u526f\u4f5c\u7528\u4f1a\u91cd\u65b0\u8fd0\u884c, \u8fd9\u65f6\u5019\u4f1a\u521b\u5efa\u4e00\u4e2a\u66f4\u65b0\u540e\u7684\u865a\u62df DOM \u6811\u3002\u8fd0\u884c\u65f6\u6e32\u67d3\u5668\u904d\u5386\u8fd9\u68f5\u65b0\u6811\uff0c \u5c06\u5b83\u4e0e\u65e7\u6811\u8fdb\u884c\u6bd4\u8f83\uff0c\u7136\u540e\u5c06\u5fc5\u8981\u7684\u66f4\u65b0\u5e94\u7528\u5230\u771f\u5b9e DOM \u4e0a\u53bb\u3002<\/li>\n<\/ul>\n<h3>h \u51fd\u6570\u4e0e render \u51fd\u6570<\/h3>\n<h4>h \u51fd\u6570<\/h4>\n<p><a href=\"https:\/\/cn.vuejs.org\/api\/render-function\" title=\"h \u51fd\u6570\">h \u51fd\u6570<\/a><\/p>\n<ul>\n<li>h \u51fd\u6570\u672c\u8d28\u4e0a\u5c31\u662f\u4e00\u4e2a \u7528\u6765\u751f\u6210 VNode \u7684\u51fd\u6570\n<ul>\n<li>type: string | Component : \u65e2\u53ef\u4ee5\u662f\u4e00\u4e2a\u5b57\u7b26\u4e32, \u4e5f\u53ef\u4ee5\u662f\u4e00\u4e2a vue \u7ec4\u4ef6\u5b9a\u4e49<\/li>\n<li>props?:object | null: \u8981\u4f20\u9012\u7684 prop<\/li>\n<li>children?: Children | Slot | Slots: \u5b50\u8282\u70b9<\/li>\n<\/ul>\n<\/li>\n<\/ul>\n<pre class=\"prettyprint linenums\" ><code>&lt;script&gt;\n  const { render, h } = Vue\n  \/\/\u751f\u6210 vnode\n  const vnode = h(&#039;div&#039;, {\n    class: &#039;test&#039;\n  }, &#039;hello render&#039;)\n  \/\/\u62ff\u5230\u627f\u8f7d\u7684\u5bb9\u5668\n  const container = document.querySelector(&#039;#app&#039;)\n  \/\/\u6e32\u67d3\u51fd\u6570\n  render(vnode, container)\n&lt;\/script&gt;<\/code><\/pre>\n<ul>\n<li>\u6253\u5370 vnode \u540e, \u7cbe\u7b80\u7684 vnode<br \/>\n<img data-original=\"https:\/\/blog.odjbinail.cn\/wp-content\/uploads\/2026\/02\/2026022615241792.png\"  alt=\"\" \/><\/li>\n<noscript><img decoding=\"async\" src=\"https:\/\/blog.odjbinail.cn\/wp-content\/uploads\/2026\/02\/2026022615241792.png\" alt=\"\" \/><\/li><\/noscript>\n<\/ul>\n<h4>render \u51fd\u6570<\/h4>\n<p><a href=\"https:\/\/cn.vuejs.org\/api\/options-rendering.html#render\" title=\"render \u51fd\u6570\">render \u51fd\u6570<\/a><\/p>\n<ul>\n<li>\u901a\u8fc7 render \u51fd\u6570, \u6211\u4eec\u53ef\u4ee5: \u4f7f\u7528\u7f16\u7a0b\u5f0f\u5730\u65b9\u5f0f\uff0c\u521b\u5efa\u865a\u62df DOM \u6811\u5bf9\u5e94\u7684\u771f\u5b9e DOM \u6811\uff0c\u5230\u6307\u5b9a\u4f4d\u7f6e\u3002<\/li>\n<\/ul>\n<h3>\u8fd0\u884c\u65f6\u6838\u5fc3\u8bbe\u8ba1\u539f\u5219---\u89e3\u91ca<\/h3>\n<h4>1.runtime-core \u4e0e runtime-dom \u7684\u5173\u7cfb, \u4e3a\u4ec0\u4e48\u8981\u8fd9\u4e48\u8bbe\u8ba1?<\/h4>\n<p>\u5728 vue \u6e90\u7801\u4e2d, \u5173\u4e8e\u8fd0\u884c\u65f6\u7684\u5305\u4e3b\u8981\u6709\u4e24\u4e2a:<\/p>\n<ul>\n<li>1.packages\/runtime-core: \u8fd0\u884c\u65f6\u7684\u6838\u5fc3\u4ee3\u7801<\/li>\n<li>2.packages\/runtime-dom : \u8fd0\u884c\u65f6\u5173\u4e8e\u6d4f\u89c8\u5668\u6e32\u67d3\u7684\u4ee3\u7801<\/li>\n<\/ul>\n<h4>2.\u6e32\u67d3\u65f6, \u6302\u8f7d\u548c\u66f4\u65b0\u7684\u903b\u8f91\u5904\u7406<\/h4>\n<h2>\u6784\u5efa h \u51fd\u6570\u751f\u6210 vnode<\/h2>\n<h3>\u6e90\u7801\u9605\u8bfb<\/h3>\n<ul>\n<li><a href=\"https:\/\/web.nodejs.cn\/en-us\/docs\/web\/javascript\/reference\/operators\/bitwise_or_assignment\/\" title=\"\u6309\u4f4d\u6216\u8d4b\u503c\">\u6309\u4f4d\u6216\u8d4b\u503c<\/a><\/li>\n<li>\u6d4b\u8bd5\u5b9e\u4f8b:<\/li>\n<\/ul>\n<pre class=\"prettyprint linenums\" ><code>&lt;body&gt;\n  &lt;div id=&quot;app&quot;&gt;\n  &lt;\/div&gt;\n&lt;\/body&gt;\n\n&lt;script&gt;\n  const { h } = Vue\n  const vnode = h(&#039;div&#039;, {\n    class: &#039;test&#039;,\n  }, &#039;hello world&#039;)\n  console.log(vnode);\n\n&lt;\/script&gt;<\/code><\/pre>\n<ul>\n<li>\u5728 packages\/runtime-core\/src\/h.ts \u4e3a 208 \u884c const l = arguments.length \u589e\u52a0 debugger<\/li>\n<\/ul>\n<p><img data-original=\"https:\/\/blog.odjbinail.cn\/wp-content\/uploads\/2026\/02\/2026022620522744.png\"  alt=\"\" \/><\/p>\n<noscript><img decoding=\"async\" src=\"https:\/\/blog.odjbinail.cn\/wp-content\/uploads\/2026\/02\/2026022620522744.png\" alt=\"\" \/><\/p><\/noscript>\n<h3>\u6784\u5efa h \u51fd\u6570\uff0c\u5904\u7406 ELEMENT+TEXT_CHILDREN \u573a\u666f<\/h3>\n<p>shapeFlag \u4e3a 9<br \/>\n\u521b\u5efa packages\/shared\/src\/shapeFlags.ts \u5199\u5165\u6240\u6709\u7684\u5bf9\u5e94\u7c7b\u578b<\/p>\n<pre class=\"prettyprint linenums\" ><code>export const enum ShapeFlags {\n  \/**\n   * type=Element\n   *\/\n  ELEMENT = 1,\n  \/**\n   * \u51fd\u6570\u7ec4\u4ef6\n   *\/\n  FUNCTIONAL_COMPONENT = 1 &lt;&lt; 1,\n  \/**\n   * \u6709\u72b6\u6001(\u54cd\u5e94\u6570\u636e)\u7ec4\u4ef6\n   *\/\n  STATEFUL_COMPONENT = 1 &lt;&lt; 2,\n  \/**\n   * children=Text\n   *\/\n  TEXT_CHILDREN = 1 &lt;&lt; 3,\n  \/**\n   * children=Array\n   *\/\n  ARRAY_CHILDREN = 1 &lt;&lt; 4,\n  \/**\n   * children=slot\n   *\/\n  SLOTS__CHILDREN = 1 &lt;&lt; 5,\n  \/**\n   * \u7ec4\u4ef6: \u6709\u72b6\u6001(\u54cd\u5e94\u6570\u636e)\u7ec4\u4ef6 | \u51fd\u6570\u7ec4\u4ef6\n   *\/\n  COMPONENT = ShapeFlags.STATEFUL_COMPONENT | ShapeFlags.FUNCTIONAL_COMPONENT\n}<\/code><\/pre>\n<ul>\n<li>\u521b\u5efa packages\/runtime-core\/src\/h.ts<\/li>\n<li>\u521b\u5efa packages\/runtime-core\/src\/vnode.ts<\/li>\n<\/ul>\n<h3>\u5904\u7406 ELEMENT+ARRAY_CHILDREN \u573a\u666f<\/h3>\n<p>shapeFlag \u4e3a 17<\/p>\n<p><img data-original=\"https:\/\/blog.odjbinail.cn\/wp-content\/uploads\/2026\/02\/2026022710420648.png\"  alt=\"\" \/> <\/p>\n<noscript><img decoding=\"async\" src=\"https:\/\/blog.odjbinail.cn\/wp-content\/uploads\/2026\/02\/2026022710420648.png\" alt=\"\" \/> <\/p><\/noscript>\n<h3>\u6e90\u7801\u9605\u8bfb: h \u51fd\u6570, \u7ec4\u4ef6\u7684\u672c\u8d28\u4e0e\u5bf9\u5e94\u7684 VNode<\/h3>\n<ul>\n<li>\u5728 vue \u4e2d, \u7ec4\u4ef6\u672c\u8d28\u4e0a\u662f \u4e00\u4e2a\u5bf9\u8c61\u6216\u4e00\u4e2a\u51fd\u6570(\u5c11\u89c1)<\/li>\n<li>\u53ef\u4ee5\u76f4\u63a5\u5229\u7528 h \u51fd\u6570+render \u51fd\u6570\u6e32\u67d3\u51fa\u4e00\u4e2a\u57fa\u672c\u7684\u7ec4\u4ef6:\n<ul>\n<li>\u521b\u5efa h-component.html<\/li>\n<\/ul>\n<\/li>\n<\/ul>\n<pre class=\"prettyprint linenums\" ><code>&lt;script&gt;\n    const { h, render } = Vue\n    const component = {\n        render() {\n            \/\/ const vnode1=h(&#039;div&#039;,&#039;\u8fd9\u662f\u4e00\u4e2a component&#039;)\n            \/\/ console.log(vnode1);\n            \/\/ return vnode1\n\n            \/\/\u76f4\u63a5\u5229\u7528\u5f53\u524d\u6253\u5370\u7684 vnode , \u7ed5\u8fc7 h \u7684\u6e32\u67d3\n            return {\n                &quot;__v_isVNode&quot;: true,\n                &quot;type&quot;: &#039;div&#039;,\n                &quot;children&quot;: &#039;\u8fd9\u662f\u4e00\u4e2a component&#039;,\n                &quot;shapeFlag&quot;: 9\n            }\n        }\n    }\n    \/\/ const vnode2=h(component)\n    \/\/ console.log(vnode2);\n\n    const vnode2 = {\n        &quot;__v_isVNode&quot;: true,\n        &quot;shapeFlag&quot;: 4,\n        &quot;type&quot;: component\n    }\n    render(vnode2, document.querySelector(&#039;#app&#039;))\n&lt;\/script&gt;<\/code><\/pre>\n<h3>\u5b9e\u73b0: \u5904\u7406\u7ec4\u4ef6\u7684 VNode<\/h3>\n<ul>\n<li>packages\/runtime-core\/src\/vnode.ts  \u52a0\u4e0a isObject(type)\u7684\u5224\u5b9a<\/li>\n<\/ul>\n<pre class=\"prettyprint linenums\" ><code>export function createVNode(type, props, children): VNode {\n  const shapeFlag = isString(type)\n    ? ShapeFlags.ELEMENT\n    : isObject(type)\n      ? ShapeFlags.STATEFUL_COMPONENT\n      : 0\n  return createBaseVNode(type, props, children, shapeFlag)\n}<\/code><\/pre>\n<h3>\u6e90\u7801\u9605\u8bfb: h \u51fd\u6570, \u8ddf\u8e2a Text\u3001Comment\u3001Fragment \u573a\u666f<\/h3>\n<pre class=\"prettyprint linenums\" ><code>  &lt;script&gt;\n    \/\/Fragment : \u7247\u6bb5  vue3 \u4e00\u4e2a\u6a21\u677f\u4e2d, \u53ef\u4ee5\u6709\u591a\u4e2a\u6839\u8282\u70b9,\u5c31\u662f\u5229\u7528\u8fd9\u7247\u6bb5\u5b8c\u6210\u7684\n    const { h, render, Text,Comment,Fragment } = Vue\n    \/\/ const vnodeText = h(Text, &#039;\u8fd9\u662f\u4e00\u4e2a Text&#039;)\n    \/\/ console.log(vnodeText)\n\n    \/\/ const vnodeComment=h(Comment,&#039;\u8fd9\u662f\u4e00\u4e2a comment&#039;)\n    \/\/ console.log(vnodeComment);\n    \/\/ render(vnodeComment,document.querySelector(&#039;#app&#039;))\n\n    const vnodeFragment=h(Fragment)\n\n    console.log(vnodeFragment);\n    render(vnodeFragment,document.querySelector(&#039;#app&#039;))\n  &lt;\/script&gt;<\/code><\/pre>\n<h3>\u5b9e\u73b0: Text\u3001Comment\u3001Fragment<\/h3>\n<ul>\n<li>packages\/runtime-core\/src\/vnode.ts<\/li>\n<\/ul>\n<pre class=\"prettyprint linenums\" ><code>export const Fragment = Symbol(&#039;Fragment&#039;)\nexport const Text = Symbol(&#039;Text&#039;)\nexport const Comment = Symbol(&#039;Comment&#039;)<\/code><\/pre>\n<h3>\u6e90\u7801\u9605\u8bfb: \u5bf9 class \u548c style \u7ed1\u5b9a<\/h3>\n<p><a href=\"https:\/\/cn.vuejs.org\/guide\/essentials\/class-and-style.html\" title=\"Class \u4e0e Style \u7ed1\u5b9a\">Class \u4e0e Style \u7ed1\u5b9a<\/a><\/p>\n<h3>\u5b8c\u6210\u865a\u62df\u8282\u70b9\u4e0b\u7684 class \u548c style \u7684\u589e\u5f3a<\/h3>\n<p>packages\/shared\/src\/normalizeProp.ts<\/p>\n<pre class=\"prettyprint linenums\" ><code>import { isArray, isObject, isString } from &#039;@vue\/shared&#039;\n\nexport function normalizeClass(value: unknown): string {\n  let res = &#039;&#039;\n\n  if (isString(value)) {\n    res = value\n  } else if (isArray(value)) {\n    for (let i = 0; i &lt; value.length; i++) {\n      const normalized = normalizeClass(value[i])\n      if (normalized) {\n        res += normalized + &#039; &#039;\n      }\n    }\n  } else if (isObject(value)) {\n    for (const name in value as object) {\n      if ((value as object)[name]) {\n        res += name + &#039; &#039;\n      }\n    }\n  }\n\n  return res.trim()\n}\n<\/code><\/pre>\n<ul>\n<li>\u6848\u4f8b<\/li>\n<\/ul>\n<pre class=\"prettyprint linenums\" ><code>&lt;script&gt;\n const {h} =Vue\n const vnode=h(&#039;div&#039;,{\n   class:[\n     {\n       &#039;red&#039;:true,\n     },\n     {\n       &#039;pink&#039;:true,\n     },\n     {\n       &#039;blue&#039;:false\n     }\n   ]\n },&#039;\u589e\u5f3a class&#039;)\n console.log(vnode)\n&lt;\/script&gt;<\/code><\/pre>\n<h2>\u6784\u5efa renderer \u6e32\u67d3\u5668<\/h2>\n","protected":false},"excerpt":{"rendered":"<p>\u95ee\u9898: .vue \u4e2d\u7684 HTML \u662f\u771f\u5b9e\u7684 html \u5417? \u4e0d\u662f \u4e2d\u95f4\u505a\u4e86\u4ec0\u4e48\u4e8b\u60c5, \u8ba9 \u5047\u7684 html \u6807\u7b7e [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[1],"tags":[],"class_list":["post-5240","post","type-post","status-publish","format-standard","hentry","category-1"],"_links":{"self":[{"href":"https:\/\/blog.odjbinail.cn\/index.php?rest_route=\/wp\/v2\/posts\/5240","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/blog.odjbinail.cn\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/blog.odjbinail.cn\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/blog.odjbinail.cn\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/blog.odjbinail.cn\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=5240"}],"version-history":[{"count":131,"href":"https:\/\/blog.odjbinail.cn\/index.php?rest_route=\/wp\/v2\/posts\/5240\/revisions"}],"predecessor-version":[{"id":5400,"href":"https:\/\/blog.odjbinail.cn\/index.php?rest_route=\/wp\/v2\/posts\/5240\/revisions\/5400"}],"wp:attachment":[{"href":"https:\/\/blog.odjbinail.cn\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=5240"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/blog.odjbinail.cn\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=5240"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/blog.odjbinail.cn\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=5240"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}