[{"data":1,"prerenderedAt":2494},["ShallowReactive",2],{"note:code\u002Fvue\u002F02-dom-to-vue":3},{"id":4,"title":5,"body":6,"description":16,"extension":2488,"meta":2489,"navigation":161,"path":2490,"seo":2491,"stem":2492,"__hash__":2493},"notes\u002Fsource\u002Fcode\u002Fvue\u002F02-dom-to-vue.md","02 DOM 到 Vue 的心智模型",{"type":7,"value":8,"toc":2466},"minimark",[9,13,17,20,25,28,31,108,111,119,122,206,210,504,507,539,546,549,588,591,595,598,664,667,692,942,945,965,968,972,1258,1261,1290,1293,1341,1344,1348,1351,1392,1395,1452,1455,1458,1469,1473,1476,1482,1485,1488,1593,1596,1625,1629,1632,1635,1659,1662,1710,1736,1739,1756,1759,1880,1894,1898,1901,1926,1929,1940,1943,1954,1957,1982,1993,1997,2000,2040,2043,2062,2065,2068,2091,2094,2133,2136,2138,2192,2194,2221,2225,2230,2245,2248,2271,2275,2278,2295,2298,2302,2305,2329,2332,2336,2339,2375,2378,2381,2385,2388,2402,2408,2412,2415,2438,2442,2445,2462],[10,11,5],"h1",{"id":12},"_02-dom-到-vue-的心智模型",[14,15,16],"p",{},"你略懂 DOM，这是学习 Vue 的好起点。Vue 并不是让你忘掉 HTML、CSS、JavaScript，而是帮你少写那些容易出错的“手动同步 DOM”的代码。",[14,18,19],{},"本章核心目标：理解为什么原生 DOM 在复杂交互里会越来越乱，以及 Vue 如何用“状态驱动界面”的方式解决这个问题。",[21,22,24],"h2",{"id":23},"_1-dom-是什么","1. DOM 是什么",[14,26,27],{},"浏览器把 HTML 解析成一棵对象树，这棵树叫 DOM。",[14,29,30],{},"HTML：",[32,33,38],"pre",{"className":34,"code":35,"language":36,"meta":37,"style":37},"language-html shiki shiki-themes github-light github-dark","\u003Cmain>\n  \u003Ch1>任务列表\u003C\u002Fh1>\n  \u003Cbutton id=\"add\">新增\u003C\u002Fbutton>\n\u003C\u002Fmain>\n","html","",[39,40,41,57,72,98],"code",{"__ignoreMap":37},[42,43,46,50,54],"span",{"class":44,"line":45},"line",1,[42,47,49],{"class":48},"sVt8B","\u003C",[42,51,53],{"class":52},"s9eBZ","main",[42,55,56],{"class":48},">\n",[42,58,60,63,65,68,70],{"class":44,"line":59},2,[42,61,62],{"class":48},"  \u003C",[42,64,10],{"class":52},[42,66,67],{"class":48},">任务列表\u003C\u002F",[42,69,10],{"class":52},[42,71,56],{"class":48},[42,73,75,77,80,84,87,91,94,96],{"class":44,"line":74},3,[42,76,62],{"class":48},[42,78,79],{"class":52},"button",[42,81,83],{"class":82},"sScJk"," id",[42,85,86],{"class":48},"=",[42,88,90],{"class":89},"sZZnC","\"add\"",[42,92,93],{"class":48},">新增\u003C\u002F",[42,95,79],{"class":52},[42,97,56],{"class":48},[42,99,101,104,106],{"class":44,"line":100},4,[42,102,103],{"class":48},"\u003C\u002F",[42,105,53],{"class":52},[42,107,56],{"class":48},[14,109,110],{},"浏览器内部会把它变成类似这样的结构：",[32,112,117],{"className":113,"code":115,"language":116,"meta":37},[114],"language-text","document\n  main\n    h1\n    button#add\n","text",[39,118,115],{"__ignoreMap":37},[14,120,121],{},"JavaScript 可以通过 DOM API 找到元素、读取内容、修改内容、监听事件。",[32,123,127],{"className":124,"code":125,"language":126,"meta":37,"style":37},"language-js shiki shiki-themes github-light github-dark","const button = document.querySelector('#add')\n\nbutton.addEventListener('click', () => {\n  console.log('用户点击了新增')\n})\n","js",[39,128,129,157,163,185,200],{"__ignoreMap":37},[42,130,131,135,139,142,145,148,151,154],{"class":44,"line":45},[42,132,134],{"class":133},"szBVR","const",[42,136,138],{"class":137},"sj4cs"," button",[42,140,141],{"class":133}," =",[42,143,144],{"class":48}," document.",[42,146,147],{"class":82},"querySelector",[42,149,150],{"class":48},"(",[42,152,153],{"class":89},"'#add'",[42,155,156],{"class":48},")\n",[42,158,159],{"class":44,"line":59},[42,160,162],{"emptyLinePlaceholder":161},true,"\n",[42,164,165,168,171,173,176,179,182],{"class":44,"line":74},[42,166,167],{"class":48},"button.",[42,169,170],{"class":82},"addEventListener",[42,172,150],{"class":48},[42,174,175],{"class":89},"'click'",[42,177,178],{"class":48},", () ",[42,180,181],{"class":133},"=>",[42,183,184],{"class":48}," {\n",[42,186,187,190,193,195,198],{"class":44,"line":100},[42,188,189],{"class":48},"  console.",[42,191,192],{"class":82},"log",[42,194,150],{"class":48},[42,196,197],{"class":89},"'用户点击了新增'",[42,199,156],{"class":48},[42,201,203],{"class":44,"line":202},5,[42,204,205],{"class":48},"})\n",[21,207,209],{"id":208},"_2-原生-dom-写计数器","2. 原生 DOM 写计数器",[32,211,213],{"className":34,"code":212,"language":36,"meta":37,"style":37},"\u003Cbutton id=\"decrease\">-\u003C\u002Fbutton>\n\u003Cspan id=\"count\">0\u003C\u002Fspan>\n\u003Cbutton id=\"increase\">+\u003C\u002Fbutton>\n\n\u003Cscript>\n  let count = 0\n\n  const countEl = document.querySelector('#count')\n  const increaseBtn = document.querySelector('#increase')\n  const decreaseBtn = document.querySelector('#decrease')\n\n  function render() {\n    countEl.textContent = count\n  }\n\n  increaseBtn.addEventListener('click', () => {\n    count++\n    render()\n  })\n\n  decreaseBtn.addEventListener('click', () => {\n    count--\n    render()\n  })\n\u003C\u002Fscript>\n",[39,214,215,235,255,275,279,288,302,307,329,350,371,376,388,399,405,410,428,437,446,452,457,475,483,490,495],{"__ignoreMap":37},[42,216,217,219,221,223,225,228,231,233],{"class":44,"line":45},[42,218,49],{"class":48},[42,220,79],{"class":52},[42,222,83],{"class":82},[42,224,86],{"class":48},[42,226,227],{"class":89},"\"decrease\"",[42,229,230],{"class":48},">-\u003C\u002F",[42,232,79],{"class":52},[42,234,56],{"class":48},[42,236,237,239,241,243,245,248,251,253],{"class":44,"line":59},[42,238,49],{"class":48},[42,240,42],{"class":52},[42,242,83],{"class":82},[42,244,86],{"class":48},[42,246,247],{"class":89},"\"count\"",[42,249,250],{"class":48},">0\u003C\u002F",[42,252,42],{"class":52},[42,254,56],{"class":48},[42,256,257,259,261,263,265,268,271,273],{"class":44,"line":74},[42,258,49],{"class":48},[42,260,79],{"class":52},[42,262,83],{"class":82},[42,264,86],{"class":48},[42,266,267],{"class":89},"\"increase\"",[42,269,270],{"class":48},">+\u003C\u002F",[42,272,79],{"class":52},[42,274,56],{"class":48},[42,276,277],{"class":44,"line":100},[42,278,162],{"emptyLinePlaceholder":161},[42,280,281,283,286],{"class":44,"line":202},[42,282,49],{"class":48},[42,284,285],{"class":52},"script",[42,287,56],{"class":48},[42,289,291,294,297,299],{"class":44,"line":290},6,[42,292,293],{"class":133},"  let",[42,295,296],{"class":48}," count ",[42,298,86],{"class":133},[42,300,301],{"class":137}," 0\n",[42,303,305],{"class":44,"line":304},7,[42,306,162],{"emptyLinePlaceholder":161},[42,308,310,313,316,318,320,322,324,327],{"class":44,"line":309},8,[42,311,312],{"class":133},"  const",[42,314,315],{"class":137}," countEl",[42,317,141],{"class":133},[42,319,144],{"class":48},[42,321,147],{"class":82},[42,323,150],{"class":48},[42,325,326],{"class":89},"'#count'",[42,328,156],{"class":48},[42,330,332,334,337,339,341,343,345,348],{"class":44,"line":331},9,[42,333,312],{"class":133},[42,335,336],{"class":137}," increaseBtn",[42,338,141],{"class":133},[42,340,144],{"class":48},[42,342,147],{"class":82},[42,344,150],{"class":48},[42,346,347],{"class":89},"'#increase'",[42,349,156],{"class":48},[42,351,353,355,358,360,362,364,366,369],{"class":44,"line":352},10,[42,354,312],{"class":133},[42,356,357],{"class":137}," decreaseBtn",[42,359,141],{"class":133},[42,361,144],{"class":48},[42,363,147],{"class":82},[42,365,150],{"class":48},[42,367,368],{"class":89},"'#decrease'",[42,370,156],{"class":48},[42,372,374],{"class":44,"line":373},11,[42,375,162],{"emptyLinePlaceholder":161},[42,377,379,382,385],{"class":44,"line":378},12,[42,380,381],{"class":133},"  function",[42,383,384],{"class":82}," render",[42,386,387],{"class":48},"() {\n",[42,389,391,394,396],{"class":44,"line":390},13,[42,392,393],{"class":48},"    countEl.textContent ",[42,395,86],{"class":133},[42,397,398],{"class":48}," count\n",[42,400,402],{"class":44,"line":401},14,[42,403,404],{"class":48},"  }\n",[42,406,408],{"class":44,"line":407},15,[42,409,162],{"emptyLinePlaceholder":161},[42,411,413,416,418,420,422,424,426],{"class":44,"line":412},16,[42,414,415],{"class":48},"  increaseBtn.",[42,417,170],{"class":82},[42,419,150],{"class":48},[42,421,175],{"class":89},[42,423,178],{"class":48},[42,425,181],{"class":133},[42,427,184],{"class":48},[42,429,431,434],{"class":44,"line":430},17,[42,432,433],{"class":48},"    count",[42,435,436],{"class":133},"++\n",[42,438,440,443],{"class":44,"line":439},18,[42,441,442],{"class":82},"    render",[42,444,445],{"class":48},"()\n",[42,447,449],{"class":44,"line":448},19,[42,450,451],{"class":48},"  })\n",[42,453,455],{"class":44,"line":454},20,[42,456,162],{"emptyLinePlaceholder":161},[42,458,460,463,465,467,469,471,473],{"class":44,"line":459},21,[42,461,462],{"class":48},"  decreaseBtn.",[42,464,170],{"class":82},[42,466,150],{"class":48},[42,468,175],{"class":89},[42,470,178],{"class":48},[42,472,181],{"class":133},[42,474,184],{"class":48},[42,476,478,480],{"class":44,"line":477},22,[42,479,433],{"class":48},[42,481,482],{"class":133},"--\n",[42,484,486,488],{"class":44,"line":485},23,[42,487,442],{"class":82},[42,489,445],{"class":48},[42,491,493],{"class":44,"line":492},24,[42,494,451],{"class":48},[42,496,498,500,502],{"class":44,"line":497},25,[42,499,103],{"class":48},[42,501,285],{"class":52},[42,503,56],{"class":48},[14,505,506],{},"逐行理解：",[508,509,510,517,523,529],"ul",{},[511,512,513,516],"li",{},[39,514,515],{},"let count = 0","：真正的数据。",[511,518,519,522],{},[39,520,521],{},"countEl","：页面上显示数字的 DOM 元素。",[511,524,525,528],{},[39,526,527],{},"render()","：把数据同步到 DOM。",[511,530,531,532,535,536,538],{},"点击按钮后先修改 ",[39,533,534],{},"count","，再调用 ",[39,537,527],{},"。",[14,540,541,542],{},"这里有一个关键问题：",[543,544,545],"strong",{},"你必须记得每次数据变化后手动更新 DOM。",[14,547,548],{},"如果你忘了：",[32,550,552],{"className":124,"code":551,"language":126,"meta":37,"style":37},"increaseBtn.addEventListener('click', () => {\n  count++\n  \u002F\u002F 忘记 render()\n})\n",[39,553,554,571,578,584],{"__ignoreMap":37},[42,555,556,559,561,563,565,567,569],{"class":44,"line":45},[42,557,558],{"class":48},"increaseBtn.",[42,560,170],{"class":82},[42,562,150],{"class":48},[42,564,175],{"class":89},[42,566,178],{"class":48},[42,568,181],{"class":133},[42,570,184],{"class":48},[42,572,573,576],{"class":44,"line":59},[42,574,575],{"class":48},"  count",[42,577,436],{"class":133},[42,579,580],{"class":44,"line":74},[42,581,583],{"class":582},"sJ8bj","  \u002F\u002F 忘记 render()\n",[42,585,586],{"class":44,"line":100},[42,587,205],{"class":48},[14,589,590],{},"数据已经变了，但页面没变。用户看到的界面和真实数据不一致。",[21,592,594],{"id":593},"_3-原生-dom-写列表为什么容易变复杂","3. 原生 DOM 写列表为什么容易变复杂",[14,596,597],{},"假设你有任务数组：",[32,599,601],{"className":124,"code":600,"language":126,"meta":37,"style":37},"let tasks = [\n  { id: 1, title: '学习 JS', done: false },\n  { id: 2, title: '学习 DOM', done: true }\n]\n",[39,602,603,616,639,659],{"__ignoreMap":37},[42,604,605,608,611,613],{"class":44,"line":45},[42,606,607],{"class":133},"let",[42,609,610],{"class":48}," tasks ",[42,612,86],{"class":133},[42,614,615],{"class":48}," [\n",[42,617,618,621,624,627,630,633,636],{"class":44,"line":59},[42,619,620],{"class":48},"  { id: ",[42,622,623],{"class":137},"1",[42,625,626],{"class":48},", title: ",[42,628,629],{"class":89},"'学习 JS'",[42,631,632],{"class":48},", done: ",[42,634,635],{"class":137},"false",[42,637,638],{"class":48}," },\n",[42,640,641,643,646,648,651,653,656],{"class":44,"line":74},[42,642,620],{"class":48},[42,644,645],{"class":137},"2",[42,647,626],{"class":48},[42,649,650],{"class":89},"'学习 DOM'",[42,652,632],{"class":48},[42,654,655],{"class":137},"true",[42,657,658],{"class":48}," }\n",[42,660,661],{"class":44,"line":100},[42,662,663],{"class":48},"]\n",[14,665,666],{},"你要渲染列表：",[32,668,670],{"className":34,"code":669,"language":36,"meta":37,"style":37},"\u003Cul id=\"task-list\">\u003C\u002Ful>\n",[39,671,672],{"__ignoreMap":37},[42,673,674,676,678,680,682,685,688,690],{"class":44,"line":45},[42,675,49],{"class":48},[42,677,508],{"class":52},[42,679,83],{"class":82},[42,681,86],{"class":48},[42,683,684],{"class":89},"\"task-list\"",[42,686,687],{"class":48},">\u003C\u002F",[42,689,508],{"class":52},[42,691,56],{"class":48},[32,693,695],{"className":124,"code":694,"language":126,"meta":37,"style":37},"const listEl = document.querySelector('#task-list')\n\nfunction renderTasks() {\n  listEl.innerHTML = ''\n\n  tasks.forEach((task) => {\n    const item = document.createElement('li')\n    item.textContent = task.done ? `✅ ${task.title}` : task.title\n\n    const button = document.createElement('button')\n    button.textContent = '切换'\n    button.addEventListener('click', () => {\n      task.done = !task.done\n      renderTasks()\n    })\n\n    item.appendChild(button)\n    listEl.appendChild(item)\n  })\n}\n\nrenderTasks()\n",[39,696,697,717,721,731,741,745,767,789,822,826,845,855,872,885,892,897,901,912,922,926,931,935],{"__ignoreMap":37},[42,698,699,701,704,706,708,710,712,715],{"class":44,"line":45},[42,700,134],{"class":133},[42,702,703],{"class":137}," listEl",[42,705,141],{"class":133},[42,707,144],{"class":48},[42,709,147],{"class":82},[42,711,150],{"class":48},[42,713,714],{"class":89},"'#task-list'",[42,716,156],{"class":48},[42,718,719],{"class":44,"line":59},[42,720,162],{"emptyLinePlaceholder":161},[42,722,723,726,729],{"class":44,"line":74},[42,724,725],{"class":133},"function",[42,727,728],{"class":82}," renderTasks",[42,730,387],{"class":48},[42,732,733,736,738],{"class":44,"line":100},[42,734,735],{"class":48},"  listEl.innerHTML ",[42,737,86],{"class":133},[42,739,740],{"class":89}," ''\n",[42,742,743],{"class":44,"line":202},[42,744,162],{"emptyLinePlaceholder":161},[42,746,747,750,753,756,760,763,765],{"class":44,"line":290},[42,748,749],{"class":48},"  tasks.",[42,751,752],{"class":82},"forEach",[42,754,755],{"class":48},"((",[42,757,759],{"class":758},"s4XuR","task",[42,761,762],{"class":48},") ",[42,764,181],{"class":133},[42,766,184],{"class":48},[42,768,769,772,775,777,779,782,784,787],{"class":44,"line":304},[42,770,771],{"class":133},"    const",[42,773,774],{"class":137}," item",[42,776,141],{"class":133},[42,778,144],{"class":48},[42,780,781],{"class":82},"createElement",[42,783,150],{"class":48},[42,785,786],{"class":89},"'li'",[42,788,156],{"class":48},[42,790,791,794,796,799,802,805,807,810,813,816,819],{"class":44,"line":309},[42,792,793],{"class":48},"    item.textContent ",[42,795,86],{"class":133},[42,797,798],{"class":48}," task.done ",[42,800,801],{"class":133},"?",[42,803,804],{"class":89}," `✅ ${",[42,806,759],{"class":48},[42,808,809],{"class":89},".",[42,811,812],{"class":48},"title",[42,814,815],{"class":89},"}`",[42,817,818],{"class":133}," :",[42,820,821],{"class":48}," task.title\n",[42,823,824],{"class":44,"line":331},[42,825,162],{"emptyLinePlaceholder":161},[42,827,828,830,832,834,836,838,840,843],{"class":44,"line":352},[42,829,771],{"class":133},[42,831,138],{"class":137},[42,833,141],{"class":133},[42,835,144],{"class":48},[42,837,781],{"class":82},[42,839,150],{"class":48},[42,841,842],{"class":89},"'button'",[42,844,156],{"class":48},[42,846,847,850,852],{"class":44,"line":373},[42,848,849],{"class":48},"    button.textContent ",[42,851,86],{"class":133},[42,853,854],{"class":89}," '切换'\n",[42,856,857,860,862,864,866,868,870],{"class":44,"line":378},[42,858,859],{"class":48},"    button.",[42,861,170],{"class":82},[42,863,150],{"class":48},[42,865,175],{"class":89},[42,867,178],{"class":48},[42,869,181],{"class":133},[42,871,184],{"class":48},[42,873,874,877,879,882],{"class":44,"line":390},[42,875,876],{"class":48},"      task.done ",[42,878,86],{"class":133},[42,880,881],{"class":133}," !",[42,883,884],{"class":48},"task.done\n",[42,886,887,890],{"class":44,"line":401},[42,888,889],{"class":82},"      renderTasks",[42,891,445],{"class":48},[42,893,894],{"class":44,"line":407},[42,895,896],{"class":48},"    })\n",[42,898,899],{"class":44,"line":412},[42,900,162],{"emptyLinePlaceholder":161},[42,902,903,906,909],{"class":44,"line":430},[42,904,905],{"class":48},"    item.",[42,907,908],{"class":82},"appendChild",[42,910,911],{"class":48},"(button)\n",[42,913,914,917,919],{"class":44,"line":439},[42,915,916],{"class":48},"    listEl.",[42,918,908],{"class":82},[42,920,921],{"class":48},"(item)\n",[42,923,924],{"class":44,"line":448},[42,925,451],{"class":48},[42,927,928],{"class":44,"line":454},[42,929,930],{"class":48},"}\n",[42,932,933],{"class":44,"line":459},[42,934,162],{"emptyLinePlaceholder":161},[42,936,937,940],{"class":44,"line":477},[42,938,939],{"class":82},"renderTasks",[42,941,445],{"class":48},[14,943,944],{},"这段代码能工作，但你要自己处理很多细节：",[508,946,947,950,953,956,959,962],{},[511,948,949],{},"清空旧列表。",[511,951,952],{},"创建每个 DOM 元素。",[511,954,955],{},"填入文字。",[511,957,958],{},"给每个按钮绑定事件。",[511,960,961],{},"数据变化后重新渲染。",[511,963,964],{},"删除任务、筛选任务、编辑任务时还要继续扩展。",[14,966,967],{},"项目越大，手动 DOM 同步越容易出现问题。",[21,969,971],{"id":970},"_4-vue-怎么写同一个列表","4. Vue 怎么写同一个列表",[32,973,977],{"className":974,"code":975,"language":976,"meta":37,"style":37},"language-vue shiki shiki-themes github-light github-dark","\u003Cscript setup>\nimport { ref } from 'vue'\n\nconst tasks = ref([\n  { id: 1, title: '学习 JS', done: false },\n  { id: 2, title: '学习 DOM', done: true }\n])\n\nfunction toggleTask(id) {\n  const task = tasks.value.find((item) => item.id === id)\n\n  if (task) {\n    task.done = !task.done\n  }\n}\n\u003C\u002Fscript>\n\n\u003Ctemplate>\n  \u003Cul>\n    \u003Cli v-for=\"task in tasks\" :key=\"task.id\">\n      \u003Cspan>{{ task.done ? '✅' : '⬜' }} {{ task.title }}\u003C\u002Fspan>\n      \u003Cbutton @click=\"toggleTask(task.id)\">切换\u003C\u002Fbutton>\n    \u003C\u002Fli>\n  \u003C\u002Ful>\n\u003C\u002Ftemplate>\n","vue",[39,978,979,990,1004,1008,1023,1039,1055,1060,1064,1079,1112,1116,1124,1135,1139,1143,1151,1155,1164,1172,1197,1211,1232,1241,1250],{"__ignoreMap":37},[42,980,981,983,985,988],{"class":44,"line":45},[42,982,49],{"class":48},[42,984,285],{"class":52},[42,986,987],{"class":82}," setup",[42,989,56],{"class":48},[42,991,992,995,998,1001],{"class":44,"line":59},[42,993,994],{"class":133},"import",[42,996,997],{"class":48}," { ref } ",[42,999,1000],{"class":133},"from",[42,1002,1003],{"class":89}," 'vue'\n",[42,1005,1006],{"class":44,"line":74},[42,1007,162],{"emptyLinePlaceholder":161},[42,1009,1010,1012,1015,1017,1020],{"class":44,"line":100},[42,1011,134],{"class":133},[42,1013,1014],{"class":137}," tasks",[42,1016,141],{"class":133},[42,1018,1019],{"class":82}," ref",[42,1021,1022],{"class":48},"([\n",[42,1024,1025,1027,1029,1031,1033,1035,1037],{"class":44,"line":202},[42,1026,620],{"class":48},[42,1028,623],{"class":137},[42,1030,626],{"class":48},[42,1032,629],{"class":89},[42,1034,632],{"class":48},[42,1036,635],{"class":137},[42,1038,638],{"class":48},[42,1040,1041,1043,1045,1047,1049,1051,1053],{"class":44,"line":290},[42,1042,620],{"class":48},[42,1044,645],{"class":137},[42,1046,626],{"class":48},[42,1048,650],{"class":89},[42,1050,632],{"class":48},[42,1052,655],{"class":137},[42,1054,658],{"class":48},[42,1056,1057],{"class":44,"line":304},[42,1058,1059],{"class":48},"])\n",[42,1061,1062],{"class":44,"line":309},[42,1063,162],{"emptyLinePlaceholder":161},[42,1065,1066,1068,1071,1073,1076],{"class":44,"line":331},[42,1067,725],{"class":133},[42,1069,1070],{"class":82}," toggleTask",[42,1072,150],{"class":48},[42,1074,1075],{"class":758},"id",[42,1077,1078],{"class":48},") {\n",[42,1080,1081,1083,1086,1088,1091,1094,1096,1099,1101,1103,1106,1109],{"class":44,"line":352},[42,1082,312],{"class":133},[42,1084,1085],{"class":137}," task",[42,1087,141],{"class":133},[42,1089,1090],{"class":48}," tasks.value.",[42,1092,1093],{"class":82},"find",[42,1095,755],{"class":48},[42,1097,1098],{"class":758},"item",[42,1100,762],{"class":48},[42,1102,181],{"class":133},[42,1104,1105],{"class":48}," item.id ",[42,1107,1108],{"class":133},"===",[42,1110,1111],{"class":48}," id)\n",[42,1113,1114],{"class":44,"line":373},[42,1115,162],{"emptyLinePlaceholder":161},[42,1117,1118,1121],{"class":44,"line":378},[42,1119,1120],{"class":133},"  if",[42,1122,1123],{"class":48}," (task) {\n",[42,1125,1126,1129,1131,1133],{"class":44,"line":390},[42,1127,1128],{"class":48},"    task.done ",[42,1130,86],{"class":133},[42,1132,881],{"class":133},[42,1134,884],{"class":48},[42,1136,1137],{"class":44,"line":401},[42,1138,404],{"class":48},[42,1140,1141],{"class":44,"line":407},[42,1142,930],{"class":48},[42,1144,1145,1147,1149],{"class":44,"line":412},[42,1146,103],{"class":48},[42,1148,285],{"class":52},[42,1150,56],{"class":48},[42,1152,1153],{"class":44,"line":430},[42,1154,162],{"emptyLinePlaceholder":161},[42,1156,1157,1159,1162],{"class":44,"line":439},[42,1158,49],{"class":48},[42,1160,1161],{"class":52},"template",[42,1163,56],{"class":48},[42,1165,1166,1168,1170],{"class":44,"line":448},[42,1167,62],{"class":48},[42,1169,508],{"class":52},[42,1171,56],{"class":48},[42,1173,1174,1177,1179,1182,1184,1187,1190,1192,1195],{"class":44,"line":454},[42,1175,1176],{"class":48},"    \u003C",[42,1178,511],{"class":52},[42,1180,1181],{"class":82}," v-for",[42,1183,86],{"class":48},[42,1185,1186],{"class":89},"\"task in tasks\"",[42,1188,1189],{"class":82}," :key",[42,1191,86],{"class":48},[42,1193,1194],{"class":89},"\"task.id\"",[42,1196,56],{"class":48},[42,1198,1199,1202,1204,1207,1209],{"class":44,"line":459},[42,1200,1201],{"class":48},"      \u003C",[42,1203,42],{"class":52},[42,1205,1206],{"class":48},">{{ task.done ? '✅' : '⬜' }} {{ task.title }}\u003C\u002F",[42,1208,42],{"class":52},[42,1210,56],{"class":48},[42,1212,1213,1215,1217,1220,1222,1225,1228,1230],{"class":44,"line":477},[42,1214,1201],{"class":48},[42,1216,79],{"class":52},[42,1218,1219],{"class":82}," @click",[42,1221,86],{"class":48},[42,1223,1224],{"class":89},"\"toggleTask(task.id)\"",[42,1226,1227],{"class":48},">切换\u003C\u002F",[42,1229,79],{"class":52},[42,1231,56],{"class":48},[42,1233,1234,1237,1239],{"class":44,"line":485},[42,1235,1236],{"class":48},"    \u003C\u002F",[42,1238,511],{"class":52},[42,1240,56],{"class":48},[42,1242,1243,1246,1248],{"class":44,"line":492},[42,1244,1245],{"class":48},"  \u003C\u002F",[42,1247,508],{"class":52},[42,1249,56],{"class":48},[42,1251,1252,1254,1256],{"class":44,"line":497},[42,1253,103],{"class":48},[42,1255,1161],{"class":52},[42,1257,56],{"class":48},[14,1259,1260],{},"这里发生了什么：",[508,1262,1263,1269,1275,1281,1287],{},[511,1264,1265,1268],{},[39,1266,1267],{},"tasks"," 是响应式数据。",[511,1270,1271,1274],{},[39,1272,1273],{},"v-for"," 根据数组渲染列表。",[511,1276,1277,1280],{},[39,1278,1279],{},"@click"," 绑定点击事件。",[511,1282,1283,1286],{},[39,1284,1285],{},"toggleTask"," 只负责改数据。",[511,1288,1289],{},"数据变化后，Vue 自动更新 DOM。",[14,1291,1292],{},"你不再手动写：",[32,1294,1296],{"className":124,"code":1295,"language":126,"meta":37,"style":37},"document.createElement(...)\nappendChild(...)\ntextContent = ...\ninnerHTML = ...\n",[39,1297,1298,1312,1322,1332],{"__ignoreMap":37},[42,1299,1300,1303,1305,1307,1310],{"class":44,"line":45},[42,1301,1302],{"class":48},"document.",[42,1304,781],{"class":82},[42,1306,150],{"class":48},[42,1308,1309],{"class":133},"...",[42,1311,156],{"class":48},[42,1313,1314,1316,1318,1320],{"class":44,"line":59},[42,1315,908],{"class":82},[42,1317,150],{"class":48},[42,1319,1309],{"class":133},[42,1321,156],{"class":48},[42,1323,1324,1327,1329],{"class":44,"line":74},[42,1325,1326],{"class":48},"textContent ",[42,1328,86],{"class":133},[42,1330,1331],{"class":133}," ...\n",[42,1333,1334,1337,1339],{"class":44,"line":100},[42,1335,1336],{"class":48},"innerHTML ",[42,1338,86],{"class":133},[42,1340,1331],{"class":133},[14,1342,1343],{},"Vue 的价值不是“少写几个字符”，而是让你把注意力从 DOM 操作转回数据和业务逻辑。",[21,1345,1347],{"id":1346},"_5-命令式和声明式","5. 命令式和声明式",[14,1349,1350],{},"原生 DOM 常见写法是命令式：你一步步命令浏览器怎么做。",[32,1352,1354],{"className":124,"code":1353,"language":126,"meta":37,"style":37},"const item = document.createElement('li')\nitem.textContent = task.title\nlistEl.appendChild(item)\n",[39,1355,1356,1374,1383],{"__ignoreMap":37},[42,1357,1358,1360,1362,1364,1366,1368,1370,1372],{"class":44,"line":45},[42,1359,134],{"class":133},[42,1361,774],{"class":137},[42,1363,141],{"class":133},[42,1365,144],{"class":48},[42,1367,781],{"class":82},[42,1369,150],{"class":48},[42,1371,786],{"class":89},[42,1373,156],{"class":48},[42,1375,1376,1379,1381],{"class":44,"line":59},[42,1377,1378],{"class":48},"item.textContent ",[42,1380,86],{"class":133},[42,1382,821],{"class":48},[42,1384,1385,1388,1390],{"class":44,"line":74},[42,1386,1387],{"class":48},"listEl.",[42,1389,908],{"class":82},[42,1391,921],{"class":48},[14,1393,1394],{},"Vue 模板是声明式：你描述“数据处于某种状态时，页面应该是什么样”。",[32,1396,1398],{"className":974,"code":1397,"language":976,"meta":37,"style":37},"\u003Cli v-for=\"task in tasks\" :key=\"task.id\">\n  {{ task.title }}\n\u003C\u002Fli>\n",[39,1399,1400,1439,1444],{"__ignoreMap":37},[42,1401,1402,1404,1406,1408,1410,1413,1416,1419,1421,1423,1425,1428,1430,1432,1435,1437],{"class":44,"line":45},[42,1403,49],{"class":48},[42,1405,511],{"class":52},[42,1407,1181],{"class":133},[42,1409,86],{"class":48},[42,1411,1412],{"class":89},"\"",[42,1414,1415],{"class":48},"task ",[42,1417,1418],{"class":133},"in",[42,1420,1014],{"class":48},[42,1422,1412],{"class":89},[42,1424,818],{"class":48},[42,1426,1427],{"class":82},"key",[42,1429,86],{"class":48},[42,1431,1412],{"class":89},[42,1433,1434],{"class":48},"task.id",[42,1436,1412],{"class":89},[42,1438,56],{"class":48},[42,1440,1441],{"class":44,"line":59},[42,1442,1443],{"class":48},"  {{ task.title }}\n",[42,1445,1446,1448,1450],{"class":44,"line":74},[42,1447,103],{"class":48},[42,1449,511],{"class":52},[42,1451,56],{"class":48},[14,1453,1454],{},"命令式关注“怎么做”，声明式关注“是什么”。",[14,1456,1457],{},"在复杂页面里，声明式更容易维护，因为你能直接看到：",[508,1459,1460,1463,1466],{},[511,1461,1462],{},"数据在哪里。",[511,1464,1465],{},"页面如何由数据得到。",[511,1467,1468],{},"用户操作如何修改数据。",[21,1470,1472],{"id":1471},"_6-vue-的核心循环","6. Vue 的核心循环",[14,1474,1475],{},"Vue 最重要的心智模型：",[32,1477,1480],{"className":1478,"code":1479,"language":116,"meta":37},[114],"状态 state\n  ↓\n模板 template 描述界面\n  ↓\n页面 UI\n  ↓\n用户点击、输入、请求返回\n  ↓\n修改状态 state\n  ↓\nVue 自动更新页面\n",[39,1481,1479],{"__ignoreMap":37},[14,1483,1484],{},"这条链路如果想清楚，很多 Vue 问题都会变简单。",[14,1486,1487],{},"例如输入框：",[32,1489,1491],{"className":974,"code":1490,"language":976,"meta":37,"style":37},"\u003Cscript setup>\nimport { ref } from 'vue'\n\nconst name = ref('')\n\u003C\u002Fscript>\n\n\u003Ctemplate>\n  \u003Cinput v-model=\"name\">\n  \u003Cp>你好，{{ name }}\u003C\u002Fp>\n\u003C\u002Ftemplate>\n",[39,1492,1493,1503,1513,1517,1535,1543,1547,1555,1572,1585],{"__ignoreMap":37},[42,1494,1495,1497,1499,1501],{"class":44,"line":45},[42,1496,49],{"class":48},[42,1498,285],{"class":52},[42,1500,987],{"class":82},[42,1502,56],{"class":48},[42,1504,1505,1507,1509,1511],{"class":44,"line":59},[42,1506,994],{"class":133},[42,1508,997],{"class":48},[42,1510,1000],{"class":133},[42,1512,1003],{"class":89},[42,1514,1515],{"class":44,"line":74},[42,1516,162],{"emptyLinePlaceholder":161},[42,1518,1519,1521,1524,1526,1528,1530,1533],{"class":44,"line":100},[42,1520,134],{"class":133},[42,1522,1523],{"class":137}," name",[42,1525,141],{"class":133},[42,1527,1019],{"class":82},[42,1529,150],{"class":48},[42,1531,1532],{"class":89},"''",[42,1534,156],{"class":48},[42,1536,1537,1539,1541],{"class":44,"line":202},[42,1538,103],{"class":48},[42,1540,285],{"class":52},[42,1542,56],{"class":48},[42,1544,1545],{"class":44,"line":290},[42,1546,162],{"emptyLinePlaceholder":161},[42,1548,1549,1551,1553],{"class":44,"line":304},[42,1550,49],{"class":48},[42,1552,1161],{"class":52},[42,1554,56],{"class":48},[42,1556,1557,1559,1562,1565,1567,1570],{"class":44,"line":309},[42,1558,62],{"class":48},[42,1560,1561],{"class":52},"input",[42,1563,1564],{"class":82}," v-model",[42,1566,86],{"class":48},[42,1568,1569],{"class":89},"\"name\"",[42,1571,56],{"class":48},[42,1573,1574,1576,1578,1581,1583],{"class":44,"line":331},[42,1575,62],{"class":48},[42,1577,14],{"class":52},[42,1579,1580],{"class":48},">你好，{{ name }}\u003C\u002F",[42,1582,14],{"class":52},[42,1584,56],{"class":48},[42,1586,1587,1589,1591],{"class":44,"line":352},[42,1588,103],{"class":48},[42,1590,1161],{"class":52},[42,1592,56],{"class":48},[14,1594,1595],{},"用户输入后：",[1597,1598,1599,1602,1611,1616,1622],"ol",{},[511,1600,1601],{},"输入框内容变化。",[511,1603,1604,1607,1608,538],{},[39,1605,1606],{},"v-model"," 更新 ",[39,1609,1610],{},"name",[511,1612,1613,1615],{},[39,1614,1610],{}," 是响应式状态。",[511,1617,1618,1619,538],{},"Vue 重新渲染 ",[39,1620,1621],{},"{{ name }}",[511,1623,1624],{},"页面显示新内容。",[21,1626,1628],{"id":1627},"_7-vue-不是完全不能操作-dom","7. Vue 不是完全不能操作 DOM",[14,1630,1631],{},"初学阶段建议：能用状态表达，就不要直接操作 DOM。",[14,1633,1634],{},"不推荐：",[32,1636,1638],{"className":124,"code":1637,"language":126,"meta":37,"style":37},"document.querySelector('.message').textContent = '保存成功'\n",[39,1639,1640],{"__ignoreMap":37},[42,1641,1642,1644,1646,1648,1651,1654,1656],{"class":44,"line":45},[42,1643,1302],{"class":48},[42,1645,147],{"class":82},[42,1647,150],{"class":48},[42,1649,1650],{"class":89},"'.message'",[42,1652,1653],{"class":48},").textContent ",[42,1655,86],{"class":133},[42,1657,1658],{"class":89}," '保存成功'\n",[14,1660,1661],{},"推荐：",[32,1663,1665],{"className":124,"code":1664,"language":126,"meta":37,"style":37},"const message = ref('')\n\nfunction save() {\n  message.value = '保存成功'\n}\n",[39,1666,1667,1684,1688,1697,1706],{"__ignoreMap":37},[42,1668,1669,1671,1674,1676,1678,1680,1682],{"class":44,"line":45},[42,1670,134],{"class":133},[42,1672,1673],{"class":137}," message",[42,1675,141],{"class":133},[42,1677,1019],{"class":82},[42,1679,150],{"class":48},[42,1681,1532],{"class":89},[42,1683,156],{"class":48},[42,1685,1686],{"class":44,"line":59},[42,1687,162],{"emptyLinePlaceholder":161},[42,1689,1690,1692,1695],{"class":44,"line":74},[42,1691,725],{"class":133},[42,1693,1694],{"class":82}," save",[42,1696,387],{"class":48},[42,1698,1699,1702,1704],{"class":44,"line":100},[42,1700,1701],{"class":48},"  message.value ",[42,1703,86],{"class":133},[42,1705,1658],{"class":89},[42,1707,1708],{"class":44,"line":202},[42,1709,930],{"class":48},[32,1711,1713],{"className":974,"code":1712,"language":976,"meta":37,"style":37},"\u003Cp class=\"message\">{{ message }}\u003C\u002Fp>\n",[39,1714,1715],{"__ignoreMap":37},[42,1716,1717,1719,1721,1724,1726,1729,1732,1734],{"class":44,"line":45},[42,1718,49],{"class":48},[42,1720,14],{"class":52},[42,1722,1723],{"class":82}," class",[42,1725,86],{"class":48},[42,1727,1728],{"class":89},"\"message\"",[42,1730,1731],{"class":48},">{{ message }}\u003C\u002F",[42,1733,14],{"class":52},[42,1735,56],{"class":48},[14,1737,1738],{},"但确实有些场景需要 DOM：",[508,1740,1741,1744,1747,1750,1753],{},[511,1742,1743],{},"页面加载后让输入框自动聚焦。",[511,1745,1746],{},"测量元素宽高。",[511,1748,1749],{},"集成第三方图表库。",[511,1751,1752],{},"操作 canvas。",[511,1754,1755],{},"调用浏览器原生 API。",[14,1757,1758],{},"Vue 提供模板引用：",[32,1760,1762],{"className":974,"code":1761,"language":976,"meta":37,"style":37},"\u003Cscript setup>\nimport { onMounted, ref } from 'vue'\n\nconst inputEl = ref(null)\n\nonMounted(() => {\n  inputEl.value.focus()\n})\n\u003C\u002Fscript>\n\n\u003Ctemplate>\n  \u003Cinput ref=\"inputEl\">\n\u003C\u002Ftemplate>\n",[39,1763,1764,1774,1785,1789,1807,1811,1823,1833,1837,1845,1849,1857,1872],{"__ignoreMap":37},[42,1765,1766,1768,1770,1772],{"class":44,"line":45},[42,1767,49],{"class":48},[42,1769,285],{"class":52},[42,1771,987],{"class":82},[42,1773,56],{"class":48},[42,1775,1776,1778,1781,1783],{"class":44,"line":59},[42,1777,994],{"class":133},[42,1779,1780],{"class":48}," { onMounted, ref } ",[42,1782,1000],{"class":133},[42,1784,1003],{"class":89},[42,1786,1787],{"class":44,"line":74},[42,1788,162],{"emptyLinePlaceholder":161},[42,1790,1791,1793,1796,1798,1800,1802,1805],{"class":44,"line":100},[42,1792,134],{"class":133},[42,1794,1795],{"class":137}," inputEl",[42,1797,141],{"class":133},[42,1799,1019],{"class":82},[42,1801,150],{"class":48},[42,1803,1804],{"class":137},"null",[42,1806,156],{"class":48},[42,1808,1809],{"class":44,"line":202},[42,1810,162],{"emptyLinePlaceholder":161},[42,1812,1813,1816,1819,1821],{"class":44,"line":290},[42,1814,1815],{"class":82},"onMounted",[42,1817,1818],{"class":48},"(() ",[42,1820,181],{"class":133},[42,1822,184],{"class":48},[42,1824,1825,1828,1831],{"class":44,"line":304},[42,1826,1827],{"class":48},"  inputEl.value.",[42,1829,1830],{"class":82},"focus",[42,1832,445],{"class":48},[42,1834,1835],{"class":44,"line":309},[42,1836,205],{"class":48},[42,1838,1839,1841,1843],{"class":44,"line":331},[42,1840,103],{"class":48},[42,1842,285],{"class":52},[42,1844,56],{"class":48},[42,1846,1847],{"class":44,"line":352},[42,1848,162],{"emptyLinePlaceholder":161},[42,1850,1851,1853,1855],{"class":44,"line":373},[42,1852,49],{"class":48},[42,1854,1161],{"class":52},[42,1856,56],{"class":48},[42,1858,1859,1861,1863,1865,1867,1870],{"class":44,"line":378},[42,1860,62],{"class":48},[42,1862,1561],{"class":52},[42,1864,1019],{"class":82},[42,1866,86],{"class":48},[42,1868,1869],{"class":89},"\"inputEl\"",[42,1871,56],{"class":48},[42,1873,1874,1876,1878],{"class":44,"line":390},[42,1875,103],{"class":48},[42,1877,1161],{"class":52},[42,1879,56],{"class":48},[14,1881,1882,1883,1886,1887,1890,1891,538],{},"这里的 ",[39,1884,1885],{},"ref=\"inputEl\""," 是模板引用，不是响应式 ",[39,1888,1889],{},"ref()"," 本身，但它们配合使用：Vue 会在组件挂载后把真实 DOM 元素放进 ",[39,1892,1893],{},"inputEl.value",[21,1895,1897],{"id":1896},"_8-cdn-示例和工程化项目的区别","8. CDN 示例和工程化项目的区别",[14,1899,1900],{},"你可以用 CDN 直接在 HTML 中使用 Vue：",[32,1902,1904],{"className":34,"code":1903,"language":36,"meta":37,"style":37},"\u003Cscript src=\"https:\u002F\u002Funpkg.com\u002Fvue@3\u002Fdist\u002Fvue.global.js\">\u003C\u002Fscript>\n",[39,1905,1906],{"__ignoreMap":37},[42,1907,1908,1910,1912,1915,1917,1920,1922,1924],{"class":44,"line":45},[42,1909,49],{"class":48},[42,1911,285],{"class":52},[42,1913,1914],{"class":82}," src",[42,1916,86],{"class":48},[42,1918,1919],{"class":89},"\"https:\u002F\u002Funpkg.com\u002Fvue@3\u002Fdist\u002Fvue.global.js\"",[42,1921,687],{"class":48},[42,1923,285],{"class":52},[42,1925,56],{"class":48},[14,1927,1928],{},"这适合入门理解：",[508,1930,1931,1934,1937],{},[511,1932,1933],{},"不需要安装 Node。",[511,1935,1936],{},"不需要 Vite。",[511,1938,1939],{},"一个 HTML 文件就能运行。",[14,1941,1942],{},"但正式项目通常使用 Vite：",[32,1944,1948],{"className":1945,"code":1946,"language":1947,"meta":37,"style":37},"language-powershell shiki shiki-themes github-light github-dark","npm create vue@latest\n","powershell",[39,1949,1950],{"__ignoreMap":37},[42,1951,1952],{"class":44,"line":45},[42,1953,1946],{},[14,1955,1956],{},"原因：",[508,1958,1959,1966,1973,1976,1979],{},[511,1960,1961,1962,1965],{},"可以写 ",[39,1963,1964],{},".vue"," 单文件组件。",[511,1967,1968,1969,1972],{},"可以用 ",[39,1970,1971],{},"import\u002Fexport"," 拆文件。",[511,1974,1975],{},"可以安装 Router、Pinia、测试工具。",[511,1977,1978],{},"可以构建生产产物。",[511,1980,1981],{},"开发时有热更新和错误提示。",[14,1983,1984,1985,1988,1989,1992],{},"本课程的 ",[39,1986,1987],{},"examples\u002Fcdn-basics\u002Findex.html"," 用来理解概念，",[39,1990,1991],{},"course-app"," 用来学习真实项目结构。",[21,1994,1996],{"id":1995},"_9-从-dom-思维迁移到-vue-思维","9. 从 DOM 思维迁移到 Vue 思维",[14,1998,1999],{},"当你想写：",[32,2001,2003],{"className":124,"code":2002,"language":126,"meta":37,"style":37},"document.querySelector(...)\nelement.textContent = ...\nelement.classList.add(...)\n",[39,2004,2005,2017,2026],{"__ignoreMap":37},[42,2006,2007,2009,2011,2013,2015],{"class":44,"line":45},[42,2008,1302],{"class":48},[42,2010,147],{"class":82},[42,2012,150],{"class":48},[42,2014,1309],{"class":133},[42,2016,156],{"class":48},[42,2018,2019,2022,2024],{"class":44,"line":59},[42,2020,2021],{"class":48},"element.textContent ",[42,2023,86],{"class":133},[42,2025,1331],{"class":133},[42,2027,2028,2031,2034,2036,2038],{"class":44,"line":74},[42,2029,2030],{"class":48},"element.classList.",[42,2032,2033],{"class":82},"add",[42,2035,150],{"class":48},[42,2037,1309],{"class":133},[42,2039,156],{"class":48},[14,2041,2042],{},"先停一下，问：",[1597,2044,2045,2048,2059],{},[511,2046,2047],{},"我真正想表达的状态是什么？",[511,2049,2050,2051,2054,2055,2058],{},"这个状态能不能用 ",[39,2052,2053],{},"ref"," 或 ",[39,2056,2057],{},"computed"," 表示？",[511,2060,2061],{},"模板能不能根据这个状态显示不同内容或 class？",[14,2063,2064],{},"例如按钮禁用：",[14,2066,2067],{},"原生 DOM 思维：",[32,2069,2071],{"className":124,"code":2070,"language":126,"meta":37,"style":37},"button.disabled = title.length === 0\n",[39,2072,2073],{"__ignoreMap":37},[42,2074,2075,2078,2080,2083,2086,2089],{"class":44,"line":45},[42,2076,2077],{"class":48},"button.disabled ",[42,2079,86],{"class":133},[42,2081,2082],{"class":48}," title.",[42,2084,2085],{"class":137},"length",[42,2087,2088],{"class":133}," ===",[42,2090,301],{"class":137},[14,2092,2093],{},"Vue 思维：",[32,2095,2097],{"className":974,"code":2096,"language":976,"meta":37,"style":37},"\u003Cbutton :disabled=\"title.length === 0\">提交\u003C\u002Fbutton>\n",[39,2098,2099],{"__ignoreMap":37},[42,2100,2101,2103,2105,2107,2110,2112,2114,2117,2119,2121,2124,2126,2129,2131],{"class":44,"line":45},[42,2102,49],{"class":48},[42,2104,79],{"class":52},[42,2106,818],{"class":48},[42,2108,2109],{"class":82},"disabled",[42,2111,86],{"class":48},[42,2113,1412],{"class":89},[42,2115,2116],{"class":48},"title.",[42,2118,2085],{"class":137},[42,2120,2088],{"class":133},[42,2122,2123],{"class":137}," 0",[42,2125,1412],{"class":89},[42,2127,2128],{"class":48},">提交\u003C\u002F",[42,2130,79],{"class":52},[42,2132,56],{"class":48},[14,2134,2135],{},"例如错误样式：",[14,2137,2067],{},[32,2139,2141],{"className":124,"code":2140,"language":126,"meta":37,"style":37},"if (hasError) {\n  input.classList.add('error')\n} else {\n  input.classList.remove('error')\n}\n",[39,2142,2143,2151,2165,2175,2188],{"__ignoreMap":37},[42,2144,2145,2148],{"class":44,"line":45},[42,2146,2147],{"class":133},"if",[42,2149,2150],{"class":48}," (hasError) {\n",[42,2152,2153,2156,2158,2160,2163],{"class":44,"line":59},[42,2154,2155],{"class":48},"  input.classList.",[42,2157,2033],{"class":82},[42,2159,150],{"class":48},[42,2161,2162],{"class":89},"'error'",[42,2164,156],{"class":48},[42,2166,2167,2170,2173],{"class":44,"line":74},[42,2168,2169],{"class":48},"} ",[42,2171,2172],{"class":133},"else",[42,2174,184],{"class":48},[42,2176,2177,2179,2182,2184,2186],{"class":44,"line":100},[42,2178,2155],{"class":48},[42,2180,2181],{"class":82},"remove",[42,2183,150],{"class":48},[42,2185,2162],{"class":89},[42,2187,156],{"class":48},[42,2189,2190],{"class":44,"line":202},[42,2191,930],{"class":48},[14,2193,2093],{},[32,2195,2197],{"className":974,"code":2196,"language":976,"meta":37,"style":37},"\u003Cinput :class=\"{ error: hasError }\">\n",[39,2198,2199],{"__ignoreMap":37},[42,2200,2201,2203,2205,2207,2210,2212,2214,2217,2219],{"class":44,"line":45},[42,2202,49],{"class":48},[42,2204,1561],{"class":52},[42,2206,818],{"class":48},[42,2208,2209],{"class":82},"class",[42,2211,86],{"class":48},[42,2213,1412],{"class":89},[42,2215,2216],{"class":48},"{ error: hasError }",[42,2218,1412],{"class":89},[42,2220,56],{"class":48},[21,2222,2224],{"id":2223},"_10-常见误区","10. 常见误区",[2226,2227,2229],"h3",{"id":2228},"误区一vue-会自动理解普通变量","误区一：Vue 会自动理解普通变量",[32,2231,2233],{"className":124,"code":2232,"language":126,"meta":37,"style":37},"let count = 0\n",[39,2234,2235],{"__ignoreMap":37},[42,2236,2237,2239,2241,2243],{"class":44,"line":45},[42,2238,607],{"class":133},[42,2240,296],{"class":48},[42,2242,86],{"class":133},[42,2244,301],{"class":137},[14,2246,2247],{},"普通变量变化，Vue 不会自动更新模板。需要：",[32,2249,2251],{"className":124,"code":2250,"language":126,"meta":37,"style":37},"const count = ref(0)\n",[39,2252,2253],{"__ignoreMap":37},[42,2254,2255,2257,2260,2262,2264,2266,2269],{"class":44,"line":45},[42,2256,134],{"class":133},[42,2258,2259],{"class":137}," count",[42,2261,141],{"class":133},[42,2263,1019],{"class":82},[42,2265,150],{"class":48},[42,2267,2268],{"class":137},"0",[42,2270,156],{"class":48},[2226,2272,2274],{"id":2273},"误区二一边用-vue一边大量-queryselector","误区二：一边用 Vue，一边大量 querySelector",[14,2276,2277],{},"如果你在 Vue 组件里到处写：",[32,2279,2281],{"className":124,"code":2280,"language":126,"meta":37,"style":37},"document.querySelector(...)\n",[39,2282,2283],{"__ignoreMap":37},[42,2284,2285,2287,2289,2291,2293],{"class":44,"line":45},[42,2286,1302],{"class":48},[42,2288,147],{"class":82},[42,2290,150],{"class":48},[42,2292,1309],{"class":133},[42,2294,156],{"class":48},[14,2296,2297],{},"往往说明你还没有用状态表达界面。只有真实需要 DOM 本身时才这样做。",[2226,2299,2301],{"id":2300},"误区三以为模板只是-html","误区三：以为模板只是 HTML",[14,2303,2304],{},"Vue 模板看起来像 HTML，但它多了指令：",[508,2306,2307,2312,2316,2320,2325],{},[511,2308,2309],{},[39,2310,2311],{},"v-if",[511,2313,2314],{},[39,2315,1273],{},[511,2317,2318],{},[39,2319,1606],{},[511,2321,2322],{},[39,2323,2324],{},":class",[511,2326,2327],{},[39,2328,1279],{},[14,2330,2331],{},"这些指令让模板和响应式状态连接起来。",[2226,2333,2335],{"id":2334},"误区四数据结构不清晰就开始写界面","误区四：数据结构不清晰就开始写界面",[14,2337,2338],{},"先想数据：",[32,2340,2342],{"className":124,"code":2341,"language":126,"meta":37,"style":37},"const tasks = [\n  { id: 1, title: '学习 Vue', done: false }\n]\n",[39,2343,2344,2354,2371],{"__ignoreMap":37},[42,2345,2346,2348,2350,2352],{"class":44,"line":45},[42,2347,134],{"class":133},[42,2349,1014],{"class":137},[42,2351,141],{"class":133},[42,2353,615],{"class":48},[42,2355,2356,2358,2360,2362,2365,2367,2369],{"class":44,"line":59},[42,2357,620],{"class":48},[42,2359,623],{"class":137},[42,2361,626],{"class":48},[42,2363,2364],{"class":89},"'学习 Vue'",[42,2366,632],{"class":48},[42,2368,635],{"class":137},[42,2370,658],{"class":48},[42,2372,2373],{"class":44,"line":74},[42,2374,663],{"class":48},[14,2376,2377],{},"再想界面如何显示这些数据。不要反过来先堆 HTML，再到处找地方塞逻辑。",[21,2379,2380],{"id":2380},"本章练习",[2226,2382,2384],{"id":2383},"练习-1原生-dom-任务列表","练习 1：原生 DOM 任务列表",[14,2386,2387],{},"用原生 DOM 写一个页面：",[508,2389,2390,2393,2396,2399],{},[511,2391,2392],{},"输入框输入任务标题。",[511,2394,2395],{},"点击按钮新增任务。",[511,2397,2398],{},"列表显示所有任务。",[511,2400,2401],{},"点击任务按钮切换完成状态。",[14,2403,2404,2405,2407],{},"要求你必须写一个 ",[39,2406,527],{}," 函数，每次数据变化后调用。",[2226,2409,2411],{"id":2410},"练习-2vue-任务列表","练习 2：Vue 任务列表",[14,2413,2414],{},"用 Vue 写同样功能：",[508,2416,2417,2425,2430,2435],{},[511,2418,2419,2421,2422,538],{},[39,2420,1267],{}," 使用 ",[39,2423,2424],{},"ref([])",[511,2426,2427,2428,538],{},"表单输入使用 ",[39,2429,1606],{},[511,2431,2432,2433,538],{},"列表使用 ",[39,2434,1273],{},[511,2436,2437],{},"点击按钮只修改数据，不手动创建 DOM。",[2226,2439,2441],{"id":2440},"练习-3对比总结","练习 3：对比总结",[14,2443,2444],{},"回答：",[1597,2446,2447,2450,2453,2459],{},[511,2448,2449],{},"原生 DOM 版本中，数据在哪里？DOM 更新在哪里？",[511,2451,2452],{},"Vue 版本中，数据在哪里？DOM 更新是谁做的？",[511,2454,2455,2456,2458],{},"为什么忘记调用 ",[39,2457,527],{}," 会导致界面和数据不同步？",[511,2460,2461],{},"Vue 中什么时候仍然需要模板引用拿 DOM？",[2463,2464,2465],"style",{},"html pre.shiki code .sVt8B, html code.shiki .sVt8B{--shiki-default:#24292E;--shiki-dark:#E1E4E8}html pre.shiki code .s9eBZ, html code.shiki .s9eBZ{--shiki-default:#22863A;--shiki-dark:#85E89D}html pre.shiki code .sScJk, html code.shiki .sScJk{--shiki-default:#6F42C1;--shiki-dark:#B392F0}html pre.shiki code .sZZnC, html code.shiki .sZZnC{--shiki-default:#032F62;--shiki-dark:#9ECBFF}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html pre.shiki code .szBVR, html code.shiki .szBVR{--shiki-default:#D73A49;--shiki-dark:#F97583}html pre.shiki code .sj4cs, html code.shiki .sj4cs{--shiki-default:#005CC5;--shiki-dark:#79B8FF}html pre.shiki code .sJ8bj, html code.shiki .sJ8bj{--shiki-default:#6A737D;--shiki-dark:#6A737D}html pre.shiki code .s4XuR, html code.shiki .s4XuR{--shiki-default:#E36209;--shiki-dark:#FFAB70}",{"title":37,"searchDepth":59,"depth":59,"links":2467},[2468,2469,2470,2471,2472,2473,2474,2475,2476,2477,2483],{"id":23,"depth":59,"text":24},{"id":208,"depth":59,"text":209},{"id":593,"depth":59,"text":594},{"id":970,"depth":59,"text":971},{"id":1346,"depth":59,"text":1347},{"id":1471,"depth":59,"text":1472},{"id":1627,"depth":59,"text":1628},{"id":1896,"depth":59,"text":1897},{"id":1995,"depth":59,"text":1996},{"id":2223,"depth":59,"text":2224,"children":2478},[2479,2480,2481,2482],{"id":2228,"depth":74,"text":2229},{"id":2273,"depth":74,"text":2274},{"id":2300,"depth":74,"text":2301},{"id":2334,"depth":74,"text":2335},{"id":2380,"depth":59,"text":2380,"children":2484},[2485,2486,2487],{"id":2383,"depth":74,"text":2384},{"id":2410,"depth":74,"text":2411},{"id":2440,"depth":74,"text":2441},"md",{"order":59},"\u002Fsource\u002Fcode\u002Fvue\u002F02-dom-to-vue",{"title":5,"description":16},"source\u002Fcode\u002Fvue\u002F02-dom-to-vue","llNR4TmRVo9u4Gcp0XmoIoqlnl1gdOCrG5Sy82vCeJc",1784032889391]