【Vue3】全局组件,递归组件,动态组件,传送组件,缓存组件,异步组件等

父子组件传参

  • 父组件通过v-bind绑定一个数据,然后子组件通过defineProps接受传过来的值
父传子
模板上直接使用
<template>
  <div class="main">
    <div class="vt-test">子组件</div>
    <div>{{ title }}</div>
  </div>
</template>

<script setup lang="ts">
//接受父组件传过来的值
defineProps({
  title: {
    type: String,
    default: '默认值',
  },
});
</script>
js里面使用
// 接受父组件传过来的值;
const props = defineProps({
  title: {
    type: String,
    default: '默认值',
  },
});
console.log('父组件传过来的值', props.title);
ts组件里面泛型接收
//ts模式下接收采取泛型更方便
const prop = defineProps<{
  title: string;
}>();
console.log('父组件传过来的值', prop.title);
ts泛型里面设置默认值
//ts模式下设置默认值
const prop = withDefaults(
  defineProps<{
    title: string;
    arr: number[];
  }>(),
  {
    arr: () => [1, 2, 3],
  }
);
console.log('父组件传过来的值', prop.title);
子传父
方式一,采用defineEmits
  • 子组件
<template>
  <div class="main">
    <div class="vt-test">子组件</div>
    <button @click="send">点击给父组件传值</button>
  </div>
</template>

<script setup lang="ts">
//给父组件传值采用defineEmits
const emit = defineEmits(['on-click','on-getname']);
const send = () => {
  emit('on-click', '花神');
  emit('on-getname', '花神');
};
</script>
  • 父组件
<template>
  <div class="vt-parents">父组件</div>
  <hr />
  <Helloworld :title="name" @on-click="getclick" @on-getname='getName'></Helloworld>
</template>

<script setup lang="ts">
import Helloworld from './components/HelloWorld.vue';
const name = '花神';
const getName = (value) => {
  console.log(value, '子组件传的值');
};
</script>
  • 子组件传多个事件
//给父组件传值采用defineEmits
const emit = defineEmits(['on-click', 'on-getname']);
const send = () => {
  emit('on-click', '花神');
  emit('on-getname', '花神2');
};
const getname = () => {
  emit('on-getname', '花神2');
};
方式二,采用ts的泛型
<script setup lang="ts">
//给父组件传值采用defineEmits
//有没有返回值,没有返回值定义void,不加也不报错
const emit = defineEmits<{
  (e: 'on-click', value: string): void;
  (e: 'on-getname', value: string): void;
}>();
const send = () => {
  emit('on-click', '花神');
};
const getname = () => {
  emit('on-getname', '花神2');
};
</script>
方式三,采用ref获取子组件内部暴露的数据和方法
子组件先暴露
  • defineExpose
    在这里插入图片描述
父组件接收
  • 类型检测<InstanceType>不写也行

全局组件

  • 在main.ts文件里导入组件并挂载在全局中

在这里插入图片描述

  • 页面上直接使用即可
    在这里插入图片描述
发现有报错,找不到模块“./App.vue”或其相应的类型声明

在这里插入图片描述

  • 解决思路:在项目根目录 env.d.ts 文件中,加入以下内容:
/// <reference types="vite/client" />
declare module "*.vue" {
  import type { DefineComponent } from "vue"
  const vueComponent: DefineComponent<{}, {}, any>
  export default vueComponent
}
批量导入组件
  • 想一次性全部导入模块的所有变量就可以使用 * as 代表全部
  • Object.entries() ,将一个对象中可枚举属性的键名和键值按照二维数组的方式返回
    在这里插入图片描述

可选链

  • 单问号,没有值返回undefined
  • 双问号,只判断undefined和null,0和false不处理
    在这里插入图片描述

递归组件

  • 简单来说就是在组件中内使用组件本身
  • 一般用来实现树形菜单,多级菜单
  • 注意的是:要防止无限递归,造成调用栈溢出
步骤一,建立子组件Tree.vue
<template>
  <div class="main" v-for="(item, index) in data" :key="index">
    <input type="checkbox" v-model="item.checked" /><span>{{ item.name }}</span>
    <Tree v-if="item?.children?.length" :data="item?.children"></Tree>
  </div>
</template>

<script setup lang="ts">
import { ref, reactive } from 'vue';
//定义接收的数据类型
interface Tree {
  name: string;
  checked: boolean;
  children?: Tree[];
}
defineProps<{ data?: Tree[] }>();
</script>

<style scoped>
.main {
  margin-left: 30px;
}
</style>

步骤二,建立父组件展示最终页面
<template>
  <div class="main"></div>
  <TreeVal :data="data"></TreeVal>
</template>

<script setup lang="ts">
import { ref, reactive } from 'vue';
import TreeVal from './components/Tree.vue';
interface Tree {
  name: string;
  checked: boolean;
  children?: Tree[];
}
//造自定义数据传递给子组件
const data = reactive<Tree[]>([
  {
    name: '1',
    checked: false,
    children: [
      {
        name: '1-1',
        checked: false,
        children: [
          {
            name: '1-1-1',
            checked: false,
            children: [],
          },
        ],
      },
    ],
  },
  {
    name: '2',
    checked: false,
    children: [],
  },
]);
</script>

<style scoped></style>
  • 最终展示页面
    在这里插入图片描述
如何设置递归组件名name
  • 方式一:可以采用文件名本身
    在这里插入图片描述
  • 方式二:可以页面内再建script里自定义组件名
    在这里插入图片描述
  • 方式三:通过插件

在这里插入图片描述

防止点击冒泡和传递event对象

在这里插入图片描述

动态组件

  • 让多个组件使用同一个挂载点,并动态切换
  • 在挂载点使用component标签,然后使用v-bind :is=”组件“
方式一
<template>
  <div v-for="(item, index) in com" :key="index">
    <div>{{ item.name }}</div>
    <component :is="item.com"></component>
  </div>
</template>

<script lang="ts">
import A from './components/A.vue';
import B from './components/B.vue';
import C from './components/C.vue';

export default {
  components: {
    A,
    B,
    C,
  },
};
</script>
<script setup lang="ts">
import { ref, reactive } from 'vue';
//区别,此时使用的时候是字符串形式
const com = reactive([
  { name: 'A组件', com: "A" },
  { name: 'B组件', com: "B" },
  { name: 'C组件', com: "C" },
]);
</script>
方式二。Vue3写法
<template>
  <div v-for="(item, index) in com" :key="index">
    <div>{{ item.name }}</div>
    <component :is="item.com"></component>
  </div>
</template>
<script setup lang="ts">
import { ref, reactive } from 'vue';
import A from './components/A.vue';
import B from './components/B.vue';
import C from './components/C.vue';
//这边直接使用
const com = reactive([
  { name: 'A组件', com: A },
  { name: 'B组件', com: B },
  { name: 'C组件', com: C },
]);
</script>
  • 虽然展示,但有报错
    在这里插入图片描述
  • 使用markRaw,到时候会多一个skip属性,reactive碰到这个属性,会跳过proxy代理
<script setup lang="ts">
import { ref, reactive, markRaw } from 'vue';
import A from './components/A.vue';
import B from './components/B.vue';
import C from './components/C.vue';

const com = reactive([
  { name: 'A组件', com: markRaw(A) },
  { name: 'B组件', com: markRaw(B) },
  { name: 'C组件', com: markRaw(C) },
]);
</script>

Teleport 传送组件

  • Teleport是一种能够将我们的模板渲染至指定Dom节点,不受父级style,v-show等属性影响
  • 但data,prop数据依旧能够共用的技术
  • 主要为了解决,使Teleport节点挂载在其他指定的节点下,完全不受父级style样式的影响
  • 例如:想要将子组件的这个弹窗挂载到外层
    在这里插入图片描述
  • 使用Teleport ,to挂载到想要展示的层级
<template>
  <div class="main">
    <h3>子组件</h3>
    <!-- disabled设置为true,则to不生效,否则生效 -->
    <Teleport to="body" :disabled="true	">
      <div class="box">弹窗</div>
    </Teleport>
  </div>
</template>

<script setup lang="ts">
import { ref, reactive } from 'vue';
</script>

<style scoped lang="less">
.main {
  position: relative;
  width: 500px;
  height: 30vh;
  margin-left: 30px;
  background: #888;
}
.box {
  background: yellow;
  width: 200px;
  height: 200px;
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
}
</style>

在这里插入图片描述

keep-alive缓存组件

  • 注意,keep-alive里面只能有一个子节点,不能放多个,多个的话需要if条件判断只显示一个
  • 有时候不希望组件被重新渲染影响使用体验,或者处于性能考验,避免多次重复渲染
  • 目的,想要切换组件的时候,将我之前输入的值保留
    在这里插入图片描述
include
  • 缓存name匹配上的
  • 在vue3中,组件内部的组件name需要重新写,setup的语法糖不支持
  • 子组件
<template>
  <div class="main">
    <h3>子组件</h3>
    <Teleport to="body" :disabled="true">
      <div class="box">弹窗</div>
    </Teleport>
    <input type="text" />
  </div>
</template>

<script setup lang="ts">
import { ref, reactive } from 'vue';
</script>
//重写name,为了在父组件可以使用include缓存Avue
<script lang="ts">
export default {
  name: 'Avue',
};
</script>

  • 父组件
<template>
  <div class="main">
    <!-- include,只缓存名字匹配的,例如,这次只缓存Avue,Bvue不缓存-->
    <keep-alive :include="['Avue']">
      <Avue v-if="istrue"></Avue>
      <Bvue v-else></Bvue>
    </keep-alive>
    <button @click="change">切换</button>
  </div>
</template>

<script setup lang="ts">
import { ref, reactive } from 'vue';
import Avue from './components/A.vue';
import Bvue from './components/B.vue';
let istrue = ref('true');
const change = () => {
  istrue.value = !istrue.value;
};
</script>

<style scoped></style>

enclude
  • 不缓存name匹配上的
max,缓存最多数
  • 超出max,会剔除旧的,不活跃的,保留新组件进行缓存
keep-alive生命周期onActivated和onDeactivated
  • 初始化只会走一次
  • 子组件
<template>
  <div class="main">
    <h3>子组件</h3>
    <Teleport to="body" :disabled="true">
      <div class="box">弹窗</div>
    </Teleport>
    <input type="text" />
  </div>
</template>

<script setup lang="ts">
import {
  ref,
  reactive,
  onMounted,
  onUnmounted,
  onActivated,
  onDeactivated,
} from 'vue';
onMounted(() => {
  console.log('初始化');
});
onActivated(() => {
  console.log('keeplive缓存生命周期初始化');
});
onDeactivated(() => {
  console.log('keeplive缓存生命周期卸载');
});
onUnmounted(() => {
  console.log('卸载');
});
</script>
<script lang="ts">
export default {
  name: 'Avue',
};
</script>
  • 刚进入

在这里插入图片描述

  • 切换后
    在这里插入图片描述
  • 切回来
    在这里插入图片描述

异步组件

  • defineAsyncComponent加载异步组件
  • 大型应用中,需要将应用分割成小一些的代码块,并且减少主包的体积
<template>
  <div class="main">
    <Suspense>
      <template #default>
          <Syncvue></Syncvue>
      </template>
      <template #fallback>
        <!-- 放置骨架屏等 -->
      </template>
    </Suspense>
  </div>
</template>

<script setup lang="ts">
import { ref, reactive,defineAsyncComponent} from 'vue';
const Syncvue =defineAsyncComponent(()={import('@/components/sync.vue')})
</script>

<style scoped></style>

Suspense
  • 它帮助我们处理异步组件,但它的作用远不止于此
  • 我们可以将异步组件的加载状态和占位内容进行统一管理。当异步组件加载完成时,会自动替换占位内容,从而实现平滑的过渡效果
  • Suspense 允许我们协调整个应用程序的加载状态,而不是一个页面上到处都是 loading
  • Suspense,把异步组件放入 default 槽,把回退加载状态放入 fallback 槽。
  • Suspense 机制还提供了错误处理的能力。当异步组件加载出错时,可以显示自定义的错误信息,以便及时通知用户
<template>
  <Suspense>
    <template v-slot:default>
      <div>Loading...</div>
    </template>

    <template v-slot:error>
      <div>Failed to load component.</div>
    </template>

    <Syncvue />
  </Suspense>
</template>

<script>
import { defineAsyncComponent } from 'vue';

const Syncvue =defineAsyncComponent(()={import('@/components/sync.vue')})

export default {
  components: {
    Syncvue ,
  },
};
</script>

  • 29
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
在UniApp中,你可以使用Vue 3来创建全局组件。下面是一些创建全局组件的步骤: 1. 创建一个全局组件目录,比如 `components`。 2. 在 `components` 目录下创建一个新的组件文件,比如 `GlobalComponent.vue`。 3. 在 `GlobalComponent.vue` 文件中定义你的全局组件,可以使用Vue 3的语法来编写组件。 4. 在 `main.js`(或者其他入口文件)中引入 `GlobalComponent.vue` 并注册为全局组件。 下面是一个示例: 1. 在 `components` 目录下创建 `GlobalComponent.vue` 文件: ```vue <template> <div> <h1>这是一个全局组件</h1> <p>{{ message }}</p> </div> </template> <script> export default { data() { return { message: 'Hello, World!' } } } </script> <style scoped> h1 { color: red; } </style> ``` 2. 在 `main.js` 中注册全局组件: ```javascript import { createApp } from 'vue' import App from './App.vue' import GlobalComponent from './components/GlobalComponent.vue' const app = createApp(App) app.component('global-component', GlobalComponent) app.mount('#app') ``` 现在,你可以在任何页面的模板中使用 `<global-component>` 标签来使用全局组件。 ```vue <template> <div> <h2>页面组件</h2> <global-component></global-component> </div> </template> <script> export default { // 组件的其他配置项 } </script> <style> /* 页面组件的样式 */ </style> ``` 这样就可以在你的UniApp中使用Vue 3的全局组件了。记得确保引入了Vue 3的版本,并且按照上述步骤正确注册和使用全局组件

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值