Vue 3中那些激动人心的新功能
让我们先从大多数人可能都听说过的 API 开始……
合成(Composition)API 是 Vue 的新大版本中讨论最多的特色语法。这是一种全新的逻辑复用和代码组织方法。
目前,我们使用所谓 Options API 构建组件。要将逻辑添加到 Vue 组件中,我们要填充(option)诸如data
、methods
、computed
之类的属性。这种方法的最大缺点是它本身并非有效的 JavaScript 代码。你需要准确了解模板中可以访问哪些属性,以及this
关键字的行为。在后台,Vue 编译器需要将属性转换为可用的代码。因此我们无法享受自动提示或类型检查功能的帮助。
合成 API 会将组件属性中当前可用的机制暴露为 JavaScript 函数,从而解决这个问题。Vue 核心团队将合成 API 定义为“一组基于函数的附加 API,可以灵活地组合组件逻辑”。用合成 API 编写的代码更具可读性,也没有在幕后隐藏什么魔法,这使它更易于阅读和学习。
<template>
<button @click="increment">
Count is: {{ count }}, double is {{ double }}, click to increment.
</button>
</template>
<script>
import { ref, computed, onMounted } from 'vue'
export default {
setup() {
const count = ref(0)
const double = computed(() => count.value * 2)
function increment() {
count.value++
}
onMounted(() => console.log('component mounted!'))
return {
count,
double,
increment
}
}
}
</script>
import { ref, computed, onMounted } from 'vue'
如前所述,合成 API 将组件属性暴露为函数,因此第一步是导入所需的函数。在我们的示例中,我们需要用ref
创建响应性引用、用computed
创建计算属性,并用onMounted
访问挂载的生命周期 hook。
setup
方法是做什么的?export default {
setup() {
简单说,它只是一个将属性和函数返回到模板的函数,仅此而已。我们在这里声明所有响应属性、计算属性、观察者和生命周期 hooks,然后返回它们,以便在模板中使用。
setup
函数返回的内容将无法在模板中使用。const count = ref(0)
ref
函数声明了称为count
的响应属性。它可以包装任何原语或对象,并返回其响应性引用。传递的元素的值将保留在所创建引用的value
属性中。例如,如果要访问count
引用的值,则需要显式请求count.-value
。const double = computed(() => count.value * 2)
function increment() {
count.value++
}
double
和increment
函数时所做的事情。onMounted(() => console.log('component mounted!'))
onMounted
hook 在组件挂载时记录了一些消息,这里只是告诉你可以这样做😉return {
count,
double,
increment
}
increment
方法返回count
和double
属性,以使其在模板中可用。<template>
<button @click="increment">
Count is: {{ count }}, double is {{ double }}. Click to increment.
</button>
</template>
好了!现在,我们可以访问模板中setup
方法返回的属性和函数,就像通过旧的 Options API 声明它们一样。
这是一个简单的示例,也可以通过 Options API 轻松实现。新的合成 API 的真正好处不仅仅是以不同的方式编码,在复用我们的代码 / 逻辑时,其优势就能显现出来。
新的合成 API 有更多优势。想想代码复用,这就是它的一大用武之地。目前,如果我们要在其他组件之间共享一些代码,则有两个选择可用——分别是 mixins 和作用域插槽。两者都有自己的缺点。
假设我们要提取counter
功能并在其他组件中复用。下面的代码中你可以看到如何分别使用现有的 API 和新的合成 API 做到这一点:
import CounterMixin from './mixins/counter'
export default {
mixins: [CounterMixin]
}
mixins 的最大缺点是我们对它实际上添加到组件中的内容一无所知。这不仅让代码很难理解,而且还可能导致命名与已有的属性和函数发生冲突。
<template>
<Counter v-slot="{ count, increment }">
{{ count }}
<button @click="increment">Increment</button>
</Counter>
</template>
使用作用域插槽时,我们确切地知道可以通过v-slot
属性访问哪些属性,因此代码更容易理解。这种方法的缺点是我们只能在模板中访问它,并且只能在Counter
组件作用域中使用。
function useCounter() {
const count = ref(0)
function increment () { count.value++ }
return {
count,
incrememt
}
}
export default {
setup () {
const { count, increment } = useCounter()
return {
count,
increment
}
}
}
是不是更优雅?我们不受模板和组件作用域的限制,并且确切地知道可以从 counter 访问哪些属性。此外,由于useCounter
只是返回某些属性的函数,因此我们可以获得编辑器中代码自动完成的帮助。没有隐藏在幕后的魔法,因此编辑器可以帮助我们检查类型并给出建议。
useStore
函数,而不用污染 Vue 原型(this.$store
),这种方法也消除了 Vue 插件的幕后魔法。const { commit, dispatch } = useStore()
如果你想了解有关合成 API 及其用例的更多信息,我强烈建议你阅读 Vue 团队写的这篇文档(见下方链接)。这份文档解释了新 API 背后的理念,并给出了最佳用例的建议。Vue 核心团队的 ThorstenLünborg 还提供了一个很棒的存储库,其中包含合成 API 的使用示例。
文档:https://vue-composition-api-rfc.netlify.com/
存储库:https://github.com/LinusBorg/composition-api-demos
import Vue from 'vue'
import App from './App.vue'
Vue.config.ignoredElements = [/^app-/]
Vue.use(/* ... */)
Vue.mixin(/* ... */)
Vue.component(/* ... */)
Vue.directive(/* ... */)
new Vue({
render: h => h(App)
}).$mount('#app')
目前我们使用全局Vue
对象来提供配置并创建新的 Vue 实例。对Vue
对象所做的任何更改都会影响每个 Vue 实例和组件。
import { createApp } from 'vue'
import App from './App.vue'
const app = createApp(App)
app.config.ignoredElements = [/^app-/]
app.use(/* ... */)
app.mixin(/* ... */)
app.component(/* ... */)
app.directive(/* ... */)
app.mount('#app')
你可能已经注意到,每个配置都局限于使用createApp
定义的某个 Vue 应用程序。
它可以让你的代码更容易理解,并且不容易出现由第三方插件引起的意外问题。当前,如果某些第三方解决方案正在修改 Vue 对象,则可能会以意想不到的方式(尤其是全局 mixins)影响你的应用程序,而 Vue 3 则不会出现这种情况。
这一 API 更改现在正在这个 RFC 中讨论,意味着将来它可能还会继续变动。
RFC:https://github.com/vuejs/rfcs/pull/29
Vue 3 中值得期待的另一个激动人心的新功能是片段(Fragments)。
<template>
<div>Hello</div>
<div>World</div>
</template>
原因是代表任何 Vue 组件的 Vue 实例都需要绑定到单个 DOM 元素中。想要创建具有多个 DOM 节点的组件,唯一的方法是创建一个没有基础 Vue 实例的功能组件。
class Columns extends React.Component {
render() {
return (
<React.Fragment>
<td>Hello</td>
<td>World</td>
</React.Fragment>
);
}
}
尽管片段看起来像是普通的 DOM 元素,但它是虚拟的,根本不会在 DOM 树中渲染。这样我们可以将组件功能绑定到单个元素中,而无需创建多余的 DOM 节点。
目前,你可以在 Vue 2 中使用 vue-fragments 库来应用片段,而在 Vue 3 中它是开箱即用的!
React 生态系统中还有一个好主意也将在 Vue 3 中采用,就是 Suspense 组件。
<Suspense>
<template >
<Suspended-component />
</template>
<template #fallback>
Loading...
</template>
</Suspense>
在Suspended-component
完全渲染之前将显示回退组件。Suspense 可以等待组件下载完毕(如果该组件是异步的),或者在setup
函数中执行一些异步操作。
V-model 是一种指令,可用于在给定组件上实现双向绑定。我们可以传递响应性属性,并从组件内部对其进行修改。
v-model
:<input v-bind="property />
v-model
吗?在后台,v-model
只是传递value
属性和侦听input
事件的捷径。将上面的示例重写为以下语法会有完全相同的效果:<input
v-bind:value="property"
v-on:input="property = $event.target.value"
/>
model
属性更改默认属性和事件的名称:model: {
prop: 'checked',
event: 'change'
}
如你所见,如果我们希望在组件中进行双向绑定,则v-model
指令可能是一个非常有用的语法糖。不幸的是,每个组件只能有一个v-model
。
v-model
赋予属性名称,并根据需要拥有尽可能多的v-model
。下面这个示例中,你可以在一个表单组件中找到两个v-model
:<InviteeForm
v-model:name="inviteeName"
v-model:email="inviteeEmail"
/>
这一 API 更改现在正在这个 RFC 中讨论,这意味着将来可能会有新的变化。
RFC:https://github.com/vuejs/rfcs/pull/31
Portals 是特殊的组件,用来在当前组件之外渲染某些内容。这也是 React 原生实现的功能之一。React 文档关于 portals 是这样介绍的:
“Portals 提供了一种一流的方式来将子级渲染到父组件的 DOM 层级之外的 DOM 节点中。”
这是一种处理模态、弹出窗口以及页面顶部组件的非常好用的方法。通过 portals,你可以确保没有任何主机组件 CSS 规则会影响你要显示的组件,也无需使用z-index
搞些小动作了。
对于每个 portal,我们需要指定其目标位置,在其中渲染 portal 内容。下面是 portal-vue 库的实现,它为 Vue 2 添加了这一功能:
<portal to="destination">
<p>This slot content will be rendered wherever thportal-target with name 'destination'
is located.</p>
</portal>
<portal-target name="destination">
<!--
这个组件可以放在你应用中的任何位置上
上面 portal 组件的插槽内容会在这里渲染。
-->
</portal-target>
Vue 3 将提供对 portals 的开箱即用支持!
自定义指令 API 在 Vue 3 中将略有变化,以更好地与组件生命周期保持一致。这项更改会让 API 更加直观,从而帮助新手更容易地理解和学习 API。
const MyDirective = {
bind(el, binding, vnode, prevVnode) {},
inserted() {},
update() {},
componentUpdated() {},
unbind() {}
}
const MyDirective = {
beforeMount(el, binding, vnode, prevVnode) {},
mounted() {},
beforeUpdate() {},
updated() {},
beforeUnmount() {}, // new
unmounted() {}
}
虽然这是一项重大更改,使用 Vue 兼容构建也应该能轻松覆盖。
这一 API 更改现在正在这个 RFC 中讨论,意味着将来它可能还会继续变动。
RFC:https://github.com/vuejs/rfcs/pull/32/files
除了合成 API(它是 Vue 3 中最重要的新 API)之外,我们还能在新版中找到很多较小的改进。我们可以看到,Vue 正在向更好的开发人员体验和更简单、更直观的 API 的目标前进。我们也很高兴看到 Vue 团队决定采用目前由第三方库带来的许多理念,将它们引入核心框架。
上面的内容只介绍了主要的 API 更改和改进。如果你对其他内容感到好奇,请务必查看 Vue RFCs 存储库。
Vue RFCs 存储库:https://github.com/vuejs/rfcs/
Filip Rakowski 是一名 Web 开发人员,对最新的 Web 技术充满热情,并且特别喜欢 Vue 和渐进式 Web 应用。他的日常工作是开发开源产品、开发程序员接口以及与社区互动。他是 Vue Storefront 的联合创始人、StorefrontUI 的作者、Vue.js 官方社区合作伙伴和 VuePress 核心团队成员。
原文链接:https://vueschool.io/articles/vuejs-tutorials/exciting-new-features-in-vue-3/
近年来,随着 jQuery 的落幕,三大框架的割据以及小程序的爆发,大前端的发展也经历了从静态页面到 JavaScript 跨时代的诞生,再从 PC 端到移动端的转向,以及由依赖后端到前后端分离的架构演变。
腾讯在线教育前端团队,近年来在大前端技术架构演进方面也有了不少突破,如 Hybird 方案、离线包方案、PWA 结合 SSR 方案,以及 RN 动态化方案的落地和执行等。
这次 GMTC 全球大前端技术大会(深圳站)2019,我们专门请到了 腾讯的前端高级工程师曹海歌,希望可以从腾讯在线教育前端团队的实操案例中,深入了解腾讯为提升研发效率,进行的前端工程化体系建设过程。扫描下方二维码或点击阅读原文,查看详情。
- 那些复杂的列表总要弄个清楚——(四)激动人心的BaseAdapter之二
- 那些复杂的列表总要弄个清楚——(三)激动人心的BaseAdapter之一
- 关于 Vue.js:那些好的,不怎么样的和糟糕的
- 激动人心的AutoCAD .net开发技术
- 丰富的开发体验和激动人心的用户体验:XAML
- 创业-一个激动人心的想法
- 推荐一个激动人心的Silverlight网站应用
- 4月《程序员》上我讲HTML5的文章---激动人心的HTML5之美
- 激动人心的Windows 8之旅 !!!!!!!!
- SQL Server 2012 的12个激动人心的功能
- IT外企那点儿事(4):激动人心的入职演讲
- SQL Server 2012 的12个激动人心的功能
- 最激动人心的图片--DirectShow两兄弟
- An exciting trip 激动人心的旅行
- 4月《程序员》上我讲HTML5的文章---激动人心的HTML5之美
- vue项目实战 — — 那些自己给自己挖的深坑
- 程序开发可以说是当代最激动人心的行业,激励着无数青年人进入这个行业。但实际上,软件开发工作并不是轰轰
- Android 5.0 Lollipop 新版本中那些值得关注的新功能
- 程序员总结的那些Vue性能优化经验
- MyUnity 4.0 新视频演示-激动人心的新行为功能