转载请注明出处:葡萄城官网,葡萄城为开发者提供专业的开发工具、解决方案和服务,赋能开发者。
原文参考: https://www.sitepoint.com/vue...
响应式系统(Reactivity systems)是现代前端框架的关键部分之一。应用系统的的高度交互性、动态性和响应能力全靠它支持。每一个Web开发人员而言都应该了解这一系统的功能和实践操做。前端
响应系统是一种使自动使数据源(模型)与数据表示(视图)层自动保持同步的机制。每次模型更改时,都会从新渲染视图。vue
以一个简单的Markdown编辑器为例。一般编辑器有两个窗格:一个窗格用于编写Markdown代码(用于修改基础模型),另外一个窗格用于预览已编译的HTML(显示已更新的视图)。当咱们在书写窗格中写东西时,它会当即在预览窗格中自动预览。这个例子比较简单,在实际状况中会复杂不少。react
在许多状况下,咱们要显示的数据取决于其余数据。在这种状况下,须要跟踪相关数据,并根据跟踪状况来更新数据。例如,咱们有一个fullName,该属性由firstName和lastName属性组成。修改其任何依赖项后,fullName将自动从新评估,并在视图中显示结果。数组
了解什么是响应式系统后,在了解Vue 3中的响应系统如何工做以及如何在实践中使用以前,让咱们一块儿来快速回顾一下Vue 2中的响应系统内容及其注意事项。浏览器
Vue 2中的响应或多或少会被“隐藏”。不管咱们放置在data对象中的是什么,Vue都会使其隐式反应(reactive implicitly)。这样虽然可使开发人员的工做更加轻松,但灵活度却会不可避免的下降。
在幕后,Vue 2使用ES5 Object.defineProperty将data对象的全部属性转换为getter和setter。对于每一个组件实例,Vue建立一个依赖关系观察程序实例,观察者会记录组件渲染期间依赖收集/跟踪的任何属性。当属性触发依赖项的设置器时,将通知观察者,并将组件从新渲染并更新视图。可是却也会有一些问题存在。前端框架
因为Object.defineProperty方法的限制,Vue没法检测到某些数据更改。包括:app
用下述实例讨论该状况:框架
<h1>Hello! My name is {{ person.name }}. I'm {{ person.age }} years old.</h1> <button @click="addAgeProperty">Add "age" property</button> <p>Here are my favorite activities:</p> <ul> <li v-for="item, index in activities" :key="index"> {{ item }} <button @click="editActivity(index)">Edit</button> </li> </ul> <button @click="clearActivities">Clear the activities list</button> </div>
el: '#app', data: { person: { name: "David" }, activities: [ "Reading books", "Listening music", "Watching TV" ] }, methods: { // 1. Add a new property to an object addAgeProperty() { this.person.age = 30 }, // 2. Setting an array item by index editActivity(index) { const newValue = prompt('Input a new value') if (newValue) { this.activities[index] = newValue } }, // 3. Modifying the length of the array clearActivities() { this.activities.length = 0 } } });
在上面的示例中,咱们会发现这三种方法都不起做用。咱们不能向该person对象添加新属性,没法使用activities的索引来编辑数组中的项目,也不能修改activities数组的长度。编辑器
优化以下:函数
el: '#app', data: { person: { name: "David" }, activities: [ "Reading books", "Listening music", "Watching TV" ] }, methods: { // 1. Adding a new property to the object addAgeProperty() { Vue.set(this.person, 'age', 30) }, // 2. Setting an array item by index editActivity(index) { const newValue = prompt('Input a new value') if (newValue) { Vue.set(this.activities, index, newValue) } }, // 3. Modifying the length of the array clearActivities() { this.activities.splice(0) } } });
在此示例中,咱们用Vue.setAPI方法将新age属性添加到person对象,并从活动数组中选择/修改特定项目。在最后一种状况下,使用JavaScript内置splice方法。
这个作法彻底可行但却略显笨拙,并且会致使先后代码不一致。而Vue 3就解决了这个问题。
咱们用下面示例继续看:
data() { return { person: { name: "David" }, activities: [ "Reading books", "Listening music", "Watching TV" ] } }, methods: { // 1. Adding a new property to the object addAgeProperty() { this.person.age = 30 }, // 2. Setting an array item by index editActivity(index) { const newValue = prompt('Input a new value') if (newValue) { this.activities[index] = newValue } }, // 3. Modifying the length of the array clearActivities() { this.activities.length = 0 } } } Vue.createApp(App).mount('#app')
能够看到在Vue 3中,全部方法均可以正常工做。
在Vue 2.6中,引入的Vue.observable API方法,必定程度的公开了响应式系统,使开发人员能够体验到响应式系统的内容。实际上,这和Vue内部用来包装data对象是彻底相同的方法,对于在简单场景建立小的跨组件状态存储颇有用。但依旧没办法和Vue3的响应式系统相比,接下来就为你们详细介绍。
注意:因为Object.defineProperty方法是仅限ES5且不可调整的功能,所以Vue 2不支持IE8及如下版本。
为了充分利用ES6 Proxy and Reflect API ,Vue 3中的响应式系统已被彻底重写。新版本新增响应式API,该API使系统比之前更加灵活和强大。
Proxy API容许开发人员拦截和修改目标对象上的更低级对象操做。代理(proxy)是对象的克隆/包装(clone/wrapper),并提供特殊功能(称为target),这些功能响应特定的操做并覆盖JavaScript对象的内置行为(称为traps)。若是仍然须要使用默认行为,则可使用相应的Reflection API,其名称顾名思义就是反映Proxy API的方法。这里有一个示例,用来了解如何在Vue 3中使用这些API:
name: "David", age: 27 }; const handler = { get(target, property, receiver) { // track(target, property) console.log(property) // output: name return Reflect.get(target, property, receiver) }, set(target, property, value, receiver) { // trigger(target, property) console.log(`${property}: ${value}`) // output: "age: 30" and "hobby: Programming" return Reflect.set(target, property, value, receiver) } } let proxy = new Proxy(person, handler); console.log(person) // get (reading a property value) console.log(proxy.name) // output: David // set (writing to a property) proxy.age = 30; // set (creating a new property) proxy.hobby = "Programming"; console.log(person)
要建立一个新的代理,使用new Proxy(target, handler)构造函数。它带有两个参数:目标对象(person对象)和处理程序对象,该对象定义将拦截哪些操做(get和set操做)。在handler对象中, get和set陷阱来跟踪什么时候读取属性以及什么时候修改/添加属性。设置控制台语句以确保运行正确。
在get和set陷阱采用下列参数:
注释中track函数和trigger函数特定用于Vue,用于跟踪什么时候读取属性以及什么时候修改/添加属性。
在示例的最后一部分,用控制台语句输出原始person对象。而后用另外一份声明中读取属性name的proxy对象。接下来,修改age属性并建立一个新hobby属性。最后,再次输出该对象以查看它是否正确更新。
以上就是Vue3响应式系统的完整工做流程,但在实际工做中会复杂得多。
使用Vue 3响应式系统,还有一些注意事项:
以上咱们将Vue2和Vue3中响应式系统部分进行了比较,并对响应式系统的工做原理进行了说明,在后面的文章中,咱们会进一步为你们介绍Vue3中响应式系统的API,敬请期待。
若是你已经熟练掌握Vue3, 不妨让咱们经过实际搭建一款基于Vue 3组件的表格编辑系统,更加深刻学习