0


vue3笔记:自定义组件

自定义组件,举个🌰:

1、封装自定义组件

CustomList.vue
<!-- src/components/CustomList.vue --><scriptlang="ts">import type { IDataItem }from"../type/customlist";// IProps 不能直接从外部导入,当前会报错,以后可能会支持(有人提了issue)exportinterfaceIProps{
  title?: string;data: Array<IDataItem>;}</script><scriptsetuplang="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;}>();constclickItem=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><stylelang="less"scoped></style>
src

底下

type

文件夹中声明的

interface

接口文件

// src/type/customlist.d.tsexportinterfaceIDataItem{name: string;id: number;}

2、在

App.vue

中使用自定义组件

CustomList.vue
<!-- src/App.vue --><scriptsetuplang="ts">import{ ref, reactive, onMounted, onBeforeMount }from"vue";import CustomList from"./components/CustomList.vue";import type { IDataItem }from"./type/customlist";// 声明一个data,传到自定义组件CustomListconst data =reactive([]as Array<IDataItem>);const customListRef = ref<HTMLElement |null>(null);// 点击了自定义组件的item,执行了自定义组件抛出宏定义事件并接收其携带过来的参数constclickItem=function(item: string,e: Event){
  console.log("clickItem...", item, e);};// 点击了自定义组件的ul在templete里面直接抛出的事件并接收其携带过来的参数constclickUl=function(e: Event,value: number){
  console.log("clickUl...", e, value);};onBeforeMount(()=>{constlist: Array<IDataItem>=[{name:"aaa",id:1,},{name:"bbb",id:2,},];
  data.push(...list);});onMounted(()=>{
  console.log("onMounted...", customListRef.value);});</script><template><divclass="content"><!-- 使用自定义组件CustomList --><CustomList@click-ul="clickUl"@click-item="clickItem":data="data"ref="customListRef"/></div></template><stylescopedlang="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

导入

<scriptsetup>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)exportinterfaceIProps{
  title?: string;data: Array<IDataItem>;}const props =withDefaults(defineProps<IProps>(),{title:"CustomList",});

3、

props

只读,不可修改

组件内的

props

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

<scriptsetuplang="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;}>();constcallback=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";constcallback=function(e: Event, value){
    console.log("callback...", e, value);}</script><template><MyComponent@some-event="callback"/></template>

四、插槽

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

1、匿名插槽

组件内插入

<slot>

标签不指定

name

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

<!-- 子组件 SubmitButton --><buttontype="submit"><slot>这里是默认内容文本</slot></button><!-- 使用 SubmitButton (不传值) ,按钮内部显示【这里是默认内容文本】--><SubmitButton/><!--  使用 SubmitButton (传值) ,按钮内部显示【Save】--><SubmitButton>Save</SubmitButton>

2、具名插槽

组件内插入

<slot>

标签时加上一个

name

属性,区分不同的插槽,可以有多个。

<slotname="header"></slot>

3、具名作用域插槽

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

<!-- 子组件 MyComponent --><template><slotname="header"message="hello header"></slot><slotmessage="hello default"></slot><slotname="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://blog.csdn.net/weixin_45921387/article/details/129329525
版权归原作者 是烤面包片呀? 所有, 如有侵权,请联系我们删除。

“vue3笔记:自定义组件”的评论:

还没有评论