基础
Last updated
Last updated
在前一章, 我们熟悉了 Vue.js 。我们已经在两个不同的程序中使用了它。 我们学习了如何在项目中应用 Vue.js。 我们实践了响应式数据绑定。
现在, 你可能会问自己: Vue 是怎样运作的? 它又是如何在数据模型变化时快速响应 UI 变化的? 你可能决定在项目中使用它, 想知道用不用遵循一些架构模式或者范例。 在本章我们将探索这些关键的概念, 理解隐藏在 Vue.js 背后的特性。 我们将分析所有安装 Vue.js 的方法, 同时为我们的方程式创建一个骨架, 然后在后续章节中不断地增强改进。 我们也会学习调试、 测试我们的方程式。
所以呢, 在本章,我们将学习如下内容:
什么是 MVVM 架构, 在 Vue.js 中如何体现
什么是声明式视图
Vue.js 如何定义属性, getters、 setters
响应式和数据绑定如何运作
什么是脏检查机制、 DOM、 虚拟 DOM
Vue.js 1.0 和 2.0 的区别
什么是可重用的组件
插件、 指令、 自定义插件、 自定义指令如何在 Vue.js 中运作
如何安装、 运行、 调试 Vue 方程式
你还记得我们是怎么创建 Vue 实例的吗? 我们以关键字 new Vue({...}) 来创建实例。 你一定记得在配置项中, 我们可以把 data 对象传递给绑定的元素。 data 对象是我们的模型, 而 DOM 元素是 Vue 实例绑定的地方。
Vue 中的经典视图模型事例
同时, 我们的 Vue 实例帮助我们把模型绑定到视图中, 反之亦然。 我们的方程式因此遵循着 Model-View-ViewModel(MVVM) 模式。
Model-View-ViewModel 模式简化图
我们的模型包含数据和一些基本逻辑, 视图对之响应。 视图模型控制数据绑定, 保证在模型数据的变化会迅速反应在视图中, 反之亦然。
我们的视图因此完全是数据驱动的。 视图模型响应了对数据流的控制, 这样数据绑定的声明才管用。
数据一旦传入 Vue 实例后将发生什么呢? 为什么这些被 Vue 应用的转换会自动地绑定到视图呢?
我们来分析一下我们需要做什么, 我是说, 每当我们需要给一个字符串应用一些变化给 DOM 元素时,我们该怎样应用这个监听函数? 在 var stringVar = 'hello' ; stringVar.onchange(doSomething) 中有太多的工作要做。
我们可以包装字符串的值, 设置一些 setting 或者 getting 函数, 当每次更新字符串的时候, DOM 也随之更新。 你会怎样实现这个功能呢? 当你思考这个问题时, 我将准备一些有趣而简短的例子。
在你的购物清单方程式中打开你的开发者工具, 写下如下代码:
将我们 DOM 元素赋值给 h2
如果我们把 text 的值赋给 obj.text 属性, 我们怎样才能追踪 h2 中每一次的属性变化呢?
我们可以使用 Object.defineProperty 方法(https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Object/define)。
这个方法允许我们创建一个 getter、 setter 函数, 因此可以获取这些属性的变化。
现在在控制台改变 obj.text 的属性, 观察标题
Vue.js 就是应用了这个机制。 当数据被传入到 Vue 实例中时, 它的所有属性都将通过 object.defineProperty 方法。 在页面中的每个指令,都被安排了一个 set 方法。 打开 vue.js 文件并搜索 set: function reactiveSetter(newVal) 。增加一个断点并调试购物列表的输入, 直到找到在函数中最后一个叫 dep.notify() 的调用:
在这个函数中, 你可以看到它正在遍历每一个属性的观察器, 并更新它们。 如果你跳过这个调用, 你将不会看到 DOM 的更新。 因为更新上执行的事件轮询被放在了一个定期执行的队列里。
找到 runBatcherQueue 函数, 并放入断点。 再次尝试改变标题的值。 如你所见, 这个函数将遍历正在队列里等待的观察器, 然后调用它们的 run 方法。 观察这个方法, 你可以看到它在比较新值和旧值。
然后会启动一个回掉
如果你再仔细研究一个这个回掉函数, 你会发现它会在最后更新 DOM 值。
很简单不是吗!
在这里用的是 Vue.js 1.0版本。
所以呢, Vue.js 的响应式机制非常简单。 观察器被赋到所有指令和数据属性上, 然后在 Object.defineProperty 的 set 方法上, 依次通知更新每个 DOM 或数据。
数据对象到 DOM 间的数据流
那些拥有指令的 DOM 元素都被附着上了监听器, 来依次通知更新每次调用的数据值。
当你尝试一个新工具时, 你一定想和其它工具或框架相比较一下。 你可以在 Vue.js 的官方页面找到一些深度地比较: http://vuejs.org/guide/comparison.html 。 在这些框架中我将在这里列出一些我认为重要的说明。
React 和 Vue 很像。 他们都使用了虚拟 DOM , 拥有可重用的组件, 响应式数据。 它值得一提, 但是, Vue 从 2.0 才开始使用虚拟 DOM。 2.0 之前它使用的是真实 DOM。 2.0 版本性能远超 1.0 同时也超过 React ( http://vuejs.org/guide/comparison.html#Performance-Profiles )。
两个框架最大的差别在于使用组件的方式。 你可能已经知道, 在 React 中所有一切都是 JavaScript。 用 JavaScript 开发所有的东东, 甚至是模板, 方程式一直运行在相同的作用域里,渲染变得非常有弹性。
但是, 一些需要快速原型的初级设计者, 或者是那些不想学习 JSX 的人来说, 这真是个痛点。 在 Vue 组件中, 你也可以使用 JSX, 也可以使用一般的 web 开发结构: 在 style 标签中写 CSS, 在 template 中写 HTML,在 script 标签中写 JavaScript 。 例如比较在 React 中写的渲染函数和在 Vue 组件的模板, 我将展示一个简单的事例来说明这些不同:
使用 Vue , 你只需写一些 HTML 代码在 template 标签中:
我个人喜欢把这些东西都分离开, 因此我发现 Vue 这种方式更对口。
另一件很棒的事是 Vue 允许你在组件中使用带有作用域的样式, 只需要在 style 标签加上 scoped 属性。
有了这个样式, 当你使用预处理器时,你可以在所在组件定义全局变量并创建或重定义样式。
值得一提的还有两个框架的学习曲线。 学习 React 你可能需要学习 JSX 和 ES2015 的语法, 因为大多数 React的官方事例都在用。 学习 Vue 你完全不需要这些, 就像使用 jQuery 一样,使用 Vue 模型和数据绑定非常简单。 然后选择对你有用的部分就行。
如果你想再深入地比较两个框架, 去看看文档, 精心制作相似的事例, 再看看哪个框架适合你。
Angular 1 和 Angular 2 差别很大。 Angular 2 和 Angular 1 完全不一样。 它拥有更好的表现, API 不同了, 底层实现也被重写了。
这两个版本是如此不同以至于在 Vue 的官方文档中分别对这两个框架进行了比较。 但是横向对比这两个版本的 Angular ,你会发现 Vue 比它们更加友好。 对比 Angular 和 Vue 的 hello world 方程式 (https://angular.io/docs/js/latest/quickstart.html ) (http://vuejs.org/guide/index.html#HelloWorld)
"即使没有 TypeScript, Angular 的快速指南也需要 ES2015, 18 个 NPM 依赖, 4 个文件, 3000 多行代码来输出 Hello World."
--http://vuejs.org/guide/comparison.html#Learning-Curve
如果你依然在使用 Angular 1, 值得一提的差别在于 Angular 的脏检查机制, 在存在大量观察器时, Angular 性能会明显下降, 而 Vue 只会重解析变化属性的观察器, 其它观察器不会变化。
我没写错, 这也值得比较。 Vue 最近已经升级到了更快更轻的第二版, 如果你还在用第一版, 绝对值得升级。 你可以在这里查看 2016 年 4 月份发布的相关信息 https://vuejs.org/2016/04/27/announcing-2.0/
在开始编码之前,让我们来回顾一下 Vue 的特性。 分析下什么是可重用的组件, 如何控制方程式的状态, 谈谈插件, 过滤器, 混入。 在这一部分, 我们将稍微浏览一下这些特性。 后面再深入学习。
既然你知道如何使用数据绑定, 也知道它如何运转, 是时候介绍另一项杀手级功能了。 Vue.js 创建的组件可以像盖房的砖块一样重用。 每个组件都拥有自己属于自己的样式和模板, 完全独立于其它组件。
创建组件的语法和创建 Vue 实例的语法很相似,你应该使用 Vue.extend 而非 Vue :
Vue.js 中的自定义组件
例如,把我们的购物列表拆分成组件。 如你所知, 我们的购物列表有三个基本部分: 列表项, 输入项, 标题变更项:
我们购物清单方程式的三个基本部分
我们可以把三个基本部分变为组件
现在我们来创建三个组件: ItemsComponent, ChangeTitleComponent, AddItemComponent。 它们都需要 data 属性。 AddItem 方法将从主要 Vue 实例转移到 ChangeTitleComponent。 所有必需的 HTML 将从 index.html 转移到每个组件。 所以最后,我们的脚本就像下面这样:
我们需要怎样在视图中使用这些组件呢? 我们只需用组件名替代相应的标记标签。 看起来像这样:
组件化的购物清单
第一个高亮区域我们将以 </add-itemcomponent> 标签来替换, 第二个拿 </items-component> 标签替换, 第三个拿 </change-title-component> 标签替换。 因此最终是这个样子的:
我们将在后续章节继续深入组件, 学习用更棒的方式来组织它们。
在前面的章节, 你已经学习了用指令来增强方程式的行为。
你已经学习了很多指令来绑定数据到视图(v-model, v-if, v-show... )。 在这些指令外, Vue.js 还允许你创建自己的自定义指令。 自定义指令机制允许你自定义 DOM 与 data 映射间的行为。
当注册一个自定义指令时, 你可以提供三个函数: bind, update, unbind。 在 bind 函数内, 你可以向元素附加一个事件监听器, 监听任何你需要的东东。 在 update 函数内, 它接收新值和旧值作为参数, 你可以在数据变化时自定义行为。 unbind 方法解绑所有需要解除的操作。
在 Vue 2.0 中, 指令管的事大大减少了 -- 现在它只用于底层 DOM 操作。 Vue 也更改了先前在自定义指令上的指南 ( https://github.com/vuejs/vue/issues/2873) 。
因此呢, 全新版本的自定义指令应该是这个样子地:
在精简版本中, 万一你想在数据变化时搞些动作, 可以只使用 update 方法, 它可以直接以第二个参数的形式传入指令方程:
理论很棒, 但是不来点实例就没意思了。 所以呢, 我们来看一个简单的例子, 当一个数字改变时, 计算它的平方。
在你的模板中这样用哦,加上 v- 前缀:
以 item 的值来实例化 Vue 。 你可以看到在 div 中的元素会立即更新。 完整代码在这里 https://jsfiddle.net/chudaol/we07oxbd/ 。
作为 Vue 的核心功能, 它提供对数据绑定的声明及组件编译。 主要通过一系列功能插件来增强。 有这么几类插件:
增加全局的属性或者方法(vue-element)
例如增加全局能力的插件(vue-touch)
在 Vue 属性上增加 Vue实例
提供一些扩展功能或 API (vue-router)
插件必须通过一个可以增强或改进的全局的 Vue 对象来提供一个实例方法。 为了更好地使用插件, Vue 使用了 use 方法来接收插件实例( Vue.use(SomePlugin))。
你可以写自己的插件来使 Vue 实例拥有自定义的行为。
我们这就以前面的自定义指令来创建一个简化版的插件吧。 创建一个叫 VueMathPlugin.js 的文件,然后这样写哦:
现在我们创建一个 script.js 文件。 加点代码。 在这个脚本中, 我们将导入 Vue 实例和 VueMathPlugin , 使用 use 方法来引用插件。
现在创建一个 index.html 文件来引入 main.js 文件(当然我们需要 Browserify 和 Babelify)。 在这个文件中,我们在 input 上增加一个 v-model 指令, 用于输入值。 创建两个 span 来使用 v-square 和 v-sqrt 指令:
创建一个 package.json 文件来引入我们需要的依赖。
现在安装依赖, 构建项目
npm install npm run build
在浏览器中打开 index.html。 尝试改变输入框中的值。 观察效果。
数据被立刻响应在自定义插件中的指令上
用三角函数(sine, cosine, tangent)来增强 MathPlugin 。 当然你也可以使用 Annexes。
当方程式达到一定体积时, 有必要来管理全局的的状态了。 受到 Flux( https://facebook.github.io/flux/) 的启发,我们有了 Vuex 来管理共享 Vue 组件中的状态。
别以为这很难理解哦(●'◡'●)。 实际上呢,就是些数据。 每个组件拥有它自己的数据, "方程式状态" 指的就是可以在组件中共享的数据!
Vuex 是如何管理状态更新的
就像其它插件, 你需要通知 Vue 来 use 它。
然后初始化组件, 声明实例化 store
现在呢, 主程序和它所有的组件已经知道了 store , 并可以访问它了, 也可以在方程式的生命周期里制动。 我们将在后面的章节仔细研究它。
是的, 没错 Vue 拥有自己的命令行工具。 它可以帮助我们初始化任何我们想配置的 Vue 方程式。 你可以使用 Webpack 模板, Browserify 模板, 或者只创建一个简单的 HTML 文件。
npm 安装:
npm install -g vue-cli
各种初始化方程式的方法:
为了查看区别, 我们通过运行 vue init 来创建一个简单的模板和 Webpack 模板, 看看生成的结构有什么区别。
vue init simple 和 vue init webpack 的输出
下面是方程式结构的区别:
vue init simple 和 vue init webpack 生成的文件结构差别
index.html 文件只是一个包含 Vue.js 的简单配置文件, 所以如果你只是想搞个快速原型的话, 就用这个吧。
如果你想搞个可以测试及热加载的复杂单页应用的话, 使用 Webpack 或者 Browserify 配置。
这里有许多 Vue 语法高亮插件:
在这部分我们要分析所有安装 Vue.js 的方法, 我们会创建一个在后续章节中继续开发的应用的骨架。 我们也会学习调试测试方程式的几种方法。
这里有一堆方法去安装 Vue.js ,下载脚本后引入 HTML 文件中的 script 标签中, 使用 bower , npm 或者 Vue 的 命令行工具都可以启动整个方程式。
我们选一种自己最喜欢的就行, 我们开始吧。
下载 vue.js。 这里有多个版本, 简化版和开发版。 开发版在这 ( https://vuejs.org/js/vue.js) 。 精简版在这 (https://vuejs.org/js/vue.min.js ) 。
如果你是在开发环境中, 请用非压缩的版本。 你会爱上这些在控制台打出的小提示和警告的。
在 script 标签内引入 vue.js :
Vue 已经被注册为全局变量了, 你可以直接使用它:
Vue.js 可从下面 CDN 获取
jsdeliver: https://cdn.jsdelivr.net/vue/2.0.3/vue.js
unpkg: https://unpkg.com/vue@2.0.3/dist/vue.js (推荐)
在你的 script 中加入路径即可使用
CDN 版本有可能不与最新版同步。
我们的例子有可能与独立安装的版本不一致, 我们使用了 CDN。
如果你已经使用了 Bower 来管理方程式, 也不想用别的工具, 这里也可以使用 Bower 下载。
我们的事例就像前两个一样, 只不过已经换成在 bower 文件中啦(●'◡'●)。
内容安全协议是一项标准协议, 所有的方程式应该遵守从而避免安全攻击。 如果你是为浏览器开发方程式, 你一定对这条协议很熟悉。
对那些要求兼容 CSP 的脚本环境, 这里有个特殊版本的 Vue.js https://github.com/vuejs/vue/tree/csp/dist 。
我们来示范一下在 Chrome 方程式中的关于 Vue.js 的 CSP-compliant!
首先为我们的事例创建一个文件夹。 在 Chrome 方程式中最重要的是 manifest.json 文件, 它用于描述你的方程式。 创建并写入下面信息:
下一步来创建我们的 main.js 文件, 它作为 Chrome 方程式的入口。 脚本应该监听方程式的启动并打开指定大小的新窗口。 我们指定窗口大小为 500 x 300 , 在 index.html 打开。
现在,Chrome-specific 方程式的神奇魔法已经结束, 我们需要创建我们的 index.html 文件, 就像前面一样写入相同的代码。
下载好 CSP-compliant 版本的 Vue.js 并把它添加到 assets 文件夹。
好了, 我们一起来创建 app.js 文件吧。
把它放到 assets 文件夹中。
别忘了创建两个 16 像素和 128 像素的 icon 哦。
你的代码应该和我的会很像:
使用 vue.js 为 Chrome 方程式提供的代码结构
当然最重要的事是来测试一下哦!
在你的 Chrome浏览器中打开 chrome://extensions/url
切换到开发者模式
点击安装扩展, 找到我们刚创建的文件夹
你的方程式就会出现在列表中了! 点击启动。
用 vue.js 制作的简单 Chrome 方程式
恭喜! 你已经制作了一个 Chrome 方程式。
npm 安装方式用于大规模应用。 启动 npm install 就像下面这样:
然后引用它:
如果你喜欢 ES2015 ,可以这样引入
我们的 HTML 文件看起来是这样的:
现在创建 script.js 它应该就像独立版或 CDN 安装的那样, 只是在 require 这里不一样。
我们需要安装 Vue 和 Browserify 来把我们的 script.js 编译到 main.js 中:
在 package.json 文件中, 加点脚本来启动 Browserify 。我们的 package.json 就像下面这样:
现在运行一下命令:
npm run build
打开 index.html
我有个朋友在这时说: 啥? 这么多步骤, 安装, 命令行, 说明....结果就是这样的? 手动再见。
如果你也这么想, 当然你以一种复杂的方法在做一件简单的事, 但是当你的方程式有更大规模的时候, 你会发现用上这些工具会把那些复杂的事会变得更加简单, 哈哈哈, 该休息下了!
正如我们前面提及的, Vue 提供了自己的命令行工具, 它允许我们以我们想要的工作流来启动单页方程式。 它也提供了热重载及测试开发环境。 安装完 vue-cli 后, 运行 init <模板> <项目名> 就行了。
现在打开 loaclhost:8080 。 打开源文件, 你可以看到 app.vue 文件, 你还记得我们说组件就像构建我们方程式的砖块一样吗? 记得我们在 main.js 中创建注册组件, 我提示你说我们将学习更加优雅地构建组件吗? 哈哈, 你现在就会知道如何以一种更棒的方法来构建组件了!
找到 import Hello from './components/Hello' 这行。 这正好说明了组件如何在另外的组件中被使用。看看上面的模板文件, 它包含 标签。 在 HTML 文件中 hello 组件就是这样呈现的。 看看这个组件; 它在 src/components 文件夹中。 如你所见, 这确实和我们之前做的很像。 我们来修改一下:
在 App.vue 组件里移除除了 hello 标签外的模板:
现在返回方程式, 你将看到以下图片:
用 vue-cli 启动 Vue 方程式
除了 Webpack 模板外,你还可以选择下面几种配置
webpack-simple: 精简版, Webpack + vue-loader ,适合快速原型
browserify: 完整版, Browserify + Vueify + hot-reload, linting, init-testing
browserify-simple: 精简版, Browserify + Vueify , 适合快速原型
simple: 最简单的版本
我亲爱的读者, 你已经知道了如何安装使用 Vue.js ,也明白了它的运行机制, 你一定跃跃欲试了吧!
俺明白。 你需要从 GitHub 下载开发版的 Vue.js。
我们这就来构建一个事例。 创建像 dev-build 之类的文件夹, 把所有 npm 文件拷贝进去。
现在构建我们的方程式
打开 index.html ; 我们看到了 Learing Vue.js 的标题。
我们再来修改一点 vue.js 的源码! 找到 node_modules/vue/src/compiler/parser 文件夹, 打开 text-parser.js 文件, 找到下面这行:
实际上这个正则定义了 HTML 模板中默认的分隔符。 分隔符里面的东东被认为是 Vue 数据 或 JavaScript 代码。 我们来修改一下! 我们用 % % 来替代 {} :
现在重新构建 Vue 源码, 刷新浏览器, 瞧瞧我们发现了什么?
在改变 Vue 源码后, 大括号不能正常执行了!
那些在大括号内的信息已经不能被 Vue 识别了, 事实上, 它被当成了 HTML 的一部分。
现在我们打开 index.html , 用 %% 替代 大括号 :
重新构建,刷新浏览器, 现在怎么样了? 又好了! 哈哈, 我敢肯定你现在有一大堆想法来定制 Vue.js ,还等什么, 马上出发吧!
你可以像调试其它网络方程式一样调试 Vue。 使用你自己的开发者工具 (firebug), breakpoints, debugger statements.... 如果你想仔细研究 Chrome 的调试工具可以看看这个文档 https://developer.chrome.com/devtools。
我们也提供 Vue.js 的开发者工具, 它很容易调试 Vue 方程式。 你可以从 Chrome 商店里下载安装 https://chrome.google.com/webstore/detail/vuejsdevtools/nhdogjmejiglipccpnnnanhbledajbpd 。
扫兴的是, 它不能调试本地打开的文件, 搭建一些简单的服务器就行拉(例如 https://www.npmjs.com/package/http-server )。
然后安装, 打开,我们的购物清单方程式, 打开开发者工具, 你可以看到 Vue 选项卡已经出现啦:
Vue 开发者工具
在这里, 我们只有一个组件 -- Root 。 你可以想象, 当我们有一堆组件时, 它们将会出现在 Vue 开发工具的调试盘上。 点击 Root 组件并检查。 你可以看到所有绑定到这个组件上的数据。 如果你想改变一些, 例如, 增加一个列表项, 切换复选框, 改变标题....所有的改变都将被传播到 Vue 开发者工具上。 你可以在右手边看到变化。 我们这就来试试, 增加一条列表项。
模型内的变化将迅速同步到 Vue 开发者工具中。
你还记得在第一章我们开始的方程式吗? 购物清单和番茄钟。 在这个部分, 我们将使用 vue-cli 来搭建我们方程式, 让它包含可重用的组件, 可测试, 易于部署。 一旦我们启动了方程式, 我们便会一直使用它到本书最后。 好吧, 我们开始吧!
我们将使用 vue-cli 生成 Webpack 配置的购物清单脚手架。
记得先安装 vue-cli : npm install -g vue-cli
如果你已经安装了 vue-cli, 打开你要创建方程式的文件夹, 输入:
所有的问题都回答 yes ! 然后你的方程式就启动了:
用 vue-cli 启动购物清单方程式
切换到购物清单文件夹, 运行 npm install, npm run dev。 在你的浏览器中打开 loaclhost:8080 , 你将看到 Hello World 页面。
新创建的 Hello World 视图
我们来清空启动代码, 从而添加上我们自己的代码。 进入 App.vue 文件,删除所有东东, 只留下下面的结构:
template
script
style
在最后我们的 App.vue 文件应该像这样:
打开文件看看效果, 嗯,很好。 其实你啥事都没做, 一个空白页。
我们往 template 标签内加点东西, 查看页面, 它自动更新啦。 这是因为 vue-hot-reload 插件发现了你在 Vue 组件中改动, 它自动重构建了项目, 而且重新刷新了浏览器页面。 试试在 script 标签内写点东西, 比如一个未定义的变量:
页面不会刷新, 在你的命令行里看看, 它显示了一个错误:
每次文件变化, lint 也会被启动。
这是由于 ESLint 插件的原因, 所以会在代码变化时执行 lint 。
有了它, 我们可以保证代码的质量。
说到质量, 我们应该准备让我们的方程式运行单元测试。
幸好, Webpack 版的 vue-cli 已经为我们安排好了。 运行 npm run unit 就可以运行单元测试了, 运行 npm e2e 运行端对端测试。 因为端对端测试和方程式用了相同的端口, 它俩不能同时启动。 所以, 如果你想在开发时跑测试, 你应该在 config/index.js 里改变端口, 或者暂停方程式。 在测试后, 我们发现测试失败了。 这是因为它检查了那些我们移除的具体元素。 打开 test/e2e/specs 文件夹, 清除所有我们不需要的断言。 看起来应该是这样的:
返回测试。 现在能通过了。 从现在开始, 我们需要在我们的方程式里增加一些代码, 然后再写些单元测试和端对端测试。
运行 vue init webpack pomodoro 重复必要的步骤, 开始运行。
将番茄钟打造成一个 Chrome 方程式! 你只需要使用 CSP-compliant 版本的 Vue.js 并添加 manifest.json 文件。
在本章,我们分析了 Vue.js 幕后的东东。 你已经知道了响应式数据是如何实现的。 你看到了 Vue.js 使用 Object.defineProperty 的 getters 和 setters 来传播数据变化。 你看到了 Vue.js 的关键概念,像是可重用的组件, 插件系统, 状态管理。 我们已经启动了在后续章节持续开发的方程式。
在下一章, 我们将深入 Vue 的组件系统。 我们将在方程式中使用组件。
object.defineProperty 在每次属性变化时被调用
在 setter 函数中调用观察方法处的断点