宝剑锋从磨砺出,梅花香自苦寒来。这篇文章主要讲述10 个 Vue3 实战指南,冲就完事了相关的知识,希望能为你提供帮助。
本篇介绍 10 点如何从实战中学习突破 Vue JS 3 的新特性,细细看完,一定会有收获~?
初始化挂载在 Vue2 中,我们在 main.js 通常这样进行初始化挂载:
new Vue(
render: h => h(App),
components:App
).$mount(#app)
在 Vue3 中,调整为这样:
importcreateAppfrom 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 中,你可以创建多个实例,且每个实例都可以拥有单独的配置。
importcreateAppfrom 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(...,
...
)
但是,这也并不影响我们设置共享全局配置,我们可以通过如下工厂函数方式实现:
importcreateAppfrom 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);
Composition API受到 React 的启发,Vue3 引入 Composition API 和 “hook” 函数。有了它,Vue 组件的使用变得更加灵活,也变得更加强大。特别是针对大型应用,以下会给出示例。
以前在 Vue2 中我们是这样写组件的:获取数据,设置数据。
< script>
importfetchResourcesfrom @/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,会是这样写:
importref, onMounted, computedfrom vue
importfetchResourcesfrom @/actions
export default function useResources()
const resources = ref([])
const getResources = async () => resources.value = https://www.songbingjia.com/android/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 = https://www.songbingjia.com/android/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
importref, computedfrom vue
export default function useSearchResource(resources)
const searchQuery = ref()
const setSearchQuery = searched =>
searchQuery.value = https://www.songbingjia.com/android/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 = https://www.songbingjia.com/android/await fetchResources()
onMounted(getResources);
const resourceCount = computed(() => resources.value.length)
const hasResources = computed(() => resourceCount.value > 0 )
constsearchedResources, 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 的实战介绍。
Data 选项在 Vue2 中,data选项不是对象就函数,但是在 Vue3 中将只能是函数。这将被统一成标准。
< script>
export default
data()
return
someData: 1234
< /script>
Filters 被移除不会再出现这样的写法:
< 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>
SuspenseSuspense 是一种特殊的 Vue 组件,用于解析有异步数据的组件。
比如:
< Suspense>
< template #default>
< AsyncComponent>
< /template>
< template #fallback>
Loading Data...
< /template>
< /Suspense>
使用新的 Composition API,setup 可设置异步函数。Suspense 可以展示异步的模板直到 setup 被解析完。
实战代码:
< template>
Welcome, user.name
< /template>
< script>
importfetchUserfrom @/actions;
export default
async setup()
const user = await fetchUser();
returnuser
< /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 中,所有的更改都是响应式的。
多个 v-model在 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="https://www.songbingjia.com/android/title"
@input="changeTitle($event.target.value)"
type="text" />
< /div>
< div class="mb-3">
< select
:value="https://www.songbingjia.com/android/type"
@change="changeType($event.target.value)">
< option
v-for="type in types"
:key="type"
:value="https://www.songbingjia.com/android/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 组件并把内容包在里面,如下:
< 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" />
Vue RouterVue2 中我们这样设置及绑定路由:
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 中:
importcreateRouter, createWebHistoryfrom 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 个 Vue3 实战指南,冲就完事了】
推荐阅读
- JVM运行时数据区了解一下()
- CentOS 7 下 Yum 安装 MySQL 5.7
- Git 程序员必备技能
- 数据结构-二叉树
- 一个好主板对CPU超频的现实意义————一次超频经历(z390ws华硕工作站主板+i7-9700k CPU ,Ubuntu18.04.5系统
- 六石编程学(比垃圾软件更差更可怕的致命软件剧毒软件)
- win10关闭自动更新服务
- Kubernetes安装Metrics数据采集插件
- Jenkins流水线整合钉钉