动态组件的使用(了解)
切换组件案例:
比如我们现在想要实现了一个功能:
- 点击一个tab-bar,切换不同的组件显示;
这个案例我们可以通过两种不同的实现思路来实现:
-
方式一
:通过v-if来判断,显示不同的组件; -
方式二
:动态组件的方式;
方式一代码示例:
<template>
<div class="app">
<div class="tabs">
<template v-for="(item, index) in tabs" :key="item">
<button @click="changeColor(index)" :class="{ active: index === currentIndex }">
{{ item }}
</button>
</template>
</div>
<div class="view">
<!-- 1.第一种做法:v-if进行逻辑判断,决定要显示哪一个组件 -->
<template v-if="currentIndex === 0">
<home></home>
</template>
<template v-else-if="currentIndex ===1">
<about></about>
</template>
<template v-else-if="currentIndex === 2">
<category></category>
</template>
<!-- 最后一个写<template v-else> 也可以,但是不推荐-->
</div>
</div>
</template>
<script>
import About from "./views/About.vue";
import Category from "./views/Category.vue";
import Home from "./views/Home.vue";
export default {
components: {
Home,
Category,
About
},
data() {
return {
tabs: ["home", "about", "category"],
currentIndex: 0
}
},
methods: {
changeColor(index) {
this.currentIndex = index
}
}
}
</script>
动态组件方式实现
动态组件是使用component组件
,通过一个特殊的attribute is
来实现:
<template>
<div class="app">
<div class="tabs">
<template v-for="(tab, index) in tabs" :key="item">
<button @click="changeColor(tab)" :class="{ active: currentTab === tab }">
{{ tab }}
</button>
</template>
</div>
<div class="view">
<!-- 2.第二种做法:动态组件:component -->
<!-- is中的组件:(1)要么是全局注册的组件;(2)要么是局部注册过的组件 -->
<!-- <component is="about"></component> -->
<!-- 动态组件传参(了解),如果是数组类型就和age一样: 监听发送的事件也在component上 -->
<!-- <component name="sevgilid" :age="19" :is="tabs[currentIndex]"></component> -->
<component name="sevgilid" :age="19" :is="currentTab"></component>
</div>
</div>
</template>
在上面的演示中,我们可以看到:
- 首先
使用了component组件,is:组件名
,来展示对应的组件; - 然后绑定事件
点击按钮时获取对应的tab来作为组件名实现动态组件
的展示 - 传递参数和监听子组件事件正常在component组件内使用即可,如在home组件中使用props接收数据:
(动态组件了解即可,后边会讲解路由,使用路由切换更为简洁遍历)
keep-alive(理解)
认识keep-alive
在 Vue.js 中, keep-alive 内置组件可以缓存不活动的组件实例,它通过包裹动态组件来实现缓存
,避免了组件的频繁销毁和重建,从而提升了页面性能
。
我们先对之前的案例中Home组件进行改造:
- 在其中增加了一个按钮,点击可以递增的功能;
比如我们将counter点到10,那么在切换到about再切换回来Home时,状态是否可以保持呢?
- 答案是否定的;
- 这是因为默认情况下,我们在
切换组件后,Home组件会被销毁掉
,再次回来时会重新创建组件
;
但是,在开发中某些情况我们希望继续保持组件的状态,而不是销毁掉,这个时候我们就可以使用一个内置组件: keep-alive
keep-alive的使用
使用 keep-alive 内置组件很简单,只需要将需要缓存的组件用 <KeepAlive> 标签包裹
即可。例如在刚才的案例中:
像上面这样包裹后,我们在点击递增按钮到一定数值后来回切换发现已经数值不会再被重置;
但通过再各个组件内部使用created和unmounted钩子函数发现都没有回调
,这说明里面被包裹的所有组件都被缓存了
;
如果想要精准控制组件的缓存
和对保持keep-alive组件监听有没有切换
该怎么办呢?
(1)精准控制组件缓存
keep-alive有一些属性:
-
include
- string | RegExp |Array。只有名称匹配的组件会被缓存; -
exclude
- string | RegExp | Array。任何名称匹配的组件都不会被缓存; -
max
- number | string。最多可以缓存多少组件实例,一旦达到这个数字,那么缓存组件中最近没有被访问的实例会被销毁;
include和exclude prop允许组件有条件地缓存:
- 二者都可以
用逗号分隔字符串、正则表达式或一个数组
来表示; - 匹配首先检查组件自身的
name选项
;
使用示例:
Home组件中:
<template>
<h2>home组件</h2>
<h2>计数器:{{ counter }}</h2>
<button @click="counter++">+1</button>
</template>
<script>
export default {
// 此处的name提供给Keep-Alive中的include属性使用的
name: "home",
data() {
return {
counter: 0
}
}
}
</script>
App根组件中:
(2)缓存组件的生命周期
对于缓存的组件来说,再次进入时,我们是不会执行created或者mounted
等生命周期函数的:
- 但是有时候我们确实希望监听到何时重新进入到了组件,何时离开了组件;
- 这个时候我们可以使用
activated和deactivated
这两个生命周期钩子函数来监听;
需要注意的是,由于 keep-alive 是内置组件,所以不支持动态组件模式下的异步组件
:
- 因为异步组件的加载是异步的, keep-alive 无法知道异步组件何时完成加载,从而无法对其进行缓存;
- 如果
需要缓存异步组件
,可以使用工厂函数与异步组件创建一个高阶组件
,再将其包裹在 keep-alive 内;
异步组件的使用
在学习异步组件使用前,先来了解一下webpack的分包处理,因为异步组件打包时会进行分包的处理
webpack分包处理(了解)
默认的打包过程:
- 默认情况下,在构建整个组件树的过程中,因为组件和组件之间是
通过模块化直接依赖的
,那么webpack在打包时就会将组件模块打包到一起
(比如一个app.js文件中); - 这个时候随着
项目的不断庞大,app.js文件的内容过大
,会造成首屏的渲染速度变慢
;
打包时,代码的分包:
- 所以,对于一些
不需要立即使用的组件
,我们可以单独对它们进行拆分
,拆分成一些小的代码块chunk.js
; - 这些chunk.js会在需要时
从服务器加载下来
,并且运行代码
,显示对应的内容;
那么webpack中如何可以对代码进行分包呢?
Vue中实现异步组件
如果我们的项目过大了,对于某些组件
我们希望通过异步的方式来进行加载
(目的是可以对其进行分包处理),那么Vue中给我们提供了一个函数: defineAsyncComponent
defineAsyncComponent接受两种类型的参数:
-
类型一
:工厂函数,该工厂函数需要返回一个Promise对象; -
类型二
:接受一个对象类型,对异步函数进行配置;
工厂函数类型一的写法:
<script>
import { defineAsyncComponent } from "vue";
// import Category from "./views/Category.vue";
// 异步组件写法一(了解):工厂函数:返回的是一个promise对象
const AsyncCategory = defineAsyncComponent(() => import("./views/Category.vue"))
export default {
components: {
Home,
// 异步组件:打包的时候会进行分包处理
Category: AsyncCategory,
}
}
</script>
异步组件写法二(了解):
(异步组件的使用仅作了解即可,因为实际开发中路由懒加载的写法会更多)
组件的v-model
前面我们在input
中可以使用v-model
来完成双向绑定:
- 这个时候往往会非常方便,因为v-model默认帮助我们完成了两件事;
-
v-bind:value的数据绑定
和@input的事件监听
;
如果我们现在封装了一个组件,其他地方在使用这个组件时,是否也可以使用v-model来同时完成这两个功能呢?
- 也是可以的,vue也支持
在组件上使用v-model
;
当我们在组件上使用的时候,等价于如下的操作:
- 我们会发现
和input元素不同的只是属性的名称和事件触发的名称
而已;
那么,为了我们的counter组件可以正常的工作,这个组件内的click必须:
- 将其value attribute绑定到一个名叫
modelValue 的prop
上; - 在其click事件被触发时,将新的值通过
自定义的update:modelValue事件
抛出;
Counter组件代码如下:
<template>
<h2>counter:{{ modelValue }}</h2>
<button @click="changeCounter">修改counter</button>
</template>
<script>
export default{
props:{
modelValue:{
type:Number,
default:0
}
},
emits:["update:modelValue"],
methods:{
changeCounter(){
// this.$emit("update:modelValue", 1000)
this.$emit("update:modelValue", 999)
}
}
}
</script>
v-model默认绑定的参数名和事件名是modelValue;
此处的@click绑定click事件;换成@input则表示的是绑定的是input事件,当input表有input输入时触发事件
绑定多个属性(高级用法):
我们现在通过v-model是直接绑定了一个属性,如果我们希望绑定多个属性呢?
- 也就是我们希望在
一个组件上使用多个v-model
是否可以实现呢? - 我们知道,
默认情况
下的v-model其实是绑定了modelValue属性
和@update:modelValue
的事件; - 如果我们希望绑定更多,可以
给v-model传入一个参数
,那么这个参数的名称就是我们绑定属性的名称
;
默认绑定一个属性和绑定多个自定义属性的代码对比:
(1)子组件部分:
(2)父组件部分:
总结:
- v-model可以绑定多个自定义属性
- v-model在组件上的应用实际上是将一个代表数据的属性和一个代表数据修改的事件绑定到了一起,使得在父子组件之间进行数据通信变得简单和直观。 比如v-model:title相当于做了两件事:
绑定了title属性;
监听了@update:title的事件;
组件的混入Mixin(了解)
Mixin主要在Vue2中使用,在Vue3中基本不用
虽然mixin在Vue中给我们带来了很多的代码复用和逻辑复用的好处,但是也存在一些弊端:
- 命名冲突:mixin可以将通用的逻辑和代码分离出来,但是它也可能导致命名冲突。如果多个Mixin中有同名的选项,或者Mixin中的选项与组件中的选项重名,就会导致选项的合并冲突。而且如果有多个mixin混合使用可能会更加复杂,因为难以判断选项的来源和优先级。为了避免命名冲突,我们需要在编写Mixin时格外小心,同时在开发过程中也需要保持清晰的组织结构。
- 耦合性高:mixin虽然可以让我们方便地复用代码和逻辑,但是也可能导致组件与Mixin之间的耦合性增加。因为mixin需要了解组件的内部实现细节和数据结构,从而才能正确地暴露需要的数据和方法。这就导致了Mixin与组件之间的耦合度会比较高,一旦需要修改Mixins,可能会对组件产生意外的影响。
在Vue 3中,Composition API的出现主要是为了解决mixin中所存在的问题和局限性。Composition API可以更好地实现逻辑复用,并且可以更好地组织组件代码。通过Composition API,我们可以将逻辑功能组织成一组Hooks(钩子函数)并进行复用。
目前我们是使用组件化的方式在开发整个Vue的应用程序,但是组件和组件之间有时候会存在相同的代码逻辑,我们希望对相同的代码逻辑进行抽取。
在Vue2和Vue3中都支持的一种方式就是使用Mixin来完成:
- Mixin提供了一种非常灵活的方式,来
分发Vue组件中的可复用功能
; - 一个Mixin对象可以包含
任何组件选项
; - 当组件使用Mixin对象时,所有
Mixin对象的选项将被混合进入该组件本身的选项
中;
(1)基本使用:
Vue中的Mixin分为全局Mixin与组件级Mixin。下面我们以组件级Mixin为例讲解其基本使用方法。
首先,定义一个名为myMixin的mixin:
var myMixin = {
data: function () {
return {
message: 'Hello world!'
}
},
methods: {
greet: function () {
console.log(this.message)
}
}
}
然后,可以在Vue组件中使用这个mixin了。我们需要在组件中使用mixins选项来将Mixin混入(mixin)到组件中。
Vue.component('my-component', {
mixins: [myMixin],
template: '<div>{{ message }}</div>',
created: function () {
this.greet() // 执行myMixin中的方法greet
}
})
在上面的代码中,我们将myMixin混入到了my-component组件中。所以在my-component组件中,我们可以使用myMixin中定义的message实例属性和greet方法。
(2)mixin的合并规则
当多个Mixin共同作用于一个组件的时候,Vue中的Mixin会按照一定的规则进行合并;如果多个Mixin有相同的选项
,这些选项会被合并到一个选项
中,合并规则如下:
- 数据对象:在组件和Mixin中定义的数据对象会被合并成一个对象。当组件与Mixin同名的属性冲突时,以组件数据为准。
- 生命周期钩子函数:合并两个Mixin中的同名生命周期钩子时,都会被调用。Mixin的钩子总是在组件的钩子之前被调用。
- 方法:Mixin中的方法会被合并到组件中,并且优先级高于组件中的同名方法。
- 其他选项:如
props、computed
等,都会以和方法相同的方式进行合并。
(3)全局混入mixin
全局混入Mixin的主要作用是向所有的Vue实例添加一些全局的逻辑或方法。这样一来,我们就可以在所有Vue实例内使用这些全局的逻辑或方法。
比如,我们可以在全局Mixin中添加一个$myMethod
方法:
Vue.mixin({
methods: {
$myMethod: function () {
console.log('This is a global method.')
}
}
})
通过上面的代码,我们就向所有的Vue实例中添加了一个全局方法$myMethod
,可以在任何Vue组件内使用。文章来源:https://www.toymoban.com/news/detail-478790.html
new Vue({
created: function () {
this.$myMethod() //这里就可以调用到已经全局混合的$myMethod方法了
}
})
总结:文章来源地址https://www.toymoban.com/news/detail-478790.html
- 全局的Mixin可以使用应用app的方法mixin来完成注册;
- 一旦注册,那么全局混入的选项将会影响每一个组件;
到了这里,关于【vue3】10-vue组件化额外知识补充(下)-动态组件-组件缓存-v-model在组件上的应用的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!