• Vue 之 异步/动态组件 && keep-alive && v-model


    hello ,因为内容比较多且简单,所以都凑在一起写啦~

     

    目录

    一、异步组件 

    webpack的打包过程

    defineAsyncComponent异步组件函数

    类型一 : 工厂函数,该工厂函数返回一个promise对象 ( 常用 )

    类型二 : 接受一个对象类型,对异步函数进行配置( 不常用 )

     二、Suspense组件 

    三、动态组件

    举个栗子

    方式一 : 通过v-if || v-show

    方式二 : 使用动态组件

    四、keep-alive 

    举个栗子

    这里涉及两个生命周期 activated || deactivated

    五、生命周期

    六、v-model 

    1.元素上使用

    2.组件上使用 

    父组件

    子组件

    效果 

    初步优化 

    再次优化

    效果

    七、写在最后


    、异步组件 

    为什么要使用异步组件,首先我们要了解另一个概念

    webpack的打包过程

    • 默认情况下,因为组件和组件之间是通过模块化直接依赖的,所以webpack打包时会将组件模块打包到一起,比如(app.js文件中)
    • 对于一些不需要立即使用的组件,我们可以对它们进行拆分,拆成小的代码块chunk.js
    • 这些chunk.js会在需要的时候才会去请求服务器加载,然后运行

    webpack是如何进行分包的呢,是使用import('  ')函数

    如果我们的项目过大,对于某些组件我们希望通过异步的方式来进行加载( 目的是进行分包处理 ),在vue中提供了一个函数,

    defineAsyncComponent异步组件函数

    defineAsyncComponent接受两种类型的参数

    类型一 : 工厂函数,该工厂函数返回一个promise对象 ( 常用 )

    1. // 导入vue中的方法
    2. import { defineAsyncComponent } from 'vue';
    3. // 普通组件
    4. import profile from './pages/profile.vue';
    5. // 异步组件
    6. const profile = defineAsyncComponent(() => import('./pages/profile.vue'));

    类型二 : 接受一个对象类型,对异步函数进行配置( 不常用 )

    1. const profile = defineAsyncComponent({
    2. // 工厂函数
    3. loader: () => import('./pages/profile.vue'),
    4. // 加载过程中显示的组件Loading,用来占位的,用普通组件的方式导入即可
    5. loadingComponent: Loading,
    6. // 加载失败时显示的组件Error
    7. errorComponent: Error,
    8. // 在显示loadingComponent组件之前的延迟,等待多长时间 | 默认值200ms
    9. delay: 2000,
    10. // 如果提供了timerout,并且加载组件时超过了设定值,将显示错误组件,默认值 infinity == 永不超时 ms
    11. timeout: 3000,
    12. // 定义组件是否可挂起 默认true
    13. suspensible: true,
    14. /**
    15. * err : 错误信息
    16. * retry : 函数,调用retry尝试重新加载
    17. * fail : 函数,指示加载程序结束退出
    18. * attempts : 记录尝试的次数
    19. */
    20. onError(err, retry, fail, attempts) {
    21. if (err.message.match(/fetch/) && attempts <= 3) {
    22. // 请求发生错误时重试,最多尝试3次
    23. retry();
    24. } else {
    25. // 像promise的resove|reject一样,必须调用一个,否则就卡在这里了
    26. fail();
    27. }
    28. }
    29. });

    tip : 异步组件在路由中使用的很多 


     二、Suspense组件 

    Suspense是vue3正在新加的组件,正在实验的一个特性,可能以后都会存在,也可能会不存在~,可以和异步组件结合来使用

    Suspense是一个内置的全局组件,该组件有两个插槽

    • default : 如果default可以显示,那么就显示default的内容
    • fallback : 如果default无法显示,那么会显示fallback插槽的内容
    1. <suspense>
    2. <template #default>
    3. <profile />
    4. </template>
    5. <template #fallback>
    6. <loading />
    7. </template>
    8. </suspense>

    三、动态组件

    举个栗子

    比如我们现在想要实现一个功能,点击一个tab-bar,切换不同的组件显示

    方式一 : 通过v-if || v-show

    1.创建 home, about, profile 三个测试组件

    2.引用并写如下代码

    1. <template>
    2. <div class="hello-world-layout">
    3. <ul class="nav">
    4. <li class="item" v-for="item in tabArr" :key="item" @click="itemClick(item)" :class="{ active: currentTab === item }">{{ item }}</li>
    5. </ul>
    6. <template v-if="currentTab === 'home'">
    7. <home />
    8. </template>
    9. <template v-if="currentTab === 'about'">
    10. <about />
    11. </template>
    12. <template v-if="currentTab === 'profile'">
    13. <profile />
    14. </template>
    15. </div>
    16. </template>
    17. <script>
    18. // 引用测试组件
    19. import home from './pages/home.vue';
    20. import about from './pages/about.vue';
    21. import profile from './pages/profile.vue';
    22. export default {
    23. components: { home, about, profile },
    24. name: 'HelloWorld',
    25. data() {
    26. return {
    27. tabArr: ['home', 'about', 'profile'],
    28. // 指定默认组件
    29. currentTab: 'home'
    30. };
    31. },
    32. methods: {
    33. // 点击切换
    34. itemClick(item) {
    35. this.currentTab = item;
    36. }
    37. }
    38. };
    39. </script>
    40. <style lang="scss" scoped>
    41. .hello-world-layout {
    42. .nav {
    43. padding: 0;
    44. margin: 0;
    45. width: 100%;
    46. display: flex;
    47. align-items: center;
    48. list-style: none;
    49. margin-bottom: 100px;
    50. }
    51. .item {
    52. flex: 1;
    53. height: 30px;
    54. line-height: 30px;
    55. background-color: skyblue;
    56. &.active {
    57. background-color: red;
    58. color: #fff;
    59. }
    60. }
    61. }
    62. </style>

    3.效果

    方式二 : 使用动态组件

    概念 : 动态组件是使用component组件,通过一个特殊的attribute is 来实现

    is : 后面可以跟全局注册的组件名,也可以跟局部注册的组件名(不区分大小写)

    tip : 所以,代码直接可以简化成这个样子!是不是很nice 


    四、keep-alive 

    一般会和 路由一起使用,其他地方也可用~

    举个栗子

    在上面所创建的about.vue文件中我们写如下代码,就是增加一个计数器 

    1. <template>
    2. <div>about组件</div>
    3. {{ count }}
    4. <button class="addClick" @click="count++">+1</button>
    5. </template>
    6. <script>
    7. export default {
    8. data() {
    9. return {
    10. count: 0
    11. };
    12. }
    13. };
    14. </script>
    15. <style lang="scss" scoped></style>

    但是,不知道你们有没有思考一个问题,如果这个时候我们切换为home组件,然后再跳转回来,那么记得数还回存在吗~答案是否定,肯定没有了,因为动态组件内部是使用v-if来进行判定的

    如果想保留的话,就要使用keep-alive了

    keep-alive : 在开发中某些情况我们希望继续保持组件的状态,而不是销毁掉,这个时候可以使用

    1. <keep-alive>
    2. <component :is="currentTab" />
    3. </keep-alive>

    keep-alive使用很简单,有几个常用的属性 

    这个根据的是name属性 

    这里涉及两个生命周期 activated || deactivated

    对于缓存的组件来说,再次进入该组件,不会执行created或mounted等生命周期的,那么问题来了,如果我们确实希望监听到何时重新进入了该组件,何时离开了该组件

    activated : 进入时触发

    deactivated : 离开时触发

    tip : 第一次进入该组件时,created、mounted、activated会依次执行


    五、生命周期


     六、v-model 

    1.元素上使用

    <input type="text" v-model="count" placeholder="请输入..." />

    相当于 

    1. <!-- 相当于绑定value值,监听input方法改变值 -->
    2. <input type="text" :value="count" @input="count = $event.target.value" />

    整体代码 

    1. <template>
    2. <div>about组件</div>
    3. <input type="text" v-model="count" placeholder="请输入..." />
    4. <div>{{ count }}</div>
    5. </template>
    6. <script>
    7. export default {
    8. name: 'about',
    9. data() {
    10. return {
    11. count: ''
    12. };
    13. }
    14. };
    15. </script>
    16. <style lang="scss" scoped></style>

    2.组件上使用 

    父组件

    <home v-model="message" />

    相当于

    1. <!-- 相当于传modelValue属性值过去,监听update:modelValue方法更改值 -->
    2. <home :modelValue="message" @update:modelValue="message = $event" />

    整体代码 

    1. <template>
    2. <div class="hello-world-layout">
    3. <h1>父组件的message : {{ message }}</h1>
    4. <!-- 父组件使用v-model传值给子组件 -->
    5. <home v-model="message" />
    6. </div>
    7. </template>
    8. <script>
    9. import home from './pages/home.vue';
    10. export default {
    11. components: { home },
    12. name: 'HelloWorld',
    13. data() {
    14. return {
    15. message: '初始化值'
    16. };
    17. },
    18. methods: {}
    19. };
    20. </script>

    子组件

    1. <template>
    2. <div>
    3. <button @click="btnClick">子组件的按钮</button>
    4. <h3>子组件的message : {{ modelValue }}</h3>
    5. <input type="text" :value="modelValue" @input="inputHandle" />
    6. </div>
    7. </template>
    8. <script>
    9. export default {
    10. props: {
    11. // 接受的参数,默认需要这么写
    12. modelValue: {
    13. type: String,
    14. default: ''
    15. }
    16. },
    17. methods: {
    18. btnClick() {
    19. // 发射的事件,默认是这样写
    20. this.$emit('update:modelValue', '我更改了');
    21. },
    22. inputHandle(event) {
    23. this.$emit('update:modelValue', event.target.value);
    24. }
    25. }
    26. };
    27. </script>

    效果 

     

    初步优化 

    如果要实现双向绑定,子组件可以通过computed来实现

    1. <template>
    2. <div>
    3. <h3>子组件的message : {{ sonValue }}</h3>
    4. <input type="text" v-model="sonValue" />
    5. </div>
    6. </template>
    7. <script>
    8. export default {
    9. props: {
    10. // 接受的参数,默认需要这么写
    11. modelValue: {
    12. type: String,
    13. default: ''
    14. }
    15. },
    16. computed: {
    17. // 使用计算属性
    18. sonValue: {
    19. set(value) {
    20. // 更改的时候,发射事件让父组件更改
    21. this.$emit('update:modelValue', value);
    22. },
    23. get() {
    24. // 从父组件获取值
    25. return this.modelValue;
    26. }
    27. }
    28. }
    29. };
    30. </script>

    再次优化

    • 可以更改名字, v-model:message
    • 传递多个属性值

    父组件 

    1. <template>
    2. <div class="hello-world-layout">
    3. <h1>父组件的message : {{ message }}</h1>
    4. <!-- 更改默认值,传递多个参数-->
    5. <home v-model:message="message" v-model:title="title" />
    6. <h1>父组件的title : {{ title }}</h1>
    7. </div>
    8. </template>
    9. <script>
    10. import home from './pages/home.vue';
    11. export default {
    12. components: { home },
    13. name: 'HelloWorld',
    14. data() {
    15. return {
    16. message: '初始化值',
    17. title: '标题一'
    18. };
    19. },
    20. methods: {}
    21. };
    22. </script>

    子组件 

    1. <template>
    2. <div>
    3. <h3>子组件的message : {{ sonMessage }}</h3>
    4. <input type="text" v-model="sonMessage" />
    5. </div>
    6. <hr />
    7. <div>
    8. <input type="text" v-model="sonTitle" />
    9. <h3>子组件的title : {{ sonTitle }}</h3>
    10. </div>
    11. </template>
    12. <script>
    13. export default {
    14. props: {
    15. // 因为更改了默认值,参数得这么写了
    16. message: {
    17. type: String,
    18. default: ''
    19. },
    20. title: {
    21. type: String,
    22. default: ''
    23. }
    24. },
    25. computed: {
    26. // 使用计算属性
    27. sonMessage: {
    28. set(value) {
    29. // 更改的时候,发射事件让父组件更改
    30. this.$emit('update:message', value);
    31. },
    32. get() {
    33. // 从父组件获取值
    34. return this.message;
    35. }
    36. },
    37. sonTitle: {
    38. set(value) {
    39. // 更改的时候,发射事件让父组件更改
    40. this.$emit('update:title', value);
    41. },
    42. get() {
    43. // 从父组件获取值
    44. return this.title;
    45. }
    46. }
    47. }
    48. };
    49. </script>

    效果


    七、写在最后

    🌟 🌟  谢谢聪明美丽帅气的你看到我的文章,支持一下可否

    👍 👍  您的点赞,就是我动力的源泉,让我跨过彼岸

    ⭐️ ⭐️  您的收藏,就是我期待的远方,让我目标坚定

    ✏️ ✏️  您的评论,就是我心灵的医生,让我完善己身
     

  • 相关阅读:
    Fasterkv Epoch 保护框架
    【Mybatis】3 的操作类型对象
    缓冲区的奥秘:解析数据交错的魔法
    选择最适合您的Bug管理软件:市场比较与推荐
    备战秋招--redis篇
    Java 中的 ==, equals 与 hashCode 的区别与联系
    关于vant 的tabbar功能
    如何入门学习黑客技术?如何选择编程语言?如何选择适合黑客的操作系统?
    学院网站分析
    用 TripletLoss 优化bert ranking
  • 原文地址:https://blog.csdn.net/a15297701931/article/details/120888881