[{"data":1,"prerenderedAt":3593},["ShallowReactive",2],{"note:code\u002Fvue\u002F03-vue-core":3},{"id":4,"title":5,"body":6,"description":16,"extension":3587,"meta":3588,"navigation":109,"path":3589,"seo":3590,"stem":3591,"__hash__":3592},"notes\u002Fsource\u002Fcode\u002Fvue\u002F03-vue-core.md","03 Vue 核心语法和响应式",{"type":7,"value":8,"toc":3542},"minimark",[9,13,17,36,41,47,201,204,230,234,237,248,254,268,275,278,345,350,415,421,424,572,579,582,626,629,640,643,661,667,763,781,788,924,931,937,964,967,979,984,993,996,1000,1003,1021,1030,1038,1043,1111,1116,1141,1144,1176,1185,1188,1218,1220,1269,1276,1285,1338,1344,1370,1380,1383,1395,1402,1410,1468,1477,1480,1514,1517,1542,1575,1578,1611,1617,1653,1659,1666,1736,1741,1747,1778,1781,1793,1801,1808,1872,1875,1898,1904,1909,1912,1915,1969,1971,2024,2027,2034,2039,2152,2154,2172,2175,2178,2215,2228,2231,2233,2266,2273,2275,2320,2327,2332,2391,2394,2414,2422,2427,2478,2483,2523,2531,2535,2541,2588,2591,2602,2608,2719,2722,2726,2729,2849,2851,2871,2875,3453,3456,3495,3498,3539],[10,11,5],"h1",{"id":12},"_03-vue-核心语法和响应式",[14,15,16],"p",{},"本章开始正式写 Vue。你需要掌握 Vue 单文件组件、响应式状态、模板语法、计算属性、监听器和生命周期。",[14,18,19,20,24,25,28,29,28,32,35],{},"核心目标：你看到一个 ",[21,22,23],"code",{},".vue"," 文件时，能知道每个区域负责什么；看到 ",[21,26,27],{},"ref","、",[21,30,31],{},"computed",[21,33,34],{},"watch"," 时，知道为什么用它们。",[37,38,40],"h2",{"id":39},"_1-单文件组件是什么","1. 单文件组件是什么",[14,42,43,44,46],{},"Vue 项目里最常见的文件是 ",[21,45,23],{}," 文件，也叫单文件组件，英文是 Single File Component，简称 SFC。",[48,49,54],"pre",{"className":50,"code":51,"language":52,"meta":53,"style":53},"language-vue shiki shiki-themes github-light github-dark","\u003Cscript setup>\nconst title = 'Vue 核心语法'\n\u003C\u002Fscript>\n\n\u003Ctemplate>\n  \u003Ch1>{{ title }}\u003C\u002Fh1>\n\u003C\u002Ftemplate>\n\n\u003Cstyle scoped>\nh1 {\n  color: #2563eb;\n}\n\u003C\u002Fstyle>\n","vue","",[21,55,56,76,94,104,111,121,136,145,150,163,171,186,192],{"__ignoreMap":53},[57,58,61,65,69,73],"span",{"class":59,"line":60},"line",1,[57,62,64],{"class":63},"sVt8B","\u003C",[57,66,68],{"class":67},"s9eBZ","script",[57,70,72],{"class":71},"sScJk"," setup",[57,74,75],{"class":63},">\n",[57,77,79,83,87,90],{"class":59,"line":78},2,[57,80,82],{"class":81},"szBVR","const",[57,84,86],{"class":85},"sj4cs"," title",[57,88,89],{"class":81}," =",[57,91,93],{"class":92},"sZZnC"," 'Vue 核心语法'\n",[57,95,97,100,102],{"class":59,"line":96},3,[57,98,99],{"class":63},"\u003C\u002F",[57,101,68],{"class":67},[57,103,75],{"class":63},[57,105,107],{"class":59,"line":106},4,[57,108,110],{"emptyLinePlaceholder":109},true,"\n",[57,112,114,116,119],{"class":59,"line":113},5,[57,115,64],{"class":63},[57,117,118],{"class":67},"template",[57,120,75],{"class":63},[57,122,124,127,129,132,134],{"class":59,"line":123},6,[57,125,126],{"class":63},"  \u003C",[57,128,10],{"class":67},[57,130,131],{"class":63},">{{ title }}\u003C\u002F",[57,133,10],{"class":67},[57,135,75],{"class":63},[57,137,139,141,143],{"class":59,"line":138},7,[57,140,99],{"class":63},[57,142,118],{"class":67},[57,144,75],{"class":63},[57,146,148],{"class":59,"line":147},8,[57,149,110],{"emptyLinePlaceholder":109},[57,151,153,155,158,161],{"class":59,"line":152},9,[57,154,64],{"class":63},[57,156,157],{"class":67},"style",[57,159,160],{"class":71}," scoped",[57,162,75],{"class":63},[57,164,166,168],{"class":59,"line":165},10,[57,167,10],{"class":67},[57,169,170],{"class":63}," {\n",[57,172,174,177,180,183],{"class":59,"line":173},11,[57,175,176],{"class":85},"  color",[57,178,179],{"class":63},": ",[57,181,182],{"class":85},"#2563eb",[57,184,185],{"class":63},";\n",[57,187,189],{"class":59,"line":188},12,[57,190,191],{"class":63},"}\n",[57,193,195,197,199],{"class":59,"line":194},13,[57,196,99],{"class":63},[57,198,157],{"class":67},[57,200,75],{"class":63},[14,202,203],{},"三个区域：",[205,206,207,214,220],"ul",{},[208,209,210,213],"li",{},[21,211,212],{},"\u003Cscript setup>","：写 JavaScript 逻辑，例如状态、函数、导入组件。",[208,215,216,219],{},[21,217,218],{},"\u003Ctemplate>","：写界面结构，并通过 Vue 指令连接状态。",[208,221,222,225,226,229],{},[21,223,224],{},"\u003Cstyle scoped>","：写当前组件样式，",[21,227,228],{},"scoped"," 表示尽量只影响当前组件。",[231,232,233],"h3",{"id":233},"为什么要单文件组件",[14,235,236],{},"一个组件通常包含三类内容：",[205,238,239,242,245],{},[208,240,241],{},"数据和行为。",[208,243,244],{},"HTML 结构。",[208,246,247],{},"样式。",[14,249,250,251,253],{},"把它们放在同一个 ",[21,252,23],{}," 文件里，有几个好处：",[205,255,256,259,262,265],{},[208,257,258],{},"组件的所有内容集中，容易理解。",[208,260,261],{},"可以直接导入另一个组件。",[208,263,264],{},"样式可以限制在组件内部。",[208,266,267],{},"构建工具能检查语法并优化代码。",[37,269,271,272,274],{"id":270},"_2-script-setup-为什么不用-return","2. ",[21,273,212],{}," 为什么不用 return",[14,276,277],{},"普通 Vue 组件可能这样写：",[48,279,283],{"className":280,"code":281,"language":282,"meta":53,"style":53},"language-js shiki shiki-themes github-light github-dark","export default {\n  setup() {\n    const title = 'Vue'\n\n    return {\n      title\n    }\n  }\n}\n","js",[21,284,285,295,303,315,319,326,331,336,341],{"__ignoreMap":53},[57,286,287,290,293],{"class":59,"line":60},[57,288,289],{"class":81},"export",[57,291,292],{"class":81}," default",[57,294,170],{"class":63},[57,296,297,300],{"class":59,"line":78},[57,298,299],{"class":71},"  setup",[57,301,302],{"class":63},"() {\n",[57,304,305,308,310,312],{"class":59,"line":96},[57,306,307],{"class":81},"    const",[57,309,86],{"class":85},[57,311,89],{"class":81},[57,313,314],{"class":92}," 'Vue'\n",[57,316,317],{"class":59,"line":106},[57,318,110],{"emptyLinePlaceholder":109},[57,320,321,324],{"class":59,"line":113},[57,322,323],{"class":81},"    return",[57,325,170],{"class":63},[57,327,328],{"class":59,"line":123},[57,329,330],{"class":63},"      title\n",[57,332,333],{"class":59,"line":138},[57,334,335],{"class":63},"    }\n",[57,337,338],{"class":59,"line":147},[57,339,340],{"class":63},"  }\n",[57,342,343],{"class":59,"line":152},[57,344,191],{"class":63},[14,346,347,349],{},[21,348,212],{}," 是更简洁的写法：",[48,351,353],{"className":50,"code":352,"language":52,"meta":53,"style":53},"\u003Cscript setup>\nconst title = 'Vue'\n\u003C\u002Fscript>\n\n\u003Ctemplate>\n  \u003Ch1>{{ title }}\u003C\u002Fh1>\n\u003C\u002Ftemplate>\n",[21,354,355,365,375,383,387,395,407],{"__ignoreMap":53},[57,356,357,359,361,363],{"class":59,"line":60},[57,358,64],{"class":63},[57,360,68],{"class":67},[57,362,72],{"class":71},[57,364,75],{"class":63},[57,366,367,369,371,373],{"class":59,"line":78},[57,368,82],{"class":81},[57,370,86],{"class":85},[57,372,89],{"class":81},[57,374,314],{"class":92},[57,376,377,379,381],{"class":59,"line":96},[57,378,99],{"class":63},[57,380,68],{"class":67},[57,382,75],{"class":63},[57,384,385],{"class":59,"line":106},[57,386,110],{"emptyLinePlaceholder":109},[57,388,389,391,393],{"class":59,"line":113},[57,390,64],{"class":63},[57,392,118],{"class":67},[57,394,75],{"class":63},[57,396,397,399,401,403,405],{"class":59,"line":123},[57,398,126],{"class":63},[57,400,10],{"class":67},[57,402,131],{"class":63},[57,404,10],{"class":67},[57,406,75],{"class":63},[57,408,409,411,413],{"class":59,"line":138},[57,410,99],{"class":63},[57,412,118],{"class":67},[57,414,75],{"class":63},[14,416,417,418,420],{},"在 ",[21,419,212],{}," 里，顶层声明的变量、函数、导入的组件，都可以直接在模板里使用。",[14,422,423],{},"例如：",[48,425,427],{"className":50,"code":426,"language":52,"meta":53,"style":53},"\u003Cscript setup>\nimport LessonCard from '.\u002FLessonCard.vue'\n\nconst lesson = { title: '组件基础' }\n\nfunction save() {\n  console.log('保存')\n}\n\u003C\u002Fscript>\n\n\u003Ctemplate>\n  \u003CLessonCard \u002F>\n  \u003Cbutton @click=\"save\">{{ lesson.title }}\u003C\u002Fbutton>\n\u003C\u002Ftemplate>\n",[21,428,429,439,453,457,475,479,489,506,510,518,522,530,540,563],{"__ignoreMap":53},[57,430,431,433,435,437],{"class":59,"line":60},[57,432,64],{"class":63},[57,434,68],{"class":67},[57,436,72],{"class":71},[57,438,75],{"class":63},[57,440,441,444,447,450],{"class":59,"line":78},[57,442,443],{"class":81},"import",[57,445,446],{"class":63}," LessonCard ",[57,448,449],{"class":81},"from",[57,451,452],{"class":92}," '.\u002FLessonCard.vue'\n",[57,454,455],{"class":59,"line":96},[57,456,110],{"emptyLinePlaceholder":109},[57,458,459,461,464,466,469,472],{"class":59,"line":106},[57,460,82],{"class":81},[57,462,463],{"class":85}," lesson",[57,465,89],{"class":81},[57,467,468],{"class":63}," { title: ",[57,470,471],{"class":92},"'组件基础'",[57,473,474],{"class":63}," }\n",[57,476,477],{"class":59,"line":113},[57,478,110],{"emptyLinePlaceholder":109},[57,480,481,484,487],{"class":59,"line":123},[57,482,483],{"class":81},"function",[57,485,486],{"class":71}," save",[57,488,302],{"class":63},[57,490,491,494,497,500,503],{"class":59,"line":138},[57,492,493],{"class":63},"  console.",[57,495,496],{"class":71},"log",[57,498,499],{"class":63},"(",[57,501,502],{"class":92},"'保存'",[57,504,505],{"class":63},")\n",[57,507,508],{"class":59,"line":147},[57,509,191],{"class":63},[57,511,512,514,516],{"class":59,"line":152},[57,513,99],{"class":63},[57,515,68],{"class":67},[57,517,75],{"class":63},[57,519,520],{"class":59,"line":165},[57,521,110],{"emptyLinePlaceholder":109},[57,523,524,526,528],{"class":59,"line":173},[57,525,64],{"class":63},[57,527,118],{"class":67},[57,529,75],{"class":63},[57,531,532,534,537],{"class":59,"line":188},[57,533,126],{"class":63},[57,535,536],{"class":67},"LessonCard",[57,538,539],{"class":63}," \u002F>\n",[57,541,542,544,547,550,553,556,559,561],{"class":59,"line":194},[57,543,126],{"class":63},[57,545,546],{"class":67},"button",[57,548,549],{"class":71}," @click",[57,551,552],{"class":63},"=",[57,554,555],{"class":92},"\"save\"",[57,557,558],{"class":63},">{{ lesson.title }}\u003C\u002F",[57,560,546],{"class":67},[57,562,75],{"class":63},[57,564,566,568,570],{"class":59,"line":565},14,[57,567,99],{"class":63},[57,569,118],{"class":67},[57,571,75],{"class":63},[37,573,575,576],{"id":574},"_3-插值表达式","3. 插值表达式 ",[21,577,578],{},"{{ }}",[14,580,581],{},"插值表达式用于显示文本。",[48,583,585],{"className":50,"code":584,"language":52,"meta":53,"style":53},"\u003Cp>{{ message }}\u003C\u002Fp>\n\u003Cp>{{ count + 1 }}\u003C\u002Fp>\n\u003Cp>{{ user.name }}\u003C\u002Fp>\n",[21,586,587,600,613],{"__ignoreMap":53},[57,588,589,591,593,596,598],{"class":59,"line":60},[57,590,64],{"class":63},[57,592,14],{"class":67},[57,594,595],{"class":63},">{{ message }}\u003C\u002F",[57,597,14],{"class":67},[57,599,75],{"class":63},[57,601,602,604,606,609,611],{"class":59,"line":78},[57,603,64],{"class":63},[57,605,14],{"class":67},[57,607,608],{"class":63},">{{ count + 1 }}\u003C\u002F",[57,610,14],{"class":67},[57,612,75],{"class":63},[57,614,615,617,619,622,624],{"class":59,"line":96},[57,616,64],{"class":63},[57,618,14],{"class":67},[57,620,621],{"class":63},">{{ user.name }}\u003C\u002F",[57,623,14],{"class":67},[57,625,75],{"class":63},[14,627,628],{},"注意：",[205,630,631,634,637],{},[208,632,633],{},"插值会被当成文本显示。",[208,635,636],{},"Vue 会默认转义内容，减少 XSS 风险。",[208,638,639],{},"不要在插值里写很复杂的逻辑。",[14,641,642],{},"不推荐：",[48,644,646],{"className":50,"code":645,"language":52,"meta":53,"style":53},"\u003Cp>{{ tasks.filter(task => !task.done).map(task => task.title).join(', ') }}\u003C\u002Fp>\n",[21,647,648],{"__ignoreMap":53},[57,649,650,652,654,657,659],{"class":59,"line":60},[57,651,64],{"class":63},[57,653,14],{"class":67},[57,655,656],{"class":63},">{{ tasks.filter(task => !task.done).map(task => task.title).join(', ') }}\u003C\u002F",[57,658,14],{"class":67},[57,660,75],{"class":63},[14,662,663,664,666],{},"推荐用 ",[21,665,31],{},"：",[48,668,670],{"className":280,"code":669,"language":282,"meta":53,"style":53},"const activeTaskTitles = computed(() => {\n  return tasks.value\n    .filter((task) => !task.done)\n    .map((task) => task.title)\n    .join(', ')\n})\n",[21,671,672,692,700,726,744,758],{"__ignoreMap":53},[57,673,674,676,679,681,684,687,690],{"class":59,"line":60},[57,675,82],{"class":81},[57,677,678],{"class":85}," activeTaskTitles",[57,680,89],{"class":81},[57,682,683],{"class":71}," computed",[57,685,686],{"class":63},"(() ",[57,688,689],{"class":81},"=>",[57,691,170],{"class":63},[57,693,694,697],{"class":59,"line":78},[57,695,696],{"class":81},"  return",[57,698,699],{"class":63}," tasks.value\n",[57,701,702,705,708,711,715,718,720,723],{"class":59,"line":96},[57,703,704],{"class":63},"    .",[57,706,707],{"class":71},"filter",[57,709,710],{"class":63},"((",[57,712,714],{"class":713},"s4XuR","task",[57,716,717],{"class":63},") ",[57,719,689],{"class":81},[57,721,722],{"class":81}," !",[57,724,725],{"class":63},"task.done)\n",[57,727,728,730,733,735,737,739,741],{"class":59,"line":106},[57,729,704],{"class":63},[57,731,732],{"class":71},"map",[57,734,710],{"class":63},[57,736,714],{"class":713},[57,738,717],{"class":63},[57,740,689],{"class":81},[57,742,743],{"class":63}," task.title)\n",[57,745,746,748,751,753,756],{"class":59,"line":113},[57,747,704],{"class":63},[57,749,750],{"class":71},"join",[57,752,499],{"class":63},[57,754,755],{"class":92},"', '",[57,757,505],{"class":63},[57,759,760],{"class":59,"line":123},[57,761,762],{"class":63},"})\n",[48,764,766],{"className":50,"code":765,"language":52,"meta":53,"style":53},"\u003Cp>{{ activeTaskTitles }}\u003C\u002Fp>\n",[21,767,768],{"__ignoreMap":53},[57,769,770,772,774,777,779],{"class":59,"line":60},[57,771,64],{"class":63},[57,773,14],{"class":67},[57,775,776],{"class":63},">{{ activeTaskTitles }}\u003C\u002F",[57,778,14],{"class":67},[57,780,75],{"class":63},[37,782,784,785,787],{"id":783},"_4-ref最常用的响应式状态","4. ",[21,786,27],{},"：最常用的响应式状态",[48,789,791],{"className":50,"code":790,"language":52,"meta":53,"style":53},"\u003Cscript setup>\nimport { ref } from 'vue'\n\nconst count = ref(0)\n\nfunction increase() {\n  count.value++\n}\n\u003C\u002Fscript>\n\n\u003Ctemplate>\n  \u003Cbutton @click=\"increase\">增加\u003C\u002Fbutton>\n  \u003Cp>{{ count }}\u003C\u002Fp>\n\u003C\u002Ftemplate>\n",[21,792,793,803,815,819,838,842,851,859,863,871,875,883,903,916],{"__ignoreMap":53},[57,794,795,797,799,801],{"class":59,"line":60},[57,796,64],{"class":63},[57,798,68],{"class":67},[57,800,72],{"class":71},[57,802,75],{"class":63},[57,804,805,807,810,812],{"class":59,"line":78},[57,806,443],{"class":81},[57,808,809],{"class":63}," { ref } ",[57,811,449],{"class":81},[57,813,814],{"class":92}," 'vue'\n",[57,816,817],{"class":59,"line":96},[57,818,110],{"emptyLinePlaceholder":109},[57,820,821,823,826,828,831,833,836],{"class":59,"line":106},[57,822,82],{"class":81},[57,824,825],{"class":85}," count",[57,827,89],{"class":81},[57,829,830],{"class":71}," ref",[57,832,499],{"class":63},[57,834,835],{"class":85},"0",[57,837,505],{"class":63},[57,839,840],{"class":59,"line":113},[57,841,110],{"emptyLinePlaceholder":109},[57,843,844,846,849],{"class":59,"line":123},[57,845,483],{"class":81},[57,847,848],{"class":71}," increase",[57,850,302],{"class":63},[57,852,853,856],{"class":59,"line":138},[57,854,855],{"class":63},"  count.value",[57,857,858],{"class":81},"++\n",[57,860,861],{"class":59,"line":147},[57,862,191],{"class":63},[57,864,865,867,869],{"class":59,"line":152},[57,866,99],{"class":63},[57,868,68],{"class":67},[57,870,75],{"class":63},[57,872,873],{"class":59,"line":165},[57,874,110],{"emptyLinePlaceholder":109},[57,876,877,879,881],{"class":59,"line":173},[57,878,64],{"class":63},[57,880,118],{"class":67},[57,882,75],{"class":63},[57,884,885,887,889,891,893,896,899,901],{"class":59,"line":188},[57,886,126],{"class":63},[57,888,546],{"class":67},[57,890,549],{"class":71},[57,892,552],{"class":63},[57,894,895],{"class":92},"\"increase\"",[57,897,898],{"class":63},">增加\u003C\u002F",[57,900,546],{"class":67},[57,902,75],{"class":63},[57,904,905,907,909,912,914],{"class":59,"line":194},[57,906,126],{"class":63},[57,908,14],{"class":67},[57,910,911],{"class":63},">{{ count }}\u003C\u002F",[57,913,14],{"class":67},[57,915,75],{"class":63},[57,917,918,920,922],{"class":59,"line":565},[57,919,99],{"class":63},[57,921,118],{"class":67},[57,923,75],{"class":63},[14,925,926,927,930],{},"这里最容易疑惑的是 ",[21,928,929],{},".value","。",[14,932,933,936],{},[21,934,935],{},"ref(0)"," 返回的不是数字 0，而是一个响应式对象，大概可以想成：",[48,938,940],{"className":280,"code":939,"language":282,"meta":53,"style":53},"const count = {\n  value: 0\n}\n",[21,941,942,952,960],{"__ignoreMap":53},[57,943,944,946,948,950],{"class":59,"line":60},[57,945,82],{"class":81},[57,947,825],{"class":85},[57,949,89],{"class":81},[57,951,170],{"class":63},[57,953,954,957],{"class":59,"line":78},[57,955,956],{"class":63},"  value: ",[57,958,959],{"class":85},"0\n",[57,961,962],{"class":59,"line":96},[57,963,191],{"class":63},[14,965,966],{},"所以在脚本里要写：",[48,968,970],{"className":280,"code":969,"language":282,"meta":53,"style":53},"count.value++\n",[21,971,972],{"__ignoreMap":53},[57,973,974,977],{"class":59,"line":60},[57,975,976],{"class":63},"count.value",[57,978,858],{"class":81},[14,980,981,982,666],{},"模板里不用写 ",[21,983,929],{},[48,985,987],{"className":50,"code":986,"language":52,"meta":53,"style":53},"{{ count }}\n",[21,988,989],{"__ignoreMap":53},[57,990,991],{"class":59,"line":60},[57,992,986],{"class":63},[14,994,995],{},"因为 Vue 模板会自动解包 ref。",[231,997,999],{"id":998},"为什么-vue-不直接让普通变量响应式","为什么 Vue 不直接让普通变量响应式",[14,1001,1002],{},"普通变量：",[48,1004,1006],{"className":280,"code":1005,"language":282,"meta":53,"style":53},"let count = 0\n",[21,1007,1008],{"__ignoreMap":53},[57,1009,1010,1013,1016,1018],{"class":59,"line":60},[57,1011,1012],{"class":81},"let",[57,1014,1015],{"class":63}," count ",[57,1017,552],{"class":81},[57,1019,1020],{"class":85}," 0\n",[14,1022,1023,1024,930,1027,1029],{},"JavaScript 没有办法让 Vue 自动知道你什么时候执行了 ",[21,1025,1026],{},"count++",[21,1028,27],{}," 提供了一个可追踪的容器，Vue 可以知道容器里的值变了。",[37,1031,1033,1034,1037],{"id":1032},"_5-reactive响应式对象","5. ",[21,1035,1036],{},"reactive","：响应式对象",[14,1039,1040,1042],{},[21,1041,1036],{}," 适合对象：",[48,1044,1046],{"className":280,"code":1045,"language":282,"meta":53,"style":53},"import { reactive } from 'vue'\n\nconst form = reactive({\n  title: '',\n  minutes: 30,\n  priority: 'normal'\n})\n",[21,1047,1048,1059,1063,1078,1089,1099,1107],{"__ignoreMap":53},[57,1049,1050,1052,1055,1057],{"class":59,"line":60},[57,1051,443],{"class":81},[57,1053,1054],{"class":63}," { reactive } ",[57,1056,449],{"class":81},[57,1058,814],{"class":92},[57,1060,1061],{"class":59,"line":78},[57,1062,110],{"emptyLinePlaceholder":109},[57,1064,1065,1067,1070,1072,1075],{"class":59,"line":96},[57,1066,82],{"class":81},[57,1068,1069],{"class":85}," form",[57,1071,89],{"class":81},[57,1073,1074],{"class":71}," reactive",[57,1076,1077],{"class":63},"({\n",[57,1079,1080,1083,1086],{"class":59,"line":106},[57,1081,1082],{"class":63},"  title: ",[57,1084,1085],{"class":92},"''",[57,1087,1088],{"class":63},",\n",[57,1090,1091,1094,1097],{"class":59,"line":113},[57,1092,1093],{"class":63},"  minutes: ",[57,1095,1096],{"class":85},"30",[57,1098,1088],{"class":63},[57,1100,1101,1104],{"class":59,"line":123},[57,1102,1103],{"class":63},"  priority: ",[57,1105,1106],{"class":92},"'normal'\n",[57,1108,1109],{"class":59,"line":138},[57,1110,762],{"class":63},[14,1112,1113,1114,666],{},"使用时不需要 ",[21,1115,929],{},[48,1117,1119],{"className":280,"code":1118,"language":282,"meta":53,"style":53},"form.title = '学习 ref'\nform.minutes = 45\n",[21,1120,1121,1131],{"__ignoreMap":53},[57,1122,1123,1126,1128],{"class":59,"line":60},[57,1124,1125],{"class":63},"form.title ",[57,1127,552],{"class":81},[57,1129,1130],{"class":92}," '学习 ref'\n",[57,1132,1133,1136,1138],{"class":59,"line":78},[57,1134,1135],{"class":63},"form.minutes ",[57,1137,552],{"class":81},[57,1139,1140],{"class":85}," 45\n",[14,1142,1143],{},"模板：",[48,1145,1147],{"className":50,"code":1146,"language":52,"meta":53,"style":53},"\u003Cinput v-model=\"form.title\">\n\u003Cinput v-model.number=\"form.minutes\" type=\"number\">\n",[21,1148,1149,1171],{"__ignoreMap":53},[57,1150,1151,1153,1156,1159,1161,1164,1167,1169],{"class":59,"line":60},[57,1152,64],{"class":63},[57,1154,1155],{"class":67},"input",[57,1157,1158],{"class":71}," v-model",[57,1160,552],{"class":63},[57,1162,1163],{"class":92},"\"",[57,1165,1166],{"class":63},"form.title",[57,1168,1163],{"class":92},[57,1170,75],{"class":63},[57,1172,1173],{"class":59,"line":78},[57,1174,1175],{"class":63},"\u003Cinput v-model.number=\"form.minutes\" type=\"number\">\n",[231,1177,1179,1181,1182,1184],{"id":1178},"ref-和-reactive-怎么选",[21,1180,27],{}," 和 ",[21,1183,1036],{}," 怎么选",[14,1186,1187],{},"初学建议：",[205,1189,1190,1205,1212],{},[208,1191,1192,1193,1195,1196,28,1199,28,1202,930],{},"单个值：用 ",[21,1194,27],{},"，例如 ",[21,1197,1198],{},"count",[21,1200,1201],{},"loading",[21,1203,1204],{},"keyword",[208,1206,1207,1208,1211],{},"数组：也可以用 ",[21,1209,1210],{},"ref([])","，因为替换数组很方便。",[208,1213,1214,1215,930],{},"表单对象：可以用 ",[21,1216,1217],{},"reactive({ ... })",[14,1219,423],{},[48,1221,1223],{"className":280,"code":1222,"language":282,"meta":53,"style":53},"const tasks = ref([])\nconst form = reactive({\n  title: '',\n  priority: 'normal'\n})\n",[21,1224,1225,1239,1251,1259,1265],{"__ignoreMap":53},[57,1226,1227,1229,1232,1234,1236],{"class":59,"line":60},[57,1228,82],{"class":81},[57,1230,1231],{"class":85}," tasks",[57,1233,89],{"class":81},[57,1235,830],{"class":71},[57,1237,1238],{"class":63},"([])\n",[57,1240,1241,1243,1245,1247,1249],{"class":59,"line":78},[57,1242,82],{"class":81},[57,1244,1069],{"class":85},[57,1246,89],{"class":81},[57,1248,1074],{"class":71},[57,1250,1077],{"class":63},[57,1252,1253,1255,1257],{"class":59,"line":96},[57,1254,1082],{"class":63},[57,1256,1085],{"class":92},[57,1258,1088],{"class":63},[57,1260,1261,1263],{"class":59,"line":106},[57,1262,1103],{"class":63},[57,1264,1106],{"class":92},[57,1266,1267],{"class":59,"line":113},[57,1268,762],{"class":63},[37,1270,1272,1273],{"id":1271},"_6-属性绑定-v-bind","6. 属性绑定 ",[21,1274,1275],{},"v-bind",[14,1277,1278,1279,1281,1282,930],{},"HTML 属性如果需要使用变量，就用 ",[21,1280,1275],{},"，简写是 ",[21,1283,1284],{},":",[48,1286,1288],{"className":50,"code":1287,"language":52,"meta":53,"style":53},"\u003Cimg :src=\"avatarUrl\" :alt=\"user.name\">\n\u003Cbutton :disabled=\"loading\">保存\u003C\u002Fbutton>\n\u003Ca :href=\"link\">查看详情\u003C\u002Fa>\n",[21,1289,1290,1328,1333],{"__ignoreMap":53},[57,1291,1292,1294,1297,1300,1303,1305,1307,1310,1312,1314,1317,1319,1321,1324,1326],{"class":59,"line":60},[57,1293,64],{"class":63},[57,1295,1296],{"class":67},"img",[57,1298,1299],{"class":63}," :",[57,1301,1302],{"class":71},"src",[57,1304,552],{"class":63},[57,1306,1163],{"class":92},[57,1308,1309],{"class":63},"avatarUrl",[57,1311,1163],{"class":92},[57,1313,1299],{"class":63},[57,1315,1316],{"class":71},"alt",[57,1318,552],{"class":63},[57,1320,1163],{"class":92},[57,1322,1323],{"class":63},"user.name",[57,1325,1163],{"class":92},[57,1327,75],{"class":63},[57,1329,1330],{"class":59,"line":78},[57,1331,1332],{"class":63},"\u003Cbutton :disabled=\"loading\">保存\u003C\u002Fbutton>\n",[57,1334,1335],{"class":59,"line":96},[57,1336,1337],{"class":63},"\u003Ca :href=\"link\">查看详情\u003C\u002Fa>\n",[14,1339,1340,1341,1343],{},"如果不加 ",[21,1342,1284],{},"，就是普通字符串。",[48,1345,1347],{"className":50,"code":1346,"language":52,"meta":53,"style":53},"\u003Cbutton disabled=\"loading\">保存\u003C\u002Fbutton>\n",[21,1348,1349],{"__ignoreMap":53},[57,1350,1351,1353,1355,1358,1360,1363,1366,1368],{"class":59,"line":60},[57,1352,64],{"class":63},[57,1354,546],{"class":67},[57,1356,1357],{"class":71}," disabled",[57,1359,552],{"class":63},[57,1361,1362],{"class":92},"\"loading\"",[57,1364,1365],{"class":63},">保存\u003C\u002F",[57,1367,546],{"class":67},[57,1369,75],{"class":63},[14,1371,1372,1373,1376,1377,1379],{},"这里的 ",[21,1374,1375],{},"disabled=\"loading\""," 不是读取变量 ",[21,1378,1201],{},"，而是一个普通 HTML 属性，结果按钮可能一直禁用。",[14,1381,1382],{},"所以你要问：这个属性值是固定文字，还是来自变量？",[205,1384,1385,1390],{},[208,1386,1387,1388],{},"固定文字：不用 ",[21,1389,1284],{},[208,1391,1392,1393],{},"来自变量或表达式：用 ",[21,1394,1284],{},[37,1396,1398,1399],{"id":1397},"_7-事件绑定-v-on","7. 事件绑定 ",[21,1400,1401],{},"v-on",[14,1403,1404,1405,1281,1407,930],{},"事件绑定用 ",[21,1406,1401],{},[21,1408,1409],{},"@",[48,1411,1413],{"className":50,"code":1412,"language":52,"meta":53,"style":53},"\u003Cbutton @click=\"increase\">增加\u003C\u002Fbutton>\n\u003Cinput @input=\"handleInput\">\n\u003Cform @submit.prevent=\"submit\">...\u003C\u002Fform>\n",[21,1414,1415,1442,1463],{"__ignoreMap":53},[57,1416,1417,1419,1421,1424,1427,1429,1431,1434,1436,1438,1440],{"class":59,"line":60},[57,1418,64],{"class":63},[57,1420,546],{"class":67},[57,1422,1423],{"class":63}," @",[57,1425,1426],{"class":71},"click",[57,1428,552],{"class":63},[57,1430,1163],{"class":92},[57,1432,1433],{"class":63},"increase",[57,1435,1163],{"class":92},[57,1437,898],{"class":63},[57,1439,546],{"class":67},[57,1441,75],{"class":63},[57,1443,1444,1446,1448,1450,1452,1454,1456,1459,1461],{"class":59,"line":78},[57,1445,64],{"class":63},[57,1447,1155],{"class":67},[57,1449,1423],{"class":63},[57,1451,1155],{"class":71},[57,1453,552],{"class":63},[57,1455,1163],{"class":92},[57,1457,1458],{"class":63},"handleInput",[57,1460,1163],{"class":92},[57,1462,75],{"class":63},[57,1464,1465],{"class":59,"line":96},[57,1466,1467],{"class":63},"\u003Cform @submit.prevent=\"submit\">...\u003C\u002Fform>\n",[14,1469,1470,1473,1474,1476],{},[21,1471,1472],{},"@click=\"increase\""," 表示点击时调用 ",[21,1475,1433],{}," 函数。",[14,1478,1479],{},"如果需要传参数：",[48,1481,1483],{"className":50,"code":1482,"language":52,"meta":53,"style":53},"\u003Cbutton @click=\"toggleTask(task.id)\">切换\u003C\u002Fbutton>\n",[21,1484,1485],{"__ignoreMap":53},[57,1486,1487,1489,1491,1493,1495,1497,1499,1502,1505,1507,1510,1512],{"class":59,"line":60},[57,1488,64],{"class":63},[57,1490,546],{"class":67},[57,1492,1423],{"class":63},[57,1494,1426],{"class":71},[57,1496,552],{"class":63},[57,1498,1163],{"class":92},[57,1500,1501],{"class":71},"toggleTask",[57,1503,1504],{"class":63},"(task.id)",[57,1506,1163],{"class":92},[57,1508,1509],{"class":63},">切换\u003C\u002F",[57,1511,546],{"class":67},[57,1513,75],{"class":63},[14,1515,1516],{},"如果需要事件对象：",[48,1518,1520],{"className":50,"code":1519,"language":52,"meta":53,"style":53},"\u003Cinput @input=\"handleInput\">\n",[21,1521,1522],{"__ignoreMap":53},[57,1523,1524,1526,1528,1530,1532,1534,1536,1538,1540],{"class":59,"line":60},[57,1525,64],{"class":63},[57,1527,1155],{"class":67},[57,1529,1423],{"class":63},[57,1531,1155],{"class":71},[57,1533,552],{"class":63},[57,1535,1163],{"class":92},[57,1537,1458],{"class":63},[57,1539,1163],{"class":92},[57,1541,75],{"class":63},[48,1543,1545],{"className":280,"code":1544,"language":282,"meta":53,"style":53},"function handleInput(event) {\n  console.log(event.target.value)\n}\n",[21,1546,1547,1562,1571],{"__ignoreMap":53},[57,1548,1549,1551,1554,1556,1559],{"class":59,"line":60},[57,1550,483],{"class":81},[57,1552,1553],{"class":71}," handleInput",[57,1555,499],{"class":63},[57,1557,1558],{"class":713},"event",[57,1560,1561],{"class":63},") {\n",[57,1563,1564,1566,1568],{"class":59,"line":78},[57,1565,493],{"class":63},[57,1567,496],{"class":71},[57,1569,1570],{"class":63},"(event.target.value)\n",[57,1572,1573],{"class":59,"line":96},[57,1574,191],{"class":63},[231,1576,1577],{"id":1577},"事件修饰符",[48,1579,1581],{"className":50,"code":1580,"language":52,"meta":53,"style":53},"\u003Cform @submit.prevent=\"submit\">\n",[21,1582,1583],{"__ignoreMap":53},[57,1584,1585,1587,1590,1592,1595,1598,1601,1603,1605,1607,1609],{"class":59,"line":60},[57,1586,64],{"class":63},[57,1588,1589],{"class":67},"form",[57,1591,1423],{"class":63},[57,1593,1594],{"class":71},"submit",[57,1596,1597],{"class":63},".",[57,1599,1600],{"class":71},"prevent",[57,1602,552],{"class":63},[57,1604,1163],{"class":92},[57,1606,1594],{"class":63},[57,1608,1163],{"class":92},[57,1610,75],{"class":63},[14,1612,1613,1616],{},[21,1614,1615],{},".prevent"," 表示阻止浏览器默认行为。表单默认提交会刷新页面，Vue 单页应用里通常不希望这样。",[48,1618,1620],{"className":50,"code":1619,"language":52,"meta":53,"style":53},"\u003Cbutton @click.stop=\"openMenu\">打开\u003C\u002Fbutton>\n",[21,1621,1622],{"__ignoreMap":53},[57,1623,1624,1626,1628,1630,1632,1634,1637,1639,1641,1644,1646,1649,1651],{"class":59,"line":60},[57,1625,64],{"class":63},[57,1627,546],{"class":67},[57,1629,1423],{"class":63},[57,1631,1426],{"class":71},[57,1633,1597],{"class":63},[57,1635,1636],{"class":71},"stop",[57,1638,552],{"class":63},[57,1640,1163],{"class":92},[57,1642,1643],{"class":63},"openMenu",[57,1645,1163],{"class":92},[57,1647,1648],{"class":63},">打开\u003C\u002F",[57,1650,546],{"class":67},[57,1652,75],{"class":63},[14,1654,1655,1658],{},[21,1656,1657],{},".stop"," 表示阻止事件继续冒泡。",[37,1660,1662,1663],{"id":1661},"_8-条件渲染-v-if","8. 条件渲染 ",[21,1664,1665],{},"v-if",[48,1667,1669],{"className":50,"code":1668,"language":52,"meta":53,"style":53},"\u003Cp v-if=\"loading\">加载中...\u003C\u002Fp>\n\u003Cp v-else-if=\"error\">{{ error }}\u003C\u002Fp>\n\u003Cp v-else>加载完成\u003C\u002Fp>\n",[21,1670,1671,1695,1720],{"__ignoreMap":53},[57,1672,1673,1675,1677,1680,1682,1684,1686,1688,1691,1693],{"class":59,"line":60},[57,1674,64],{"class":63},[57,1676,14],{"class":67},[57,1678,1679],{"class":81}," v-if",[57,1681,552],{"class":63},[57,1683,1163],{"class":92},[57,1685,1201],{"class":63},[57,1687,1163],{"class":92},[57,1689,1690],{"class":63},">加载中...\u003C\u002F",[57,1692,14],{"class":67},[57,1694,75],{"class":63},[57,1696,1697,1699,1701,1704,1706,1708,1711,1713,1716,1718],{"class":59,"line":78},[57,1698,64],{"class":63},[57,1700,14],{"class":67},[57,1702,1703],{"class":81}," v-else-if",[57,1705,552],{"class":63},[57,1707,1163],{"class":92},[57,1709,1710],{"class":63},"error",[57,1712,1163],{"class":92},[57,1714,1715],{"class":63},">{{ error }}\u003C\u002F",[57,1717,14],{"class":67},[57,1719,75],{"class":63},[57,1721,1722,1724,1726,1729,1732,1734],{"class":59,"line":96},[57,1723,64],{"class":63},[57,1725,14],{"class":67},[57,1727,1728],{"class":81}," v-else",[57,1730,1731],{"class":63},">加载完成\u003C\u002F",[57,1733,14],{"class":67},[57,1735,75],{"class":63},[14,1737,1738,1740],{},[21,1739,1665],{}," 会真正创建或销毁元素。",[14,1742,1743,1744,666],{},"如果只是频繁显示隐藏，可以用 ",[21,1745,1746],{},"v-show",[48,1748,1750],{"className":50,"code":1749,"language":52,"meta":53,"style":53},"\u003Caside v-show=\"sidebarOpen\">侧边栏\u003C\u002Faside>\n",[21,1751,1752],{"__ignoreMap":53},[57,1753,1754,1756,1759,1762,1764,1766,1769,1771,1774,1776],{"class":59,"line":60},[57,1755,64],{"class":63},[57,1757,1758],{"class":67},"aside",[57,1760,1761],{"class":71}," v-show",[57,1763,552],{"class":63},[57,1765,1163],{"class":92},[57,1767,1768],{"class":63},"sidebarOpen",[57,1770,1163],{"class":92},[57,1772,1773],{"class":63},">侧边栏\u003C\u002F",[57,1775,1758],{"class":67},[57,1777,75],{"class":63},[14,1779,1780],{},"区别：",[205,1782,1783,1788],{},[208,1784,1785,1787],{},[21,1786,1665],{},"：条件不满足时，元素不在 DOM 中。",[208,1789,1790,1792],{},[21,1791,1746],{},"：元素还在 DOM 中，只是用 CSS 隐藏。",[14,1794,1795,1796,1798,1799,930],{},"初学时默认用 ",[21,1797,1665],{},"，遇到频繁切换且不希望销毁状态时再考虑 ",[21,1800,1746],{},[37,1802,1804,1805],{"id":1803},"_9-列表渲染-v-for","9. 列表渲染 ",[21,1806,1807],{},"v-for",[48,1809,1811],{"className":50,"code":1810,"language":52,"meta":53,"style":53},"\u003Carticle v-for=\"lesson in lessons\" :key=\"lesson.id\">\n  \u003Ch2>{{ lesson.title }}\u003C\u002Fh2>\n  \u003Cp>{{ lesson.minutes }} 分钟\u003C\u002Fp>\n\u003C\u002Farticle>\n",[21,1812,1813,1854,1859,1864],{"__ignoreMap":53},[57,1814,1815,1817,1820,1823,1825,1827,1830,1833,1836,1838,1840,1843,1845,1847,1850,1852],{"class":59,"line":60},[57,1816,64],{"class":63},[57,1818,1819],{"class":67},"article",[57,1821,1822],{"class":81}," v-for",[57,1824,552],{"class":63},[57,1826,1163],{"class":92},[57,1828,1829],{"class":63},"lesson ",[57,1831,1832],{"class":81},"in",[57,1834,1835],{"class":63}," lessons",[57,1837,1163],{"class":92},[57,1839,1299],{"class":63},[57,1841,1842],{"class":71},"key",[57,1844,552],{"class":63},[57,1846,1163],{"class":92},[57,1848,1849],{"class":63},"lesson.id",[57,1851,1163],{"class":92},[57,1853,75],{"class":63},[57,1855,1856],{"class":59,"line":78},[57,1857,1858],{"class":63},"  \u003Ch2>{{ lesson.title }}\u003C\u002Fh2>\n",[57,1860,1861],{"class":59,"line":96},[57,1862,1863],{"class":63},"  \u003Cp>{{ lesson.minutes }} 分钟\u003C\u002Fp>\n",[57,1865,1866,1868,1870],{"class":59,"line":106},[57,1867,99],{"class":63},[57,1869,1819],{"class":67},[57,1871,75],{"class":63},[14,1873,1874],{},"读法：",[205,1876,1877,1887,1892],{},[208,1878,1879,1880,1883,1884,930],{},"对 ",[21,1881,1882],{},"lessons"," 数组里的每个 ",[21,1885,1886],{},"lesson",[208,1888,1889,1890,930],{},"渲染一个 ",[21,1891,1819],{},[208,1893,1894,1895,1897],{},"用 ",[21,1896,1849],{}," 作为身份标识。",[231,1899,1901,1902],{"id":1900},"为什么必须写-key","为什么必须写 ",[21,1903,1842],{},[14,1905,1906,1908],{},[21,1907,1842],{}," 告诉 Vue：列表里的每一项是谁。",[14,1910,1911],{},"如果没有稳定 key，或者用数组下标当 key，当列表增删排序时，Vue 可能复用错 DOM，导致输入框内容、勾选状态等错位。",[14,1913,1914],{},"推荐：",[48,1916,1918],{"className":50,"code":1917,"language":52,"meta":53,"style":53},"\u003Cli v-for=\"task in tasks\" :key=\"task.id\">\n  {{ task.title }}\n\u003C\u002Fli>\n",[21,1919,1920,1956,1961],{"__ignoreMap":53},[57,1921,1922,1924,1926,1928,1930,1932,1935,1937,1939,1941,1943,1945,1947,1949,1952,1954],{"class":59,"line":60},[57,1923,64],{"class":63},[57,1925,208],{"class":67},[57,1927,1822],{"class":81},[57,1929,552],{"class":63},[57,1931,1163],{"class":92},[57,1933,1934],{"class":63},"task ",[57,1936,1832],{"class":81},[57,1938,1231],{"class":63},[57,1940,1163],{"class":92},[57,1942,1299],{"class":63},[57,1944,1842],{"class":71},[57,1946,552],{"class":63},[57,1948,1163],{"class":92},[57,1950,1951],{"class":63},"task.id",[57,1953,1163],{"class":92},[57,1955,75],{"class":63},[57,1957,1958],{"class":59,"line":78},[57,1959,1960],{"class":63},"  {{ task.title }}\n",[57,1962,1963,1965,1967],{"class":59,"line":96},[57,1964,99],{"class":63},[57,1966,208],{"class":67},[57,1968,75],{"class":63},[14,1970,642],{},[48,1972,1974],{"className":50,"code":1973,"language":52,"meta":53,"style":53},"\u003Cli v-for=\"(task, index) in tasks\" :key=\"index\">\n  {{ task.title }}\n\u003C\u002Fli>\n",[21,1975,1976,2012,2016],{"__ignoreMap":53},[57,1977,1978,1980,1982,1984,1986,1988,1991,1993,1995,1997,1999,2001,2003,2005,2008,2010],{"class":59,"line":60},[57,1979,64],{"class":63},[57,1981,208],{"class":67},[57,1983,1822],{"class":81},[57,1985,552],{"class":63},[57,1987,1163],{"class":92},[57,1989,1990],{"class":63},"(task, index) ",[57,1992,1832],{"class":81},[57,1994,1231],{"class":63},[57,1996,1163],{"class":92},[57,1998,1299],{"class":63},[57,2000,1842],{"class":71},[57,2002,552],{"class":63},[57,2004,1163],{"class":92},[57,2006,2007],{"class":63},"index",[57,2009,1163],{"class":92},[57,2011,75],{"class":63},[57,2013,2014],{"class":59,"line":78},[57,2015,1960],{"class":63},[57,2017,2018,2020,2022],{"class":59,"line":96},[57,2019,99],{"class":63},[57,2021,208],{"class":67},[57,2023,75],{"class":63},[14,2025,2026],{},"只有当列表永远不会增删、排序、过滤时，index 才勉强可用。",[37,2028,2030,2031,2033],{"id":2029},"_10-computed从已有状态推导新值","10. ",[21,2032,31],{},"：从已有状态推导新值",[14,2035,2036,2037,930],{},"当一个值可以由其他状态计算出来，不要手动存第二份，用 ",[21,2038,31],{},[48,2040,2042],{"className":280,"code":2041,"language":282,"meta":53,"style":53},"const tasks = ref([\n  { id: 1, title: '学习 ref', done: true },\n  { id: 2, title: '学习 computed', done: false }\n])\n\nconst completedCount = computed(() => {\n  return tasks.value.filter((task) => task.done).length\n})\n",[21,2043,2044,2057,2080,2099,2104,2108,2125,2148],{"__ignoreMap":53},[57,2045,2046,2048,2050,2052,2054],{"class":59,"line":60},[57,2047,82],{"class":81},[57,2049,1231],{"class":85},[57,2051,89],{"class":81},[57,2053,830],{"class":71},[57,2055,2056],{"class":63},"([\n",[57,2058,2059,2062,2065,2068,2071,2074,2077],{"class":59,"line":78},[57,2060,2061],{"class":63},"  { id: ",[57,2063,2064],{"class":85},"1",[57,2066,2067],{"class":63},", title: ",[57,2069,2070],{"class":92},"'学习 ref'",[57,2072,2073],{"class":63},", done: ",[57,2075,2076],{"class":85},"true",[57,2078,2079],{"class":63}," },\n",[57,2081,2082,2084,2087,2089,2092,2094,2097],{"class":59,"line":96},[57,2083,2061],{"class":63},[57,2085,2086],{"class":85},"2",[57,2088,2067],{"class":63},[57,2090,2091],{"class":92},"'学习 computed'",[57,2093,2073],{"class":63},[57,2095,2096],{"class":85},"false",[57,2098,474],{"class":63},[57,2100,2101],{"class":59,"line":106},[57,2102,2103],{"class":63},"])\n",[57,2105,2106],{"class":59,"line":113},[57,2107,110],{"emptyLinePlaceholder":109},[57,2109,2110,2112,2115,2117,2119,2121,2123],{"class":59,"line":123},[57,2111,82],{"class":81},[57,2113,2114],{"class":85}," completedCount",[57,2116,89],{"class":81},[57,2118,683],{"class":71},[57,2120,686],{"class":63},[57,2122,689],{"class":81},[57,2124,170],{"class":63},[57,2126,2127,2129,2132,2134,2136,2138,2140,2142,2145],{"class":59,"line":138},[57,2128,696],{"class":81},[57,2130,2131],{"class":63}," tasks.value.",[57,2133,707],{"class":71},[57,2135,710],{"class":63},[57,2137,714],{"class":713},[57,2139,717],{"class":63},[57,2141,689],{"class":81},[57,2143,2144],{"class":63}," task.done).",[57,2146,2147],{"class":85},"length\n",[57,2149,2150],{"class":59,"line":147},[57,2151,762],{"class":63},[14,2153,1143],{},[48,2155,2157],{"className":50,"code":2156,"language":52,"meta":53,"style":53},"\u003Cp>已完成 {{ completedCount }} 个\u003C\u002Fp>\n",[21,2158,2159],{"__ignoreMap":53},[57,2160,2161,2163,2165,2168,2170],{"class":59,"line":60},[57,2162,64],{"class":63},[57,2164,14],{"class":67},[57,2166,2167],{"class":63},">已完成 {{ completedCount }} 个\u003C\u002F",[57,2169,14],{"class":67},[57,2171,75],{"class":63},[231,2173,2174],{"id":2174},"为什么不用普通函数",[14,2176,2177],{},"普通函数也能算：",[48,2179,2181],{"className":280,"code":2180,"language":282,"meta":53,"style":53},"function completedCount() {\n  return tasks.value.filter((task) => task.done).length\n}\n",[21,2182,2183,2191,2211],{"__ignoreMap":53},[57,2184,2185,2187,2189],{"class":59,"line":60},[57,2186,483],{"class":81},[57,2188,2114],{"class":71},[57,2190,302],{"class":63},[57,2192,2193,2195,2197,2199,2201,2203,2205,2207,2209],{"class":59,"line":78},[57,2194,696],{"class":81},[57,2196,2131],{"class":63},[57,2198,707],{"class":71},[57,2200,710],{"class":63},[57,2202,714],{"class":713},[57,2204,717],{"class":63},[57,2206,689],{"class":81},[57,2208,2144],{"class":63},[57,2210,2147],{"class":85},[57,2212,2213],{"class":59,"line":96},[57,2214,191],{"class":63},[14,2216,2217,2218,2220,2221,2224,2225,2227],{},"但 ",[21,2219,31],{}," 有缓存。只要依赖的 ",[21,2222,2223],{},"tasks"," 没变，Vue 可以复用上次结果。更重要的是，",[21,2226,31],{}," 表达了语义：这是一个“由状态推导出的值”。",[231,2229,2230],{"id":2230},"不要重复存可推导状态",[14,2232,642],{},[48,2234,2236],{"className":280,"code":2235,"language":282,"meta":53,"style":53},"const tasks = ref([])\nconst completedCount = ref(0)\n",[21,2237,2238,2250],{"__ignoreMap":53},[57,2239,2240,2242,2244,2246,2248],{"class":59,"line":60},[57,2241,82],{"class":81},[57,2243,1231],{"class":85},[57,2245,89],{"class":81},[57,2247,830],{"class":71},[57,2249,1238],{"class":63},[57,2251,2252,2254,2256,2258,2260,2262,2264],{"class":59,"line":78},[57,2253,82],{"class":81},[57,2255,2114],{"class":85},[57,2257,89],{"class":81},[57,2259,830],{"class":71},[57,2261,499],{"class":63},[57,2263,835],{"class":85},[57,2265,505],{"class":63},[14,2267,2268,2269,2272],{},"每次任务变化你都要记得更新 ",[21,2270,2271],{},"completedCount","，容易不同步。",[14,2274,1914],{},[48,2276,2278],{"className":280,"code":2277,"language":282,"meta":53,"style":53},"const completedCount = computed(() => {\n  return tasks.value.filter((task) => task.done).length\n})\n",[21,2279,2280,2296,2316],{"__ignoreMap":53},[57,2281,2282,2284,2286,2288,2290,2292,2294],{"class":59,"line":60},[57,2283,82],{"class":81},[57,2285,2114],{"class":85},[57,2287,89],{"class":81},[57,2289,683],{"class":71},[57,2291,686],{"class":63},[57,2293,689],{"class":81},[57,2295,170],{"class":63},[57,2297,2298,2300,2302,2304,2306,2308,2310,2312,2314],{"class":59,"line":78},[57,2299,696],{"class":81},[57,2301,2131],{"class":63},[57,2303,707],{"class":71},[57,2305,710],{"class":63},[57,2307,714],{"class":713},[57,2309,717],{"class":63},[57,2311,689],{"class":81},[57,2313,2144],{"class":63},[57,2315,2147],{"class":85},[57,2317,2318],{"class":59,"line":96},[57,2319,762],{"class":63},[37,2321,2323,2324,2326],{"id":2322},"_11-watch状态变化后做一件事","11. ",[21,2325,34],{},"：状态变化后做一件事",[14,2328,2329,2331],{},[21,2330,34],{}," 用来观察一个响应式状态，当它变化后执行副作用。",[48,2333,2335],{"className":280,"code":2334,"language":282,"meta":53,"style":53},"watch(keyword, (newValue, oldValue) => {\n  console.log('旧值：', oldValue)\n  console.log('新值：', newValue)\n})\n",[21,2336,2337,2359,2373,2387],{"__ignoreMap":53},[57,2338,2339,2341,2344,2347,2350,2353,2355,2357],{"class":59,"line":60},[57,2340,34],{"class":71},[57,2342,2343],{"class":63},"(keyword, (",[57,2345,2346],{"class":713},"newValue",[57,2348,2349],{"class":63},", ",[57,2351,2352],{"class":713},"oldValue",[57,2354,717],{"class":63},[57,2356,689],{"class":81},[57,2358,170],{"class":63},[57,2360,2361,2363,2365,2367,2370],{"class":59,"line":78},[57,2362,493],{"class":63},[57,2364,496],{"class":71},[57,2366,499],{"class":63},[57,2368,2369],{"class":92},"'旧值：'",[57,2371,2372],{"class":63},", oldValue)\n",[57,2374,2375,2377,2379,2381,2384],{"class":59,"line":96},[57,2376,493],{"class":63},[57,2378,496],{"class":71},[57,2380,499],{"class":63},[57,2382,2383],{"class":92},"'新值：'",[57,2385,2386],{"class":63},", newValue)\n",[57,2388,2389],{"class":59,"line":106},[57,2390,762],{"class":63},[14,2392,2393],{},"常见副作用：",[205,2395,2396,2399,2405,2408,2411],{},[208,2397,2398],{},"发送请求。",[208,2400,2401,2402,930],{},"写入 ",[21,2403,2404],{},"localStorage",[208,2406,2407],{},"修改网页标题。",[208,2409,2410],{},"调用第三方库。",[208,2412,2413],{},"打日志。",[231,2415,2417,1181,2419,2421],{"id":2416},"computed-和-watch-的区别",[21,2418,31],{},[21,2420,34],{}," 的区别",[14,2423,2424,2426],{},[21,2425,31],{},"：我要得到一个新值。",[48,2428,2430],{"className":280,"code":2429,"language":282,"meta":53,"style":53},"const filteredTasks = computed(() => {\n  return tasks.value.filter((task) => task.title.includes(keyword.value))\n})\n",[21,2431,2432,2449,2474],{"__ignoreMap":53},[57,2433,2434,2436,2439,2441,2443,2445,2447],{"class":59,"line":60},[57,2435,82],{"class":81},[57,2437,2438],{"class":85}," filteredTasks",[57,2440,89],{"class":81},[57,2442,683],{"class":71},[57,2444,686],{"class":63},[57,2446,689],{"class":81},[57,2448,170],{"class":63},[57,2450,2451,2453,2455,2457,2459,2461,2463,2465,2468,2471],{"class":59,"line":78},[57,2452,696],{"class":81},[57,2454,2131],{"class":63},[57,2456,707],{"class":71},[57,2458,710],{"class":63},[57,2460,714],{"class":713},[57,2462,717],{"class":63},[57,2464,689],{"class":81},[57,2466,2467],{"class":63}," task.title.",[57,2469,2470],{"class":71},"includes",[57,2472,2473],{"class":63},"(keyword.value))\n",[57,2475,2476],{"class":59,"line":96},[57,2477,762],{"class":63},[14,2479,2480,2482],{},[21,2481,34],{},"：某个值变了，我要执行动作。",[48,2484,2486],{"className":280,"code":2485,"language":282,"meta":53,"style":53},"watch(keyword, (value) => {\n  localStorage.setItem('keyword', value)\n})\n",[21,2487,2488,2503,2519],{"__ignoreMap":53},[57,2489,2490,2492,2494,2497,2499,2501],{"class":59,"line":60},[57,2491,34],{"class":71},[57,2493,2343],{"class":63},[57,2495,2496],{"class":713},"value",[57,2498,717],{"class":63},[57,2500,689],{"class":81},[57,2502,170],{"class":63},[57,2504,2505,2508,2511,2513,2516],{"class":59,"line":78},[57,2506,2507],{"class":63},"  localStorage.",[57,2509,2510],{"class":71},"setItem",[57,2512,499],{"class":63},[57,2514,2515],{"class":92},"'keyword'",[57,2517,2518],{"class":63},", value)\n",[57,2520,2521],{"class":59,"line":96},[57,2522,762],{"class":63},[14,2524,2525,2526,2528,2529,930],{},"如果你只是为了显示一个结果，优先用 ",[21,2527,31],{},"。如果你要“做一件事”，才用 ",[21,2530,34],{},[37,2532,2534],{"id":2533},"_12-生命周期","12. 生命周期",[14,2536,2537,2538,930],{},"组件从创建到销毁，有不同阶段。最常用的是 ",[21,2539,2540],{},"onMounted",[48,2542,2544],{"className":280,"code":2543,"language":282,"meta":53,"style":53},"import { onMounted } from 'vue'\n\nonMounted(() => {\n  console.log('组件已经出现在页面上')\n})\n",[21,2545,2546,2557,2561,2571,2584],{"__ignoreMap":53},[57,2547,2548,2550,2553,2555],{"class":59,"line":60},[57,2549,443],{"class":81},[57,2551,2552],{"class":63}," { onMounted } ",[57,2554,449],{"class":81},[57,2556,814],{"class":92},[57,2558,2559],{"class":59,"line":78},[57,2560,110],{"emptyLinePlaceholder":109},[57,2562,2563,2565,2567,2569],{"class":59,"line":96},[57,2564,2540],{"class":71},[57,2566,686],{"class":63},[57,2568,689],{"class":81},[57,2570,170],{"class":63},[57,2572,2573,2575,2577,2579,2582],{"class":59,"line":106},[57,2574,493],{"class":63},[57,2576,496],{"class":71},[57,2578,499],{"class":63},[57,2580,2581],{"class":92},"'组件已经出现在页面上'",[57,2583,505],{"class":63},[57,2585,2586],{"class":59,"line":113},[57,2587,762],{"class":63},[14,2589,2590],{},"常见用途：",[205,2592,2593,2596,2599],{},[208,2594,2595],{},"页面进入后请求数据。",[208,2597,2598],{},"DOM 出现后聚焦输入框。",[208,2600,2601],{},"初始化第三方库。",[14,2603,2604,2605,666],{},"清理副作用用 ",[21,2606,2607],{},"onUnmounted",[48,2609,2611],{"className":280,"code":2610,"language":282,"meta":53,"style":53},"import { onMounted, onUnmounted } from 'vue'\n\nlet timerId\n\nonMounted(() => {\n  timerId = setInterval(() => {\n    console.log('tick')\n  }, 1000)\n})\n\nonUnmounted(() => {\n  clearInterval(timerId)\n})\n",[21,2612,2613,2624,2628,2635,2639,2649,2665,2679,2689,2693,2697,2707,2715],{"__ignoreMap":53},[57,2614,2615,2617,2620,2622],{"class":59,"line":60},[57,2616,443],{"class":81},[57,2618,2619],{"class":63}," { onMounted, onUnmounted } ",[57,2621,449],{"class":81},[57,2623,814],{"class":92},[57,2625,2626],{"class":59,"line":78},[57,2627,110],{"emptyLinePlaceholder":109},[57,2629,2630,2632],{"class":59,"line":96},[57,2631,1012],{"class":81},[57,2633,2634],{"class":63}," timerId\n",[57,2636,2637],{"class":59,"line":106},[57,2638,110],{"emptyLinePlaceholder":109},[57,2640,2641,2643,2645,2647],{"class":59,"line":113},[57,2642,2540],{"class":71},[57,2644,686],{"class":63},[57,2646,689],{"class":81},[57,2648,170],{"class":63},[57,2650,2651,2654,2656,2659,2661,2663],{"class":59,"line":123},[57,2652,2653],{"class":63},"  timerId ",[57,2655,552],{"class":81},[57,2657,2658],{"class":71}," setInterval",[57,2660,686],{"class":63},[57,2662,689],{"class":81},[57,2664,170],{"class":63},[57,2666,2667,2670,2672,2674,2677],{"class":59,"line":138},[57,2668,2669],{"class":63},"    console.",[57,2671,496],{"class":71},[57,2673,499],{"class":63},[57,2675,2676],{"class":92},"'tick'",[57,2678,505],{"class":63},[57,2680,2681,2684,2687],{"class":59,"line":147},[57,2682,2683],{"class":63},"  }, ",[57,2685,2686],{"class":85},"1000",[57,2688,505],{"class":63},[57,2690,2691],{"class":59,"line":152},[57,2692,762],{"class":63},[57,2694,2695],{"class":59,"line":165},[57,2696,110],{"emptyLinePlaceholder":109},[57,2698,2699,2701,2703,2705],{"class":59,"line":173},[57,2700,2607],{"class":71},[57,2702,686],{"class":63},[57,2704,689],{"class":81},[57,2706,170],{"class":63},[57,2708,2709,2712],{"class":59,"line":188},[57,2710,2711],{"class":71},"  clearInterval",[57,2713,2714],{"class":63},"(timerId)\n",[57,2716,2717],{"class":59,"line":194},[57,2718,762],{"class":63},[14,2720,2721],{},"如果不清理定时器，组件离开后定时器还会继续跑。",[37,2723,2725],{"id":2724},"_13-模板引用","13. 模板引用",[14,2727,2728],{},"当你真的需要 DOM 元素：",[48,2730,2732],{"className":50,"code":2731,"language":52,"meta":53,"style":53},"\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",[21,2733,2734,2744,2755,2759,2777,2781,2791,2802,2806,2814,2818,2826,2841],{"__ignoreMap":53},[57,2735,2736,2738,2740,2742],{"class":59,"line":60},[57,2737,64],{"class":63},[57,2739,68],{"class":67},[57,2741,72],{"class":71},[57,2743,75],{"class":63},[57,2745,2746,2748,2751,2753],{"class":59,"line":78},[57,2747,443],{"class":81},[57,2749,2750],{"class":63}," { onMounted, ref } ",[57,2752,449],{"class":81},[57,2754,814],{"class":92},[57,2756,2757],{"class":59,"line":96},[57,2758,110],{"emptyLinePlaceholder":109},[57,2760,2761,2763,2766,2768,2770,2772,2775],{"class":59,"line":106},[57,2762,82],{"class":81},[57,2764,2765],{"class":85}," inputEl",[57,2767,89],{"class":81},[57,2769,830],{"class":71},[57,2771,499],{"class":63},[57,2773,2774],{"class":85},"null",[57,2776,505],{"class":63},[57,2778,2779],{"class":59,"line":113},[57,2780,110],{"emptyLinePlaceholder":109},[57,2782,2783,2785,2787,2789],{"class":59,"line":123},[57,2784,2540],{"class":71},[57,2786,686],{"class":63},[57,2788,689],{"class":81},[57,2790,170],{"class":63},[57,2792,2793,2796,2799],{"class":59,"line":138},[57,2794,2795],{"class":63},"  inputEl.value.",[57,2797,2798],{"class":71},"focus",[57,2800,2801],{"class":63},"()\n",[57,2803,2804],{"class":59,"line":147},[57,2805,762],{"class":63},[57,2807,2808,2810,2812],{"class":59,"line":152},[57,2809,99],{"class":63},[57,2811,68],{"class":67},[57,2813,75],{"class":63},[57,2815,2816],{"class":59,"line":165},[57,2817,110],{"emptyLinePlaceholder":109},[57,2819,2820,2822,2824],{"class":59,"line":173},[57,2821,64],{"class":63},[57,2823,118],{"class":67},[57,2825,75],{"class":63},[57,2827,2828,2830,2832,2834,2836,2839],{"class":59,"line":188},[57,2829,126],{"class":63},[57,2831,1155],{"class":67},[57,2833,830],{"class":71},[57,2835,552],{"class":63},[57,2837,2838],{"class":92},"\"inputEl\"",[57,2840,75],{"class":63},[57,2842,2843,2845,2847],{"class":59,"line":194},[57,2844,99],{"class":63},[57,2846,118],{"class":67},[57,2848,75],{"class":63},[14,2850,628],{},[205,2852,2853,2862,2865],{},[208,2854,2855,2856,2859,2860,930],{},"初始时 ",[21,2857,2858],{},"inputEl.value"," 是 ",[21,2861,2774],{},[208,2863,2864],{},"组件挂载后才会变成真实 DOM。",[208,2866,2867,2868,2870],{},"所以通常在 ",[21,2869,2540],{}," 里使用。",[37,2872,2874],{"id":2873},"_14-本章完整小例子","14. 本章完整小例子",[48,2876,2878],{"className":50,"code":2877,"language":52,"meta":53,"style":53},"\u003Cscript setup>\nimport { computed, ref, watch } from 'vue'\n\nconst keyword = ref('')\nconst tasks = ref([\n  { id: 1, title: '学习 ref', done: true },\n  { id: 2, title: '学习 computed', done: false },\n  { id: 3, title: '学习 watch', done: false }\n])\n\nconst filteredTasks = computed(() => {\n  return tasks.value.filter((task) => {\n    return task.title.includes(keyword.value)\n  })\n})\n\nconst remainingCount = computed(() => {\n  return tasks.value.filter((task) => !task.done).length\n})\n\nwatch(keyword, (value) => {\n  console.log('搜索词变化：', value)\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  \u003Cinput v-model.trim=\"keyword\" placeholder=\"搜索任务\">\n\n  \u003Cp>剩余 {{ remainingCount }} 个任务\u003C\u002Fp>\n\n  \u003Cp v-if=\"filteredTasks.length === 0\">没有匹配任务\u003C\u002Fp>\n\n  \u003Cul v-else>\n    \u003Cli v-for=\"task in filteredTasks\" :key=\"task.id\">\n      \u003Clabel>\n        \u003Cinput type=\"checkbox\" :checked=\"task.done\" @change=\"toggleTask(task.id)\">\n        {{ task.title }}\n      \u003C\u002Flabel>\n    \u003C\u002Fli>\n  \u003C\u002Ful>\n\u003C\u002Ftemplate>\n",[21,2879,2880,2890,2901,2905,2922,2934,2950,2966,2984,2988,2992,3008,3026,3037,3042,3047,3052,3070,3094,3099,3104,3119,3133,3138,3143,3158,3192,3197,3206,3219,3224,3229,3238,3243,3252,3277,3282,3296,3301,3322,3327,3338,3363,3374,3408,3414,3424,3434,3444],{"__ignoreMap":53},[57,2881,2882,2884,2886,2888],{"class":59,"line":60},[57,2883,64],{"class":63},[57,2885,68],{"class":67},[57,2887,72],{"class":71},[57,2889,75],{"class":63},[57,2891,2892,2894,2897,2899],{"class":59,"line":78},[57,2893,443],{"class":81},[57,2895,2896],{"class":63}," { computed, ref, watch } ",[57,2898,449],{"class":81},[57,2900,814],{"class":92},[57,2902,2903],{"class":59,"line":96},[57,2904,110],{"emptyLinePlaceholder":109},[57,2906,2907,2909,2912,2914,2916,2918,2920],{"class":59,"line":106},[57,2908,82],{"class":81},[57,2910,2911],{"class":85}," keyword",[57,2913,89],{"class":81},[57,2915,830],{"class":71},[57,2917,499],{"class":63},[57,2919,1085],{"class":92},[57,2921,505],{"class":63},[57,2923,2924,2926,2928,2930,2932],{"class":59,"line":113},[57,2925,82],{"class":81},[57,2927,1231],{"class":85},[57,2929,89],{"class":81},[57,2931,830],{"class":71},[57,2933,2056],{"class":63},[57,2935,2936,2938,2940,2942,2944,2946,2948],{"class":59,"line":123},[57,2937,2061],{"class":63},[57,2939,2064],{"class":85},[57,2941,2067],{"class":63},[57,2943,2070],{"class":92},[57,2945,2073],{"class":63},[57,2947,2076],{"class":85},[57,2949,2079],{"class":63},[57,2951,2952,2954,2956,2958,2960,2962,2964],{"class":59,"line":138},[57,2953,2061],{"class":63},[57,2955,2086],{"class":85},[57,2957,2067],{"class":63},[57,2959,2091],{"class":92},[57,2961,2073],{"class":63},[57,2963,2096],{"class":85},[57,2965,2079],{"class":63},[57,2967,2968,2970,2973,2975,2978,2980,2982],{"class":59,"line":147},[57,2969,2061],{"class":63},[57,2971,2972],{"class":85},"3",[57,2974,2067],{"class":63},[57,2976,2977],{"class":92},"'学习 watch'",[57,2979,2073],{"class":63},[57,2981,2096],{"class":85},[57,2983,474],{"class":63},[57,2985,2986],{"class":59,"line":152},[57,2987,2103],{"class":63},[57,2989,2990],{"class":59,"line":165},[57,2991,110],{"emptyLinePlaceholder":109},[57,2993,2994,2996,2998,3000,3002,3004,3006],{"class":59,"line":173},[57,2995,82],{"class":81},[57,2997,2438],{"class":85},[57,2999,89],{"class":81},[57,3001,683],{"class":71},[57,3003,686],{"class":63},[57,3005,689],{"class":81},[57,3007,170],{"class":63},[57,3009,3010,3012,3014,3016,3018,3020,3022,3024],{"class":59,"line":188},[57,3011,696],{"class":81},[57,3013,2131],{"class":63},[57,3015,707],{"class":71},[57,3017,710],{"class":63},[57,3019,714],{"class":713},[57,3021,717],{"class":63},[57,3023,689],{"class":81},[57,3025,170],{"class":63},[57,3027,3028,3030,3032,3034],{"class":59,"line":194},[57,3029,323],{"class":81},[57,3031,2467],{"class":63},[57,3033,2470],{"class":71},[57,3035,3036],{"class":63},"(keyword.value)\n",[57,3038,3039],{"class":59,"line":565},[57,3040,3041],{"class":63},"  })\n",[57,3043,3045],{"class":59,"line":3044},15,[57,3046,762],{"class":63},[57,3048,3050],{"class":59,"line":3049},16,[57,3051,110],{"emptyLinePlaceholder":109},[57,3053,3055,3057,3060,3062,3064,3066,3068],{"class":59,"line":3054},17,[57,3056,82],{"class":81},[57,3058,3059],{"class":85}," remainingCount",[57,3061,89],{"class":81},[57,3063,683],{"class":71},[57,3065,686],{"class":63},[57,3067,689],{"class":81},[57,3069,170],{"class":63},[57,3071,3073,3075,3077,3079,3081,3083,3085,3087,3089,3092],{"class":59,"line":3072},18,[57,3074,696],{"class":81},[57,3076,2131],{"class":63},[57,3078,707],{"class":71},[57,3080,710],{"class":63},[57,3082,714],{"class":713},[57,3084,717],{"class":63},[57,3086,689],{"class":81},[57,3088,722],{"class":81},[57,3090,3091],{"class":63},"task.done).",[57,3093,2147],{"class":85},[57,3095,3097],{"class":59,"line":3096},19,[57,3098,762],{"class":63},[57,3100,3102],{"class":59,"line":3101},20,[57,3103,110],{"emptyLinePlaceholder":109},[57,3105,3107,3109,3111,3113,3115,3117],{"class":59,"line":3106},21,[57,3108,34],{"class":71},[57,3110,2343],{"class":63},[57,3112,2496],{"class":713},[57,3114,717],{"class":63},[57,3116,689],{"class":81},[57,3118,170],{"class":63},[57,3120,3122,3124,3126,3128,3131],{"class":59,"line":3121},22,[57,3123,493],{"class":63},[57,3125,496],{"class":71},[57,3127,499],{"class":63},[57,3129,3130],{"class":92},"'搜索词变化：'",[57,3132,2518],{"class":63},[57,3134,3136],{"class":59,"line":3135},23,[57,3137,762],{"class":63},[57,3139,3141],{"class":59,"line":3140},24,[57,3142,110],{"emptyLinePlaceholder":109},[57,3144,3146,3148,3151,3153,3156],{"class":59,"line":3145},25,[57,3147,483],{"class":81},[57,3149,3150],{"class":71}," toggleTask",[57,3152,499],{"class":63},[57,3154,3155],{"class":713},"id",[57,3157,1561],{"class":63},[57,3159,3161,3164,3167,3169,3171,3174,3176,3179,3181,3183,3186,3189],{"class":59,"line":3160},26,[57,3162,3163],{"class":81},"  const",[57,3165,3166],{"class":85}," task",[57,3168,89],{"class":81},[57,3170,2131],{"class":63},[57,3172,3173],{"class":71},"find",[57,3175,710],{"class":63},[57,3177,3178],{"class":713},"item",[57,3180,717],{"class":63},[57,3182,689],{"class":81},[57,3184,3185],{"class":63}," item.id ",[57,3187,3188],{"class":81},"===",[57,3190,3191],{"class":63}," id)\n",[57,3193,3195],{"class":59,"line":3194},27,[57,3196,110],{"emptyLinePlaceholder":109},[57,3198,3200,3203],{"class":59,"line":3199},28,[57,3201,3202],{"class":81},"  if",[57,3204,3205],{"class":63}," (task) {\n",[57,3207,3209,3212,3214,3216],{"class":59,"line":3208},29,[57,3210,3211],{"class":63},"    task.done ",[57,3213,552],{"class":81},[57,3215,722],{"class":81},[57,3217,3218],{"class":63},"task.done\n",[57,3220,3222],{"class":59,"line":3221},30,[57,3223,340],{"class":63},[57,3225,3227],{"class":59,"line":3226},31,[57,3228,191],{"class":63},[57,3230,3232,3234,3236],{"class":59,"line":3231},32,[57,3233,99],{"class":63},[57,3235,68],{"class":67},[57,3237,75],{"class":63},[57,3239,3241],{"class":59,"line":3240},33,[57,3242,110],{"emptyLinePlaceholder":109},[57,3244,3246,3248,3250],{"class":59,"line":3245},34,[57,3247,64],{"class":63},[57,3249,118],{"class":67},[57,3251,75],{"class":63},[57,3253,3255,3257,3259,3262,3264,3267,3270,3272,3275],{"class":59,"line":3254},35,[57,3256,126],{"class":63},[57,3258,1155],{"class":67},[57,3260,3261],{"class":71}," v-model.trim",[57,3263,552],{"class":63},[57,3265,3266],{"class":92},"\"keyword\"",[57,3268,3269],{"class":71}," placeholder",[57,3271,552],{"class":63},[57,3273,3274],{"class":92},"\"搜索任务\"",[57,3276,75],{"class":63},[57,3278,3280],{"class":59,"line":3279},36,[57,3281,110],{"emptyLinePlaceholder":109},[57,3283,3285,3287,3289,3292,3294],{"class":59,"line":3284},37,[57,3286,126],{"class":63},[57,3288,14],{"class":67},[57,3290,3291],{"class":63},">剩余 {{ remainingCount }} 个任务\u003C\u002F",[57,3293,14],{"class":67},[57,3295,75],{"class":63},[57,3297,3299],{"class":59,"line":3298},38,[57,3300,110],{"emptyLinePlaceholder":109},[57,3302,3304,3306,3308,3310,3312,3315,3318,3320],{"class":59,"line":3303},39,[57,3305,126],{"class":63},[57,3307,14],{"class":67},[57,3309,1679],{"class":71},[57,3311,552],{"class":63},[57,3313,3314],{"class":92},"\"filteredTasks.length === 0\"",[57,3316,3317],{"class":63},">没有匹配任务\u003C\u002F",[57,3319,14],{"class":67},[57,3321,75],{"class":63},[57,3323,3325],{"class":59,"line":3324},40,[57,3326,110],{"emptyLinePlaceholder":109},[57,3328,3330,3332,3334,3336],{"class":59,"line":3329},41,[57,3331,126],{"class":63},[57,3333,205],{"class":67},[57,3335,1728],{"class":71},[57,3337,75],{"class":63},[57,3339,3341,3344,3346,3348,3350,3353,3356,3358,3361],{"class":59,"line":3340},42,[57,3342,3343],{"class":63},"    \u003C",[57,3345,208],{"class":67},[57,3347,1822],{"class":71},[57,3349,552],{"class":63},[57,3351,3352],{"class":92},"\"task in filteredTasks\"",[57,3354,3355],{"class":71}," :key",[57,3357,552],{"class":63},[57,3359,3360],{"class":92},"\"task.id\"",[57,3362,75],{"class":63},[57,3364,3366,3369,3372],{"class":59,"line":3365},43,[57,3367,3368],{"class":63},"      \u003C",[57,3370,3371],{"class":67},"label",[57,3373,75],{"class":63},[57,3375,3377,3380,3382,3385,3387,3390,3393,3395,3398,3401,3403,3406],{"class":59,"line":3376},44,[57,3378,3379],{"class":63},"        \u003C",[57,3381,1155],{"class":67},[57,3383,3384],{"class":71}," type",[57,3386,552],{"class":63},[57,3388,3389],{"class":92},"\"checkbox\"",[57,3391,3392],{"class":71}," :checked",[57,3394,552],{"class":63},[57,3396,3397],{"class":92},"\"task.done\"",[57,3399,3400],{"class":71}," @change",[57,3402,552],{"class":63},[57,3404,3405],{"class":92},"\"toggleTask(task.id)\"",[57,3407,75],{"class":63},[57,3409,3411],{"class":59,"line":3410},45,[57,3412,3413],{"class":63},"        {{ task.title }}\n",[57,3415,3417,3420,3422],{"class":59,"line":3416},46,[57,3418,3419],{"class":63},"      \u003C\u002F",[57,3421,3371],{"class":67},[57,3423,75],{"class":63},[57,3425,3427,3430,3432],{"class":59,"line":3426},47,[57,3428,3429],{"class":63},"    \u003C\u002F",[57,3431,208],{"class":67},[57,3433,75],{"class":63},[57,3435,3437,3440,3442],{"class":59,"line":3436},48,[57,3438,3439],{"class":63},"  \u003C\u002F",[57,3441,205],{"class":67},[57,3443,75],{"class":63},[57,3445,3447,3449,3451],{"class":59,"line":3446},49,[57,3448,99],{"class":63},[57,3450,118],{"class":67},[57,3452,75],{"class":63},[14,3454,3455],{},"这个例子包含：",[205,3457,3458,3463,3468,3473,3479,3484,3489],{},[208,3459,3460,3462],{},[21,3461,27],{}," 保存状态。",[208,3464,3465,3467],{},[21,3466,31],{}," 推导筛选列表和剩余数量。",[208,3469,3470,3472],{},[21,3471,34],{}," 观察搜索词变化。",[208,3474,3475,3478],{},[21,3476,3477],{},"v-model"," 处理输入。",[208,3480,3481,3483],{},[21,3482,1665],{}," 处理空状态。",[208,3485,3486,3488],{},[21,3487,1807],{}," 渲染列表。",[208,3490,3491,3494],{},[21,3492,3493],{},"@change"," 处理事件。",[37,3496,3497],{"id":3497},"本章练习",[3499,3500,3501,3507,3515,3518,3523,3529,3536],"ol",{},[208,3502,3503,3504,3506],{},"创建一个 ",[21,3505,1882],{}," 数组，包含课程标题、时长、完成状态。",[208,3508,1894,3509,3511,3512,3514],{},[21,3510,1807],{}," 渲染课程列表，",[21,3513,1842],{}," 使用课程 id。",[208,3516,3517],{},"点击按钮切换完成状态。",[208,3519,1894,3520,3522],{},[21,3521,31],{}," 统计完成数量和总时长。",[208,3524,3525,3526,3528],{},"加一个搜索框，用 ",[21,3527,31],{}," 筛选课程。",[208,3530,1894,3531,3533,3534,930],{},[21,3532,34],{}," 把搜索词保存到 ",[21,3535,2404],{},[208,3537,3538],{},"用模板引用让页面加载后自动聚焦搜索框。",[157,3540,3541],{},"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 .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 .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 .s4XuR, html code.shiki .s4XuR{--shiki-default:#E36209;--shiki-dark:#FFAB70}",{"title":53,"searchDepth":78,"depth":78,"links":3543},[3544,3547,3549,3551,3555,3560,3562,3566,3568,3573,3578,3583,3584,3585,3586],{"id":39,"depth":78,"text":40,"children":3545},[3546],{"id":233,"depth":96,"text":233},{"id":270,"depth":78,"text":3548},"2. \u003Cscript setup> 为什么不用 return",{"id":574,"depth":78,"text":3550},"3. 插值表达式 {{ }}",{"id":783,"depth":78,"text":3552,"children":3553},"4. ref：最常用的响应式状态",[3554],{"id":998,"depth":96,"text":999},{"id":1032,"depth":78,"text":3556,"children":3557},"5. reactive：响应式对象",[3558],{"id":1178,"depth":96,"text":3559},"ref 和 reactive 怎么选",{"id":1271,"depth":78,"text":3561},"6. 属性绑定 v-bind",{"id":1397,"depth":78,"text":3563,"children":3564},"7. 事件绑定 v-on",[3565],{"id":1577,"depth":96,"text":1577},{"id":1661,"depth":78,"text":3567},"8. 条件渲染 v-if",{"id":1803,"depth":78,"text":3569,"children":3570},"9. 列表渲染 v-for",[3571],{"id":1900,"depth":96,"text":3572},"为什么必须写 key",{"id":2029,"depth":78,"text":3574,"children":3575},"10. computed：从已有状态推导新值",[3576,3577],{"id":2174,"depth":96,"text":2174},{"id":2230,"depth":96,"text":2230},{"id":2322,"depth":78,"text":3579,"children":3580},"11. watch：状态变化后做一件事",[3581],{"id":2416,"depth":96,"text":3582},"computed 和 watch 的区别",{"id":2533,"depth":78,"text":2534},{"id":2724,"depth":78,"text":2725},{"id":2873,"depth":78,"text":2874},{"id":3497,"depth":78,"text":3497},"md",{"order":96},"\u002Fsource\u002Fcode\u002Fvue\u002F03-vue-core",{"title":5,"description":16},"source\u002Fcode\u002Fvue\u002F03-vue-core","S96myrdolc7aMSJM7WerYC83HKuZ6AH9YiqI9w63g-g",1784032889391]