(一)响应式数据
1. 简单例子
从最简单的数据绑定开始,在 Vue 2.0 中,我们这样将一个数据绑定到模板的指定位置:
在组件创建参数的 data 构造函数中返回一个用来绑定的数据对象,其中有个 now 字段,会被渲染到模板内的 .app > p 内。
<template>
<div class="app">
<h1>Hello world!</h1>
<p>Now is: {{now.toString()}}</p>
</div>
</template>
<script>
// Vue 2.0
export default {
data() {
return {
now: new Date(),
};
},
};
</script>
用 Vue3 的组装 API 实现的话,则是这样:
// Vue 3.0
export default {
setup() {
return {
now: new Date(),
};
},
};
2. 更新数据
奇怪,看起来好像没啥区别,只是把 data 改成了 setup 吗?
并不是,假如我们现在对这个 DEMO 做个小改动,让它每秒钟刷新一次时间,用 Vue2 大概是这样实现:
// Vue 2.0
export default {
data() {
return {
now: new Date(),
};
},
mounted() {
setInterval(() => this.now = new Date(), 1000);
},
};
而 Vue3 的等效实现则为:
// Vue 3.0
import { ref, onMounted } from 'vue';
export default {
setup() {
const now = ref(new Date());
onMounted(() => {
setInterval(() => now.value = new Date(), 1000);
});
return {
now,
};
},
};
3. 对比分析
写了太多 Vue 的我们可能已经忘了,Vue2 的代码从标准 JS 模块的角度来看有多奇怪:
mounted中修改的this.now数据是在哪创建的?我们在模块default对象的成员里并没有找到对应字段,倒是在data内返回的另一个对象中有这个字段;- 而
data中返回的now也不是真正的this.now,而是this.now的初始值,在data中setInterval修改now并不能更新渲染出来的时间; - 如果想复用这个数据和它的更新逻辑,你必须将这样的结构单独写一份,然后通过特殊的
mixin函数混入到当前组件的构造参数内。
这一切,是因为整个模块 default 对象其实是 vm 对象的构造参数。其背后隐藏了对象的创建逻辑,在构造对象时构造参数中的一些不同层级的字段被绑定到了 vm 对象上。
不少新手可能都犯过一个错误,在 data 中返回的数据字段和 props、methods 或者 computed 中的字段命名撞车(尤其是使用名为 data 的字段),在编码阶段并不能被 IDE 直接发现。就是因为上面的原因,这些字段创建时隶属于不同的位置,在之后构造时才被绑在了同一个对象上,导致了运行时才能发现的冲突。
Vue3 中,改成提供 ref、reactive、toRef、onMounted 等函数的形式实现,例子中:
- 在
setup中看到的now即是用于绑定的this.now; - 修改
now.value即可看到页面状态的更新; - 如果要封装这份数据处理,只需要将
now和onMounted处理提取到同一个函数内,再将now返回即可,不再需要黑盒的mixin处理。
可以说 Vue3 是直接将响应数据的创建决定权、生命周期的通知回调,都通过 API 的形式交给了开发者,更直观明了和可控。
4. API 说明
下面详细说说常用的几个响应式数据相关 API:ref, reactive 和 toRefs。
(1) ref
上面例子中使用到的 ref,可以将一个数据包装成响应式数据代理对象。
const count = ref(0); console.log(count.value); // => 0 count.value++; console.log(count.value); // => 1
当你修改代理对象的 count.value 属性时,模板中使用到 count 的位置将响应数据的变化,更新视图中的数据状态。
(2) reactive
对于对象的响应式封装,使用 ref 稍显麻烦:
const state = ref({
count: 0,
});
console.log(state.value.count); // => 0
state.value.count++;
console.log(state.value.count); // => 1
这时可以改为使用 reactive,像操作普通对象的字段一样修改 count 即可更新视图:
const state = reactive({
count: 0,
});
console.log(state.count); // => 0
state.count++;
console.log(state.count); // => 1
对代理对象 state 添加新的字段也可触发视图更新。
(3) toRefs
有时候,对象的名字过长,我们想直接在模板内使用对象内部字段,直接使用解构是不行的:
import { reactive } from 'vue';
export default {
setup() {
const position = reactive({
x: 0,
y: 0,
});
return {
// 错误,解构出来的 x, y 并没有响应式代理。绑定到模板上后,数据变化无法触发视图更新
...position,
};
},
};
这个情况下,使用 toRefs 处理后再解构赋值即可:
import { reactive, toRefs } from 'vue';
export default {
setup() {
const position = reactive({
x: 0,
y: 0,
});
return {
...toRefs(position),
};
},
};
但需要注意,toRefs 只处理调用时 position 的现有字段,如果在之后对 position 增加新字段,将无法触发视图更新。
以上就是浅析 Vue 3.0 的组装式 API(一)的详细内容,更多关于Vue 组装式 API的资料请关注其它相关文章!
免责声明:本站文章均来自网站采集或用户投稿,网站不提供任何软件下载或自行开发的软件! 如有用户或公司发现本站内容信息存在侵权行为,请邮件告知! 858582#qq.com
《魔兽世界》大逃杀!60人新游玩模式《强袭风暴》3月21日上线
暴雪近日发布了《魔兽世界》10.2.6 更新内容,新游玩模式《强袭风暴》即将于3月21 日在亚服上线,届时玩家将前往阿拉希高地展开一场 60 人大逃杀对战。
艾泽拉斯的冒险者已经征服了艾泽拉斯的大地及遥远的彼岸。他们在对抗世界上最致命的敌人时展现出过人的手腕,并且成功阻止终结宇宙等级的威胁。当他们在为即将于《魔兽世界》资料片《地心之战》中来袭的萨拉塔斯势力做战斗准备时,他们还需要在熟悉的阿拉希高地面对一个全新的敌人──那就是彼此。在《巨龙崛起》10.2.6 更新的《强袭风暴》中,玩家将会进入一个全新的海盗主题大逃杀式限时活动,其中包含极高的风险和史诗级的奖励。
《强袭风暴》不是普通的战场,作为一个独立于主游戏之外的活动,玩家可以用大逃杀的风格来体验《魔兽世界》,不分职业、不分装备(除了你在赛局中捡到的),光是技巧和战略的强弱之分就能决定出谁才是能坚持到最后的赢家。本次活动将会开放单人和双人模式,玩家在加入海盗主题的预赛大厅区域前,可以从强袭风暴角色画面新增好友。游玩游戏将可以累计名望轨迹,《巨龙崛起》和《魔兽世界:巫妖王之怒 经典版》的玩家都可以获得奖励。