首页IT科技vue3.0自定义组件(vue3笔记:自定义组件)

vue3.0自定义组件(vue3笔记:自定义组件)

时间2025-06-21 01:12:56分类IT科技浏览4267
导读:自定义组件,举个🌰:...

自定义组件            ,举个🌰:

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 设置类型                  ,IProps 为 props 类型 为组件的 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(抛出的事件名, 需要传到父组件的参数一, 参数二...)                  。抛出事件名要用可以使用 camelCase 和 kebab-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 组件名格式

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

DOM 模板解析注意事项

传递 prop 的细节

2                  、可复用性

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

创心域SEO版权声明:以上内容作者已申请原创保护,未经允许不得转载,侵权必究!授权事宜、对本内容有异议或投诉,敬请联系网站管理员,我们将尽快回复您,谢谢合作!

展开全文READ MORE
python的自动化(python自动化是什么)