Vue3+TS系统学习八 - 组件化知识补充(上)

简介: 组件化知识补充(上)

一. 动态组件


比如我们现在想要实现了一个功能:

  • 点击一个tab-bar,切换不同的组件显示;

image.png                                                                                        

             案例截图

这个案例我们可以通过两种不同的实现思路来实现:

  • 方式一:通过v-if来判断,显示不同的组件;
  • 方式二:动态组件的方式;


1.1. v-if显示不同组件


我们可以先通过v-if来判断显示不同的组件,这个可以使用我们之前讲过的知识来实现:

<template>
  <div>
    <button v-for="tab in tabs" 
            :key="tab"
            :class="{active: currentTab === tab}"
            @click="tabClick(tab)">
      {{tab}}
    </button>
    <template v-if="currentTab === 'home'">
      <home></home>
    </template>
    <template v-else-if="currentTab === 'about'">
      <about></about>
    </template>
    <template v-else>
      <category></category>
    </template>
  </div>
</template>
<script>
  import Home from "./pages/Home.vue";
  import About from "./pages/About.vue";
  import Category from "./pages/Category.vue";
  export default {
    components: {
      Home, About, Category
    },
    data() {
      return {
        tabs: ["home", "about", "category"],
        currentTab: "home"
      }
    },
    methods: {
      tabClick(tab) {
        this.currentTab = tab;
      }
    }
  }
</script>
<style scoped>
  .active {
    color: red;
  }
</style>

这里不再给出过多解释,都是之前讲过的内容。


1.2. 动态组件的实现


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

<template>
  <div>
    <button v-for="tab in tabs" 
            :key="tab"
            :class="{active: currentTab === tab}"
            @click="tabClick(tab)">
      {{tab}}
    </button>
    <component :is="currentTab"></component>
  </div>
</template>

这个currentTab的值需要是什么内容呢?

  • 可以是通过component函数注册的组件;
  • 在一个组件对象的components对象中注册的组件;


1.3. 动态组件的传值


如果是动态组件我们可以给它们传值和监听事件吗?

  • 也是一样的;
  • 只是我们需要将属性和监听事件放到component上来使用;

App.vue的代码如下:

<template>
  <div>
    <button v-for="tab in tabs" 
            :key="tab"
            :class="{active: currentTab === tab}"
            @click="tabClick(tab)">
      {{tab}}
    </button>
    <component name="why" 
               :age="18" 
               @pageClick="pageClick" 
               :is="currentTab"/>
  </div>
</template>
<script>
  import Home from "./pages/Home.vue";
  import About from "./pages/About.vue";
  import Category from "./pages/Category.vue";
  export default {
    components: {
      Home, About, Category
    },
    data() {
      return {
        tabs: ["home", "about", "category"],
        currentTab: "home"
      }
    },
    methods: {
      tabClick(tab) {
        this.currentTab = tab;
      },
      pageClick(payload) {
        console.log("pageClick", payload);
      }
    }
  }
</script>
<style scoped>
  .active {
    color: red;
  }
</style>

Home.vue中的代码如下:

<template>
  <div @click="pageClick">
    Home组件: {{name}}-{{age}}
  </div>
</template>
<script>
  export default {
    props: {
      name: String,
      age: Number
    },
    emits: ["pageClick"],
    methods: {
      pageClick() {
        this.$emit("pageClick", "Home组件");
      }
    }
  }
</script>


1.4. keep-alive使用


1.4.1. 认识keep-alive


我们先对之前的案例中About组件进行改造:

  • 在其中增加了一个按钮,点击可以递增的功能;
<template>
  <div>
    About组件
    <button @click="counter++">{{counter}}</button>
  </div>
</template>
<script>
  export default {
    data() {
      return {
        counter: 0
      }
    }
  }
</script>

比如我们将counter点到10,那么在切换到home再切换回来about时,状态是否可以保持呢?

  • 答案是否定的;
  • 这是因为默认情况下,我们在切换组件后,about组件会被销毁掉,再次回来时会重新创建组件;

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

<keep-alive>
  <component name="why" 
             :age="18" 
             @pageClick="pageClick" 
             :is="currentTab"/>
</keep-alive>


1.4.2. keep-alive属性


keep-alive有一些属性

  • include - string | RegExp | Array。只有名称匹配的组件会被缓存;
  • exclude - string | RegExp | Array。任何名称匹配的组件都不会被缓存;
  • max - number | string。最多可以缓存多少组件实例,一旦达到这个数字,那么缓存组件中最近没有被访问的实例会被销毁;

includeexclude prop 允许组件有条件地缓存:

  • 二者都可以用逗号分隔字符串、正则表达式或一个数组来表示;
  • 匹配首先检查组件自身的 name 选项;
  • 如果 name 选项不可用,则匹配它的局部注册名称 (父组件 components 选项的键值);
<!-- 逗号分隔字符串 -->
<keep-alive include="a,b">
  <component :is="view"></component>
</keep-alive>
<!-- regex (使用 `v-bind`) -->
<keep-alive :include="/a|b/">
  <component :is="view"></component>
</keep-alive>
<!-- Array (使用 `v-bind`) -->
<keep-alive :include="['a', 'b']">
  <component :is="view"></component>
</keep-alive>


1.4.3. 缓存的生命周期


对于生命周期的知识下面的四有讲解,因为这部分知识和keep-alive联系紧密,所以放到了这里。

大家可以等学习了生命周期后,再回头看这部分的内容。

对于缓存的组件来说,再次进入时,我们是不会执行created或者mounted等生命周期函数的:

  • 但是有时候我们确实希望监听到何时重新进入到了组件,何时离开了组件;
  • 这个时候我们可以使用activateddeactivated 这两个生命周期钩子函数来监听;
<template>
  <div>
    About组件
    <button @click="counter++">{{counter}}</button>
  </div>
</template>
<script>
  export default {
    name: "about",
    data() {
      return {
        counter: 0
      }
    },
    // 当重新进入活跃状态时会回调
    activated() {
      console.log("about activated")
    },
    // 当离开活跃状态时会回调
    deactivated() {
      console.log("about deactivated")
    }
  }
</script>


二. 异步组件


2.1. webpack的代码分包


默认的打包过程:

  • 默认情况下,在构建整个组件树的过程中,因为组件和组件之间是通过模块化直接依赖的,那么webpack在打包时就会将组件模块打包到一起(比如一个app.js文件中);
  • 这个时候随着项目的不断庞大,app.js文件的内容过大,会造成首屏的渲染速度变慢;

打包时,代码的分包:

  • 所以,对于一些不需要立即使用的组件,我们可以单独对它们进行拆分,拆分成一些小的代码块chunk.js;
  • 这些chunk.js会在需要时从服务器加载下来,并且运行代码,显示对应的内容;

那么webpack中如何可以对代码进行分包呢?

默认情况下,我们直接使用import来依赖一个模块时,是不会进行分包的:

import {sum} from './utils/math';
console.log(sum(20, 30));

如果我们希望进行分包,那么可以使用import函数:

import("./utils/math").then(({ sum }) => {
  console.log(sum(20, 30));
});

image.png                                            import打包后的效果


2.2. vue中实现异步组件


如果我们的项目过大了,对于某些组件我们希望通过异步的方式来进行加载(目的是可以对其进行分包处理),那么Vue中给我们提供了一个函数:defineAsyncComponent

defineAsyncComponent接受两种类型的参数:

  • 类型一:工厂函数,该工厂函数需要返回一个Promise对象;
  • 类型二:接受一个对象类型,对异步函数进行配置;

工厂函数类型一的写法:

<script>
  import { defineAsyncComponent } from 'vue';
  const AsyncHome = defineAsyncComponent(() => import("./AsyncHome.vue"));
  export default {
    components: {
      AsyncHome
    }
  }
</script>

对象类型类型二的写法:

<script>
  import { defineAsyncComponent } from "vue";
  // const AsyncHome = defineAsyncComponent(() => import("./AsyncHome.vue"));
  import Loading from "./Loading.vue";
  import Error from "./Error.vue";
  const AsyncHome = defineAsyncComponent({
    // 工厂函数
    loader: () => import("./AsyncHome.vue"),
    // 加载过程中显示的组件
    loadingComponent: Loading,
    // 加载失败时显示的组件
    errorComponent: Error,
    // 在显示 loadingComponent 之前的延迟 | 默认值:200(单位 ms)
    delay: 200,
    // 如果提供了 timeout ,并且加载组件的时间超过了设定值,将显示错误组件
    // 默认值:Infinity(即永不超时,单位 ms)
    timeout: 3000,
    // 定义组件是否可挂起 | 默认值:true
    suspensible: false,
    /**
     *
     * @param {*} error 错误信息对象
     * @param {*} retry 一个函数,用于指示当 promise 加载器 reject 时,加载器是否应该重试
     * @param {*} fail  一个函数,指示加载程序结束退出
     * @param {*} attempts 允许的最大重试次数
     */
    onError(error, retry, fail, attempts) {
      if (error.message.match(/fetch/) && attempts <= 3) {
        // 请求发生错误时重试,最多可尝试 3 次
        retry();
      } else {
        // 注意,retry/fail 就像 promise 的 resolve/reject 一样:
        // 必须调用其中一个才能继续错误处理。
        fail();
      }
    },
  });
  export default {
    components: {
      AsyncHome,
    },
  };
</script>


2.3. 异步组件和Suspense


注意,目前(2021-06-08)Suspense显示的是一个实验性的特性,API随时可能会修改。

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

  • default:如果default可以显示,那么显示default的内容;
  • fallback:如果default无法显示,那么会显示fallback插槽的内容;
<template>
  <div>
    <suspense>
      <template #default>
        <async-home></async-home>
      </template>
      <template #fallback>
        <loading/>
      </template>
    </suspense>
  </div>
</template>
相关文章
|
8天前
|
前端开发 JavaScript Java
【03】Java+若依+vue.js技术栈实现钱包积分管理系统项目-若依框架搭建-服务端-后台管理-整体搭建-优雅草卓伊凡商业项目实战
【03】Java+若依+vue.js技术栈实现钱包积分管理系统项目-若依框架搭建-服务端-后台管理-整体搭建-优雅草卓伊凡商业项目实战
53 13
【03】Java+若依+vue.js技术栈实现钱包积分管理系统项目-若依框架搭建-服务端-后台管理-整体搭建-优雅草卓伊凡商业项目实战
|
9天前
|
人工智能 JavaScript 关系型数据库
【02】Java+若依+vue.js技术栈实现钱包积分管理系统项目-商业级电玩城积分系统商业项目实战-ui设计图figmaUI设计准备-figma汉化插件-mysql数据库设计-优雅草卓伊凡商业项目实战
【02】Java+若依+vue.js技术栈实现钱包积分管理系统项目-商业级电玩城积分系统商业项目实战-ui设计图figmaUI设计准备-figma汉化插件-mysql数据库设计-优雅草卓伊凡商业项目实战
55 14
【02】Java+若依+vue.js技术栈实现钱包积分管理系统项目-商业级电玩城积分系统商业项目实战-ui设计图figmaUI设计准备-figma汉化插件-mysql数据库设计-优雅草卓伊凡商业项目实战
|
7天前
|
SQL JavaScript 安全
【04】Java+若依+vue.js技术栈实现钱包积分管理系统项目-若依框架二次开发准备工作-以及建立初步后端目录菜单列-优雅草卓伊凡商业项目实战
【04】Java+若依+vue.js技术栈实现钱包积分管理系统项目-若依框架二次开发准备工作-以及建立初步后端目录菜单列-优雅草卓伊凡商业项目实战
44 11
【04】Java+若依+vue.js技术栈实现钱包积分管理系统项目-若依框架二次开发准备工作-以及建立初步后端目录菜单列-优雅草卓伊凡商业项目实战
|
11天前
|
人工智能 JavaScript 安全
【01】Java+若依+vue.js技术栈实现钱包积分管理系统项目-商业级电玩城积分系统商业项目实战-需求改为思维导图-设计数据库-确定基础架构和设计-优雅草卓伊凡商业项目实战
【01】Java+若依+vue.js技术栈实现钱包积分管理系统项目-商业级电玩城积分系统商业项目实战-需求改为思维导图-设计数据库-确定基础架构和设计-优雅草卓伊凡商业项目实战
55 13
【01】Java+若依+vue.js技术栈实现钱包积分管理系统项目-商业级电玩城积分系统商业项目实战-需求改为思维导图-设计数据库-确定基础架构和设计-优雅草卓伊凡商业项目实战
|
2月前
|
JavaScript
vue使用iconfont图标
vue使用iconfont图标
147 1
|
6天前
|
移动开发 JavaScript API
Vue Router 核心原理
Vue Router 是 Vue.js 的官方路由管理器,用于实现单页面应用(SPA)的路由功能。其核心原理包括路由配置、监听浏览器事件和组件渲染等。通过定义路径与组件的映射关系,Vue Router 将用户访问的路径与对应的组件关联,支持哈希和历史模式监听 URL 变化,确保页面导航时正确渲染组件。
|
10天前
|
监控 JavaScript 前端开发
ry-vue-flowable-xg:震撼来袭!这款基于 Vue 和 Flowable 的企业级工程项目管理项目,你绝不能错过
基于 Vue 和 Flowable 的企业级工程项目管理平台,免费开源且高度定制化。它覆盖投标管理、进度控制、财务核算等全流程需求,提供流程设计、部署、监控和任务管理等功能,适用于企业办公、生产制造、金融服务等多个场景,助力企业提升效率与竞争力。
60 12
|
6天前
|
JavaScript 前端开发 开发者
Vue中的class和style绑定
在 Vue 中,class 和 style 绑定是基于数据驱动视图的强大功能。通过 class 绑定,可以动态更新元素的 class 属性,支持对象和数组语法,适用于普通元素和组件。style 绑定则允许以对象或数组形式动态设置内联样式,Vue 会根据数据变化自动更新 DOM。
|
6天前
|
JavaScript 前端开发 数据安全/隐私保护
Vue Router 简介
Vue Router 是 Vue.js 官方的路由管理库,用于构建单页面应用(SPA)。它将不同页面映射到对应组件,支持嵌套路由、路由参数和导航守卫等功能,简化复杂前端应用的开发。主要特性包括路由映射、嵌套路由、路由参数、导航守卫和路由懒加载,提升性能和开发效率。安装命令:`npm install vue-router`。
|
27天前
|
JavaScript 安全 API
iframe嵌入页面实现免登录思路(以vue为例)
通过上述步骤,可以在Vue.js项目中通过 `iframe`实现不同应用间的免登录功能。利用Token传递和消息传递机制,可以确保安全、高效地在主应用和子应用间共享登录状态。这种方法在实际项目中具有广泛的应用前景,能够显著提升用户体验。
54 8

热门文章

最新文章