文章目录
- 在 Vue2 中,我们在 main.js 通常这样进行初始化挂载: new Vue({ render: h => h(App), components: { App }}).$mount('#app') 在 Vue3 中,调整为这样: import { createApp } from 'vue'import App from './App.vue'const app = createApp(App)app.mount('#app') 为什么发生这样的变化?原因是:如果我们在 Vue2 中创建多个 Vue 实例,那么所有应用(#app)都会共享全局相同的配置。 // 全局共享、相互影响Vue.mixin({ /* ... */})Vue.directive('...', { ...})const app1 = new Vue({ el: '#app-1' })const app2 = new Vue({ el: '#app-2' }) 显然,这并不是我们想要的。在 Vue3 中,你可以创建多个实例,且每个实例都可以拥有单独的配置。 import { createApp } from 'vue'import App1 from './App1.vue'import App2 from './App2.vue'const app1 = createApp(App1)const app2 = createApp(App2)app1.mount('#app-1')app2.mount('#app-2')app1.directive('...', { ...})app2.directive('...', { ...}) 但是,这也并不影响我们设置共享全局配置,我们可以通过如下工厂函数方式实现: import { createApp } from 'vue';import App1 from './App1.vue';import App2 from './App2.vue';const createApp = (Instance) => { const App = createApp(Instance); App.directive('i-am-cool', { inserted: () => { console.log('I am cool!'); }, });}createIdolApp(App1).mount('#app-1');createIdolApp(App2).mount('#app-2');
- 受到 React 的启发,Vue3 引入 Composition API 和 “hook” 函数。有了它,Vue 组件的使用变得更加灵活,也变得更加强大。特别是针对大型应用,以下会给出示例。 以前在 Vue2 中我们是这样写组件的:获取数据,设置数据。 <script>import { fetchResources } from '@/actions'import ResourceDetail from '@/components/ResourceDetail'import ResourceList from '@/components/ResourceList'export default { components: { ResourceDetail, ResourceList, }, data() { return { title: 'Your resources', selectedResource: null, resources: [] } }, async created() { this.resources = await fetchResources() }, computed: { hasResources() { return this.resourceCount > 0 }, activeResource() { return this.selectedResource || (this.hasResources && this.resources[0]) || null }, resourceCount(){ return this.resources.length } }, methods: { selectResource(resource) { this.selectedResource = {...resource} } }}</script> 如果我们使用 composition API,会是这样写: import { ref, onMounted, computed } from 'vue'import { fetchResources } from '@/actions'export default function useResources() { const resources = ref([]) const getResources = async () => resources.value = await fetchResources() onMounted(getResources); const resourceCount = computed(() => resources.value.length) const hasResources = computed(() => resourceCount.value > 0 ) return { resources, resourceCount, hasResources }} 这是一个非常简单的 Composition function 实现了获取 resources 数据的功能。 Composition 函数通常用 use 开头作为关键字,比如此处的 “useResources”,以此区别于普通函数。 下面针对以上代码关键点进行一一释义: 1. ref 会创建一个动态对象。如果你要从 ref 获取原始值,则需要取 “value” 属性,比如 —— resources.value 看以下示例: var a = 7;var b = a;b = 10;// a = 7// b = 10var a = ref(7);var b = a;b.value = 100;// a = 100// b = 100 我们将返回的 resoure 数组设置为 ref。是因为如果数组有新增项或移除项,这样做能在程序中有所表现。 一图胜万言: 2. getResources 函数用于获取数据。 3. onMounted 生命周期函数会在组件添加到 Dom 时调用。 4. computed 属性会随着它的依赖(resources or resourceCount)变化而重新计算。 5. return 最后一步我们将返回 data/function,我们再向组件暴露 useResource hook 函数以供使用。 最终 hook-in: <script>import ResourceDetail from '@/components/ResourceDetail'import ResourceList from '@/components/ResourceList'import useResources from '@/composition/useResources';export default { components: { ResourceDetail, ResourceList, }, data() { return { title: 'Your resources', selectedResource: null } }, setup() { return { ...useResources() // 在 setup 里 } }, computed: { activeResource() { return this.selectedResource || (this.hasResources && this.resources[0]) || null } }, methods: { selectResource(resource) { this.selectedResource = {...resource} } }}</script> 我们再 setup 中进行引用,返回值都可以再通过 this 进行调用。 我们在 computed 和 methods 也能同样进行调用 Composition 函数的返回。 注意:setup 钩子函数执行在组件实例创建(created)之前。 在组件创建前 setup 中 hook 被执行,只要 props 被解析,服务就会以 composition API 作为入口。因为此时当 setup 执行时,组件实例还未生成,没有 this 对象。 神奇吗?我们就这样将获取数据进行封装然后应用到了 hook 调用中。 再写一个对 resources 资源进行搜索过滤的功能: useSearchResource import { ref, computed } from 'vue'export default function useSearchResource(resources) { const searchQuery = ref('') const setSearchQuery = searched => { searchQuery.value = searched } const searchedResources = computed(() => { if (!searchQuery.value) { return resources.value } const lcSearch = searchQuery.value.toLocaleLowerCase(); return resources.value.filter(r => { const title = r?.title.toLocaleLowerCase() return title.includes(lcSearch) }) }) return { setSearchQuery, searchedResources }} useResources export default function useResources() { const resources = ref([]) const getResources = async () => resources.value = await fetchResources() onMounted(getResources); const resourceCount = computed(() => resources.value.length) const hasResources = computed(() => resourceCount.value > 0 ) const { searchedResources, setSearchQuery } = useSearchResources(resources) return { resources: searchedResources, resourceCount, hasResources, setSearchQuery }} 拆解分析: searchQuery包含一个空字符串,使用了 ref,computed searchedResources 可以检测 searchQuery 的变化值。 setSearchQuery是一个简单的赋值给 searchQuery 的函数。 searchedResources会在 searchQuery 或 resources 变化的时候触发。 searchedResources负责过滤 resources。每个 resource 包含一个 title,如果 title 包含 searchedQuery 字符串,那么 resource 就会被加入到 searchedResources 数组中。 最后函数返回setSearchQuery和searchedResourced,再在 useResources 中进行引用及返回。 再看下在组件中使用它到底有多简单: <template>...<input @keyup="handleSearch" type="text" class="form-control" placeholder="Some title" />...</template><script>...methods: { ... handleSearch(e) { this.setSearchQuery(e.target.value) }}...</script> 真有你的! 无论何时执行 setSearchQuery 更改 searchQuery 的值,都将重新执行 searchedResources 将其进行过滤操作并返回结果。 以上便是超重要的新特性 composition API 的实战介绍。
- 在 Vue2 中,data选项不是对象就函数,但是在 Vue3 中将只能是函数。这将被统一成标准。 <script> export default { data() { return { someData: '1234' } } }</script>
- 不会再出现这样的写法: <h1>{{title | capitalized }} </h1> 这样的表达式不是合法有效的 Javascript,在 Vue 中实现这样的写法需要额外的成本。它可以很容易被转化为计算属性或函数。 computed: { capitalizedTitle() { return title[0].toUpperCase + title.slice(1); }}
- 在 Vue2 中我们经常这样包裹我们的根标签: <template> <div> <h1>...</h1> <div class="container">...</div> ... </div></template> 在 Vue3 中将不再有此限制: <template> <h1>...</h1> <div class="container">...</div> ...</template>
- Suspense 是一种特殊的 Vue 组件,用于解析有异步数据的组件。 比如: <Suspense> <template #default> <AsyncComponent> </template> <template #fallback> Loading Data... </template></Suspense> 使用新的 Composition API,setup 可设置异步函数。Suspense 可以展示异步的模板直到 setup 被解析完。 实战代码: <template> Welcome, {{user.name}}</template><script> import { fetchUser } from '@/actions'; export default { async setup() { const user = await fetchUser(); return { user } } }</script> <Suspense> <template #default> <UserPanel/> </template> <template #fallback> Loading user ... </template></Suspense>
- 妇孺皆知,Vue3 的响应式也有很大变化(proxy),不再需要使用 Vue.set 或 Vue.delete。你可以使用简单的原生函数来操作数组或对象。 // in composition APIconst resources = ref([])const addResource = newResource => resources.value.unshift(newResource)const removeResource = atIndex => resources.value.splice(atIndex ,1)const reactiveUser = ref({name: 'Filip'})const changeName = () => reactiveUser.value.name = 'John' 以前则是需要这样: <script>export default { data() { return { resources: [1,2,3], person: { name: 'Filip' } } } methods: { addResource(newResource) { this.resources.unshift(newResource) }, removeResource(atIndex) { this.resources.splice(atIndex ,1) }, changeName(newResource) { this.person.name = 'John' } }}</script> 在 composition API 中,所有的更改都是响应式的。
- 在 Vue3 中,你可以使用多个 v-model,比如这样: <ChildComponent v-model:prop1="prop1" v-model:prop2="prop2"/> 可以实现以下代码逻辑: <ChildComponent :prop1="prop1" @update:prop1="prop1 = $event" :prop2="prop2" @update:prop2="prop2 = $event"/> 看一个具体的例子: <resource-form v-model:title="title" v-model:description="description" v-model:type="type" v-model:link="link" @on-form-submit="submitForm"/> form 组件是这样: <template> <form> <div class="mb-3"> <label htmlFor="title">Title</label> <input :value="title" @input="changeTitle($event.target.value)" type="text" /> </div> <div class="mb-3"> <select :value="type" @change="changeType($event.target.value)"> <option v-for="type in types" :key="type" :value="type">{{type}}</option> </select> </div> <button @click="submitForm" class="btn btn-primary btn-lg btn-block" type="button"> Submit </button> </form></template>export default { props: { title: String, description: String, link: String, type: String, }, data() { return { types: ['blog', 'book', 'video'] } }, methods: { submitForm() { this.$emit('on-form-submit'); }, changeTitle(title) { this.$emit('update:title', title) }, changeType(type) { this.$emit('update:type', type) } ... }} 我们绑定多个 input 值,监听变化,再emit 来更新值父组件的值。注意这里写法的格式。
- 提供如何在当前上下文之外只呈现模板的一部分的方法。 要“teleport”内容,我们需要使用 teleport 组件并把内容包在里面,如下: <teleport to="#teleportContent"> <div class="teleport-body">I am Teleported!</div></teleport> 此内容将被传送到 id 为 teleportContent 的节点中 <div id="teleportContent"></div> 唯一的条件是:在定义传送内容之前,传送到的目标节点需已经存在。 我们可以绑定 id,类,[data-xx]。 <!-- ok --><teleport to="#some-id" /><teleport to=".some-class" /><teleport to="[data-teleport]" /><!-- Wrong --><teleport to="h1" /><teleport to="some-string" />
- Vue2 中我们这样设置及绑定路由: import Vue from 'vue'import VueRouter from 'vue-router';import SomePage1 from './pages/SomePage1';import SomePage2 from './pages/SomePage2';Vue.use(VueRouter);const routes = [ { path: '/', redirect: '/path' }, { path: '/path', name: 'HomePage', component: SomePage1 }, { path: '/some/path', component: SomePage2 }]const router = new VueRouter({ mode: 'history', linkExactActiveClass: 'active', routes})export default router; main.js import router from './router'; new Vue({render: h => h(App), router, components: { App }}).$mount('#app') 在 Vue3 中: import { createRouter, createWebHistory } from 'vue-router'import SomePage1 from './pages/SomePage1'import SomePage2 from './pages/SomePage2'const routes = [ { path: '/', redirect: {name: 'HomePage'}}, { path: '/path', name: 'HomePage', component: SomePage1 }, { path: '/some/path', component: SomePage2 }]const router = createRouter({ history: createWebHistory(), linkExactActiveClass: 'active', routes})export default router; main.js import router from './router'const app = createApp(App)app.use(router)app.mount('#app')
- 此篇总结了 Vue3 的一些主要功能,都是从实战出发来突破 Vue3 的新特性。实践是检验真理的唯一标准!如果想要了解更多,请查阅 官方文档。 我是掘金安东尼: 一名人气前端技术博主(文章 100w+ 阅读量) 终身写作者(INFP 写作人格) 坚持与热爱(简书打卡 1000 日) 我能陪你一起度过漫长技术岁月吗(以梦为马) 觉得不错,给个点赞和关注吧(这是我最大的动力 )b( ̄▽ ̄)d
本篇介绍 10 点如何从实战中学习突破 Vue JS 3 的新特性,细细看完,一定会有收获~
在 Vue2 中,我们在 main.js 通常这样进行初始化挂载:
new Vue({
render: h => h(App),
components: { App }
}).$mount('#app')
在 Vue3 中,调整为这样:
import { createApp } from 'vue'
import App from './App.vue'
const app = createApp(App)
app.mount('#app')
为什么发生这样的变化?原因是:如果我们在 Vue2 中创建多个 Vue 实例,那么所有应用(#app)都会共享全局相同的配置。
// 全局共享、相互影响
Vue.mixin({
/* ... */
})
Vue.directive('...', {
...
})
const app1 = new Vue({ el: '#app-1' })
const app2 = new Vue({ el: '#app-2' })
显然,这并不是我们想要的。在 Vue3 中,你可以创建多个实例,且每个实例都可以拥有单独的配置。
import { createApp } from 'vue'
import App1 from './App1.vue'
import App2 from './App2.vue'
const app1 = createApp(App1)
const app2 = createApp(App2)
app1.mount('#app-1')
app2.mount('#app-2')
app1.directive('...', {
...
})
app2.directive('...', {
...
})
但是,这也并不影响我们设置共享全局配置,我们可以通过如下工厂函数方式实现:
import { createApp } from 'vue';
import App1 from './App1.vue';
import App2 from './App2.vue';
const createApp = (Instance) => {
const App = createApp(Instance);
App.directive('i-am-cool', {
inserted: () => {
console.log('I am cool!');
},
});
}
createIdolApp(App1).mount('#app-1');
createIdolApp(App2).mount('#app-2');
受到 React 的启发,Vue3 引入 Composition API 和 “hook” 函数。有了它,Vue 组件的使用变得更加灵活,也变得更加强大。特别是针对大型应用,以下会给出示例。
以前在 Vue2 中我们是这样写组件的:获取数据,设置数据。
<script>
import { fetchResources } from '@/actions'
import ResourceDetail from '@/components/ResourceDetail'
import ResourceList from '@/components/ResourceList'
export default {
components: {
ResourceDetail,
ResourceList,
},
data() {
return {
title: 'Your resources',
selectedResource: null,
resources: []
}
},
async created() {
this.resources = await fetchResources()
},
computed: {
hasResources() {
return this.resourceCount > 0
},
activeResource() {
return this.selectedResource || (this.hasResources && this.resources[0]) || null
},
resourceCount(){
return this.resources.length
}
},
methods: {
selectResource(resource) {
this.selectedResource = {...resource}
}
}
}
</script>
如果我们使用 composition API,会是这样写:
import { ref, onMounted, computed } from 'vue'
import { fetchResources } from '@/actions'
export default function useResources() {
const resources = ref([])
const getResources = async () => resources.value = await fetchResources()
onMounted(getResources);
const resourceCount = computed(() => resources.value.length)
const hasResources = computed(() => resourceCount.value > 0 )
return {
resources,
resourceCount,
hasResources
}
}
这是一个非常简单的 Composition function 实现了获取 resources 数据的功能。
Composition 函数通常用 use 开头作为关键字,比如此处的 “useResources”,以此区别于普通函数。
下面针对以上代码关键点进行一一释义:
1. ref 会创建一个动态对象。如果你要从 ref 获取原始值,则需要取 “value” 属性,比如 —— resources.value
看以下示例:
var a = 7;
var b = a;
b = 10;
// a = 7
// b = 10
var a = ref(7);
var b = a;
b.value = 100;
// a = 100
// b = 100
我们将返回的 resoure 数组设置为 ref。是因为如果数组有新增项或移除项,这样做能在程序中有所表现。
一图胜万言:

2. getResources 函数用于获取数据。
3. onMounted 生命周期函数会在组件添加到 Dom 时调用。
4. computed 属性会随着它的依赖(resources or resourceCount)变化而重新计算。
5. return 最后一步我们将返回 data/function,我们再向组件暴露 useResource hook 函数以供使用。
最终 hook-in:
<script>
import ResourceDetail from '@/components/ResourceDetail'
import ResourceList from '@/components/ResourceList'
import useResources from '@/composition/useResources';
export default {
components: {
ResourceDetail,
ResourceList,
},
data() {
return {
title: 'Your resources',
selectedResource: null
}
},
setup() {
return {
...useResources() // 在 setup 里
}
},
computed: {
activeResource() {
return this.selectedResource || (this.hasResources && this.resources[0]) || null
}
},
methods: {
selectResource(resource) {
this.selectedResource = {...resource}
}
}
}
</script>
我们再 setup 中进行引用,返回值都可以再通过 this 进行调用。
我们在 computed 和 methods 也能同样进行调用 Composition 函数的返回。
注意:setup 钩子函数执行在组件实例创建(created)之前。
在组件创建前 setup 中 hook 被执行,只要 props 被解析,服务就会以 composition API 作为入口。因为此时当 setup 执行时,组件实例还未生成,没有 this 对象。
神奇吗?我们就这样将获取数据进行封装然后应用到了 hook 调用中。
再写一个对 resources 资源进行搜索过滤的功能:
- useSearchResource
import { ref, computed } from 'vue'
export default function useSearchResource(resources) {
const searchQuery = ref('')
const setSearchQuery = searched => {
searchQuery.value = searched
}
const searchedResources = computed(() => {
if (!searchQuery.value) {
return resources.value
}
const lcSearch = searchQuery.value.toLocaleLowerCase();
return resources.value.filter(r => {
const title = r?.title.toLocaleLowerCase()
return title.includes(lcSearch)
})
})
return {
setSearchQuery,
searchedResources
}
}
- useResources
export default function useResources() {
const resources = ref([])
const getResources = async () => resources.value = await fetchResources()
onMounted(getResources);
const resourceCount = computed(() => resources.value.length)
const hasResources = computed(() => resourceCount.value > 0 )
const { searchedResources, setSearchQuery } = useSearchResources(resources)
return {
resources: searchedResources,
resourceCount,
hasResources,
setSearchQuery
}
}
拆解分析:
- searchQuery包含一个空字符串,使用了 ref,computed searchedResources 可以检测 searchQuery 的变化值。
- setSearchQuery是一个简单的赋值给 searchQuery 的函数。
- searchedResources会在 searchQuery 或 resources 变化的时候触发。
- searchedResources负责过滤 resources。每个 resource 包含一个 title,如果 title 包含 searchedQuery 字符串,那么 resource 就会被加入到 searchedResources 数组中。
- 最后函数返回setSearchQuery和searchedResourced,再在 useResources 中进行引用及返回。
再看下在组件中使用它到底有多简单:
<template>
...
<input
@keyup="handleSearch"
type="text"
class="form-control"
placeholder="Some title" />
...
</template>
<script>
...
methods: {
...
handleSearch(e) {
this.setSearchQuery(e.target.value)
}
}
...
</script>
真有你的! 无论何时执行 setSearchQuery 更改 searchQuery 的值,都将重新执行 searchedResources 将其进行过滤操作并返回结果。
以上便是超重要的新特性 composition API 的实战介绍。
在 Vue2 中,data选项不是对象就函数,但是在 Vue3 中将只能是函数。这将被统一成标准。
<script>
export default {
data() {
return {
someData: '1234'
}
}
}
</script>
不会再出现这样的写法:
<h1>{{title | capitalized }} </h1>
这样的表达式不是合法有效的 Javascript,在 Vue 中实现这样的写法需要额外的成本。它可以很容易被转化为计算属性或函数。
computed: {
capitalizedTitle() {
return title[0].toUpperCase + title.slice(1);
}
}
在 Vue2 中我们经常这样包裹我们的根标签:
<template>
<div>
<h1>...</h1>
<div class="container">...</div>
...
</div>
</template>
在 Vue3 中将不再有此限制:
<template>
<h1>...</h1>
<div class="container">...</div>
...
</template>
Suspense 是一种特殊的 Vue 组件,用于解析有异步数据的组件。
比如:
<Suspense>
<template #default>
<AsyncComponent>
</template>
<template #fallback>
Loading Data...
</template>
</Suspense>
使用新的 Composition API,setup 可设置异步函数。Suspense 可以展示异步的模板直到 setup 被解析完。
实战代码:
<template>
Welcome, {{user.name}}
</template>
<script>
import { fetchUser } from '@/actions';
export default {
async setup() {
const user = await fetchUser();
return { user }
}
}
</script>
<Suspense>
<template #default>
<UserPanel/>
</template>
<template #fallback>
Loading user ...
</template>
</Suspense>
妇孺皆知,Vue3 的响应式也有很大变化(proxy),不再需要使用 Vue.set 或 Vue.delete。你可以使用简单的原生函数来操作数组或对象。
// in composition API
const resources = ref([])
const addResource = newResource => resources.value.unshift(newResource)
const removeResource = atIndex => resources.value.splice(atIndex ,1)
const reactiveUser = ref({name: 'Filip'})
const changeName = () => reactiveUser.value.name = 'John'
以前则是需要这样:
<script>
export default {
data() {
return {
resources: [1,2,3],
person: { name: 'Filip' }
}
}
methods: {
addResource(newResource) {
this.resources.unshift(newResource)
},
removeResource(atIndex) {
this.resources.splice(atIndex ,1)
},
changeName(newResource) {
this.person.name = 'John'
}
}
}
</script>
在 composition API 中,所有的更改都是响应式的。
在 Vue3 中,你可以使用多个 v-model,比如这样:
<ChildComponent v-model:prop1="prop1" v-model:prop2="prop2"/>
可以实现以下代码逻辑:
<ChildComponent
:prop1="prop1"
@update:prop1="prop1 = $event"
:prop2="prop2"
@update:prop2="prop2 = $event"
/>
看一个具体的例子:
<resource-form
v-model:title="title"
v-model:description="description"
v-model:type="type"
v-model:link="link"
@on-form-submit="submitForm"
/>
form 组件是这样:
<template>
<form>
<div class="mb-3">
<label htmlFor="title">Title</label>
<input
:value="title"
@input="changeTitle($event.target.value)"
type="text" />
</div>
<div class="mb-3">
<select
:value="type"
@change="changeType($event.target.value)">
<option
v-for="type in types"
:key="type"
:value="type">{{type}}</option>
</select>
</div>
<button
@click="submitForm"
class="btn btn-primary btn-lg btn-block"
type="button">
Submit
</button>
</form>
</template>
export default {
props: {
title: String,
description: String,
link: String,
type: String,
},
data() {
return {
types: ['blog', 'book', 'video']
}
},
methods: {
submitForm() {
this.$emit('on-form-submit');
},
changeTitle(title) {
this.$emit('update:title', title)
},
changeType(type) {
this.$emit('update:type', type)
}
...
}
}
我们绑定多个 input 值,监听变化,再emit 来更新值父组件的值。注意这里写法的格式。
提供如何在当前上下文之外只呈现模板的一部分的方法。
要“teleport”内容,我们需要使用 teleport 组件并把内容包在里面,如下:
<teleport to="#teleportContent">
<div class="teleport-body">I am Teleported!</div>
</teleport>
此内容将被传送到 id 为 teleportContent 的节点中
<div id="teleportContent"></div>
唯一的条件是:在定义传送内容之前,传送到的目标节点需已经存在。
我们可以绑定 id,类,[data-xx]。
<!-- ok -->
<teleport to="#some-id" />
<teleport to=".some-class" />
<teleport to="[data-teleport]" />
<!-- Wrong -->
<teleport to="h1" />
<teleport to="some-string" />
Vue2 中我们这样设置及绑定路由:
import Vue from 'vue'
import VueRouter from 'vue-router';
import SomePage1 from './pages/SomePage1';
import SomePage2 from './pages/SomePage2';
Vue.use(VueRouter);
const routes = [
{ path: '/', redirect: '/path' },
{ path: '/path', name: 'HomePage', component: SomePage1 },
{ path: '/some/path', component: SomePage2 }
]
const router = new VueRouter({
mode: 'history',
linkExactActiveClass: 'active',
routes
})
export default router;
main.js
import router from './router';
new Vue({render: h => h(App),
router,
components: { App }})
.$mount('#app')
在 Vue3 中:
import { createRouter, createWebHistory } from 'vue-router'
import SomePage1 from './pages/SomePage1'
import SomePage2 from './pages/SomePage2'
const routes = [
{ path: '/', redirect: {name: 'HomePage'}},
{ path: '/path', name: 'HomePage', component: SomePage1 },
{ path: '/some/path', component: SomePage2 }
]
const router = createRouter({
history: createWebHistory(),
linkExactActiveClass: 'active',
routes
})
export default router;
main.js
import router from './router'
const app = createApp(App)
app.use(router)
app.mount('#app')
此篇总结了 Vue3 的一些主要功能,都是从实战出发来突破 Vue3 的新特性。实践是检验真理的唯一标准!如果想要了解更多,请查阅 官方文档。
我是掘金安东尼:
一名人气前端技术博主(文章 100w+ 阅读量)
终身写作者(INFP 写作人格)
坚持与热爱(简书打卡 1000 日)
我能陪你一起度过漫长技术岁月吗(以梦为马)
觉得不错,给个点赞和关注吧(这是我最大的动力 )b( ̄▽ ̄)d