vue3笔记:自定义组件

这篇具有很好参考价值的文章主要介绍了vue3笔记:自定义组件。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

自定义组件,举个🌰:

1、封装自定义组件 CustomList.vue

<!-- src/components/CustomList.vue -->
<script lang="ts">
import type { IDataItem } from "../type/customlist";
// IProps 不能直接从外部导入,当前会报错,以后可能会支持(有人提了issue)
export interface IProps {
  title?: string;
  data: Array<IDataItem>;
}
</script>

<script setup lang="ts">
import { onMounted } from "vue";
// 声明一些属性,给父组件传值进来,并且给部分设置了默认值
const props = withDefaults(defineProps<IProps>(), {
  title: "CustomList",
});
// 抛出事件,供父组件使用
// const emit = defineEmits(["click-item"]);
const emit = defineEmits<{
  (e: "click-item", item: IDataItem, $event: Event): void;
}>();
const clickItem = function (item: IDataItem, e: Event) {
  // 可以在函数里执行完一些操作
  console.log("自定义组件点击了组件里面的item...", item, e);
  // 再抛出宏定义的事件
  emit("click-item", item, e);
};
onMounted(() => {
  console.log("CustomList onMounted...", props);
});
</script>

<template>
  <h1>{{ title }}</h1>
  <ul @click="$emit('click-ul', $event, 1)">
    <li @click="clickItem(item, $event)" v-for="item in data" :key="item.id">
      {{ item.name }}
    </li>
  </ul>
</template>

<style lang="less" scoped></style>

src 底下 type 文件夹中声明的 interface 接口文件

// src/type/customlist.d.ts
export interface IDataItem {
  name: string;
  id: number;
}

2、在 App.vue 中使用自定义组件 CustomList.vue

<!-- src/App.vue -->
<script setup lang="ts">
import { ref, reactive, onMounted, onBeforeMount } from "vue";
import CustomList from "./components/CustomList.vue";
import type { IDataItem } from "./type/customlist";
// 声明一个data,传到自定义组件CustomList
const data = reactive([] as Array<IDataItem>);
const customListRef = ref<HTMLElement | null>(null);
// 点击了自定义组件的item,执行了自定义组件抛出宏定义事件并接收其携带过来的参数
const clickItem = function (item: string, e: Event) {
  console.log("clickItem...", item, e);
};
// 点击了自定义组件的ul在templete里面直接抛出的事件并接收其携带过来的参数
const clickUl = function (e: Event, value: number) {
  console.log("clickUl...", e, value);
};

onBeforeMount(() => {
  const list: Array<IDataItem> = [
    {
      name: "aaa",
      id: 1,
    },
    {
      name: "bbb",
      id: 2,
    },
  ];
  data.push(...list);
});
onMounted(() => {
  console.log("onMounted...", customListRef.value);
});
</script>

<template>
  <div class="content">
    <!-- 使用自定义组件CustomList -->
    <CustomList
      @click-ul="clickUl"
      @click-item="clickItem"
      :data="data"
      ref="customListRef"
    />
  </div>
</template>

<style scoped lang="less">
.content {
  width: 100vw;
  height: 100vh;
  display: flex;
  flex-direction: column;
  color: var(--colorTextNormal);
  padding: 50px;
}
</style>

一、组件注册

1、全局注册

main.ts 中使用 app.component('MyComponent', MyComponent) 全局注册一个组件,可以在app内的任何地方使用。

缺点:

  • 无法在生产打包时被自动移除 (也叫 tree-shaking ),即使它并没有被实际使用,它仍然会出现在打包后的 JS 文件中。

  • 依赖关系不明显,出问题不易定位,用多了难维护

2、局部注册

在用到组件的地方 import 导入

<script setup>
import ComponentA from './ComponentA.vue'
</script>

<template>
  <ComponentA />
</template>

3、总结:非必要不实用全局注册

二、属性

父组件通过给子组件传递不同的属性数据控制子组件最终展示状态。

1、定义一个 props

通过 defineProps 宏定义一个属性

const props = defineProps(['title'])
console.log(props.title)

2、给 props添加类型并给定默认值

针对类型的 props/emit 声明

defineProps<IProps>() 可以给 props 设置类型,IPropsprops 类型 为组件的 props 标注类型

withDefaults 的第二个参数支持给 props 设置默认值 使用类型声明时的默认 props 值

import type { IDataItem } from "../type/customlist";
// IProps 不能直接从外部导入,当前会报错,以后可能会支持(有人提了issue)
export interface IProps {
  title?: string;
  data: Array<IDataItem>;
}
const props = withDefaults(defineProps<IProps>(), {
  title: "CustomList",
});

3、 props只读,不可修改

组件内的 props 都是只读的,不能对其进行修改 单向数据流

<script setup lang="ts">
import { onMounted } from "vue";
// 声明一些属性,给父组件传值进来,并且给部分设置了默认值
const props = withDefaults(defineProps<IProps>(), {
  title: "CustomList",
});
onMounted(() => {
    // ❎ 不能这么干,单向数据流 props 不可修改
    props.title = "改变了CustomList的title"
});
</script>

三、事件

子组件抛出内部事件并传递参数供父组件使用。

1、template 内使用 $emit 直接抛出一个事件

在组件的模板表达式中,可以直接使用 $emit 方法触发自定义事件并抛出相关参数,$emit('抛出的事件名', 需要传到父组件的参数一, 参数二...)。抛出事件名要用可以使用 camelCasekebab-case 形式(建议 kebab-case )。

<!-- MyComponent -->
<button @click="$emit('someEvent', $event, 1)">click me</button>

2、defineEmits() 宏来声明要触发的事件

<template> 中使用的 $emit 方法不能在组件的 <script setup> 部分中使用,相当于你不能对这个事件先做出一些处理然后再抛出,使用 defineEmits() 宏声明要触发的事件可以解决这个问题:

声明触发的事件

<script>
// 抛出事件,供父组件使用
const emit = defineEmits<{
  // (e: "抛出的事件名", 抛出的参数一, 参数二...)
  (e: "callback", $event: Event): void;
}>();
const callback = function (e: Event) {
  emit("callback", e);
};
</script>
<template>
  <button @click="callback($event, 111)">click me</button>
</template>

3、使用组件并监听子组件抛出的事件及参数

<script>
import MyComponent from "./components/MyComponent.vue";
const callback = function (e: Event, value) {
    console.log("callback...", e, value);
}
</script>
<template>
    <MyComponent @some-event="callback" />
</template>

四、插槽

可以在自定义组件内部指定的部位插入自定义内容,让组件更加灵活。

1、匿名插槽

组件内插入 <slot> 标签不指定 name 属性,默认只有一个,可以给插槽内添加默认值,父组件在使用组件时不传值的时候会展示默认内容,传值则会替换掉默认内容。

<!-- 子组件 SubmitButton -->
<button type="submit">
  <slot>这里是默认内容文本</slot>
</button>

<!-- 使用 SubmitButton (不传值) ,按钮内部显示【这里是默认内容文本】-->
<SubmitButton />

<!--  使用 SubmitButton (传值) ,按钮内部显示【Save】-->
<SubmitButton>Save</SubmitButton>

2、具名插槽

组件内插入 <slot> 标签时加上一个 name 属性,区分不同的插槽,可以有多个。

<slot name="header"></slot>

3、具名作用域插槽

感觉跟具名插槽就是同一个东西,就是可以从子组件带参数过来,只能在指定的插槽里面用。

<!-- 子组件 MyComponent -->
<template>
    <slot name="header" message="hello header"></slot>
    <slot message="hello default"></slot>
    <slot name="footer" message="hello footer"></slot>
</template>

<!-- 父组件 -->
<!-- headerProps, defaultProps, footerProps 是一个对象 ,返回以对应 slot 上 { 属性: 属性值 } 形式的数据 -->
<MyComponent>
  <template #header="headerProps">
    {{ headerProps.message }}
  </template>
  <template #default="defaultProps">
    {{ defaultProps.message }}
  </template>
  <template #footer="footerProps">
    {{ footerProps.message }}
  </template>
  <!-- 解构取值的 🌰 -->
   <template #footer="{ message }">
    {{ message }}
  </template>
</MyComponent>

五、封装一个组件注意

1、组件编码规范

  • 使用 PascalCase 形式的组件名称,提高了模板的可读性,方便区分 vue component 和原生 HTML DOM 组件名格式

  • 给事件命名可以使用 camelCasekebab-case (短横线连字符) 形式,使用时用 kebab-case (短横线连字符) 形式,使用 camelCase 并没有太多优势,推荐更贴近 HTMLkebab-case 书写风格。

    DOM 模板解析注意事项
    传递 prop 的细节

2、可复用性文章来源地址https://www.toymoban.com/news/detail-478881.html

  • 组件内部样式可覆盖,尽可能不要写死,提供参数去修改
  • 组件内部页面展示更加灵活,在合适的地方提供插槽,让组件内布局可控、更加灵活

到了这里,关于vue3笔记:自定义组件的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 壁纸小程序Vue3(自定义头部组件)

     coustom-nav  1)状态栏     view class=\\\"statusBar\\\" :style=\\\"{height: statusBarHeight +\\\'px\\\'}\\\"/view H5中为0     view class=\\\"titleBar\\\" :style=\\\"{height:titleBarHeight+\\\'px\\\'}\\\" 获取胶囊位置   view class=\\\"fill\\\" :style=\\\"{height:statusBarHeight+titleBarHeight+\\\'px\\\'}\\\"     /view 填充区域,让轮播图展示全 script setup import { ref } from \\\'vue

    2024年04月11日
    浏览(33)
  • 在vue3中定义组件的5种方式

    Vue 正在不断发展,目前在 Vue3 中定义组件的方法有多种。从选项式到组合式再到类 API ,情况截然不同。本文将会定义一个简单的组件并使用所有可用的方法重构它。 这是在 Vue 中声明组件的最常见方法。从 Vue1 就开始存在了,我们很可能已经熟悉它了。一切都在对象内部声

    2024年02月13日
    浏览(32)
  • vue3自定义封装组件:消息提示、轮播图、加载更多、骨架屏组件

    定义组件:src/components/library/xtx-infinite-loading.vue 注册组件:src/components/library/index.js  引用组件:src/main.js 使用组件: .vue文件 首先是轮播图的样式:src/components/library/xtx-carousel.vue  然后是轮播图的结构与逻辑封装:src/components/library/xtx-carousel.vue 插件注册:src/components/library

    2024年02月12日
    浏览(46)
  • 自定义精美商品分类列表组件 侧边栏商品分类组件 category组件(适配vue3)

    随着技术的发展,开发的复杂度也越来越高,传统开发方式将一个系统做成了整块应用,经常出现的情况就是一个小小的改动或者一个小功能的增加可能会引起整体逻辑的修改,造成牵一发而动全身。通过组件化开发,可以有效实现单独开发,单独维护,而且他们之间可以随

    2024年02月05日
    浏览(51)
  • vue3前端excel导出;组件表格,自定义表格导出;Vue3 + xlsx + xlsx-style

    当画面有自定义的表格或者样式过于复杂的表格时,导出功能可以由前端实现 1. 使用的插件 : sheet.js-xlsx 文档地址:https://docs.sheetjs.com/ 中文地址:https://geekdaxue.co/read/SheetJS-docs-zh/README.md xlsx-style:https://www.npmjs.com/package/xlsx-style 2. 安装引用 安装插件-vue3 引用插件 3. 组件表格

    2024年04月26日
    浏览(39)
  • vue3组件通信学习笔记

    父组件 子组件 父组件 子组件 子组件1 子组件2 父组件 子组件 父组件 子组件 父组件 子组件 父组件 子组件 父组件 子组件 孙子组件 1、选择式写法 1、info.js 2、在组件1中使用 3、在组件2中使用 2、组合式API写法 1、在modules文件夹下新建todo.js 2、在组件1中使用 3、在组件2中使

    2024年02月09日
    浏览(45)
  • vue3自定义dialog createApp setup语法组件使用element

    目录  index.vue mapDialog.js

    2024年02月14日
    浏览(45)
  • 【vue3】学习笔记--组件通信方式

    学习vue3总是绕不开vue2 vue3组件通信方式如下: props数据只读,从父组件传递到子组件,子组件内部不可直接更改 子组件需要使用defineProps方法接受父组件传递过来的数据 setup语法糖下局部组件无需注册直接可以使用 父组件 子组件 vue框架中事件分为两种:原生的DOM事件和自定

    2024年02月13日
    浏览(52)
  • 【Vue3】学习笔记-新的组件

    在Vue2中: 组件必须有一个根标签 在Vue3中: 组件可以没有根标签, 内部会将多个标签包含在一个Fragment虚拟元素中 好处: 减少标签层级, 减小内存占用 什么是Teleport?—— Teleport 是一种能够将我们的 组件html结构 移动到指定位置的技术。 等待异步组件时渲染一些额外内容,让应

    2024年02月16日
    浏览(41)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包