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) { // 可以在函數里執(zhí)行完一些操作 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,執(zhí)行了自定義組件拋出宏定義事件并接收其攜帶過來的參數 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>
一、組件注冊
組件注冊:https://cn.vuejs.org/guide/components/registration.html
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、總結:非必要不實用全局注冊
二、屬性
父組件通過給子組件傳遞不同的屬性數據控制子組件最終展示狀態(tài)。
1、定義一個 props
通過 defineProps
宏定義一個屬性
const props = defineProps(['title']) console.log(props.title)
2、給 props添加類型并給定默認值
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
方法觸發(fā)自定義事件并拋出相關參數,$emit('拋出的事件名', 需要傳到父組件的參數一, 參數二...)
。拋出事件名要用可以使用 camelCase
和 kebab-case
形式(建議 kebab-case
)。
<!-- MyComponent --> <button @click="$emit('someEvent', $event, 1)">click me</button>
2、defineEmits() 宏來聲明要觸發(fā)的事件
在 <template>
中使用的 $emit
方法不能在組件的 <script setup>
部分中使用,相當于你不能對這個事件先做出一些處理然后再拋出,使用 defineEmits()
宏聲明要觸發(fā)的事件可以解決這個問題:
<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、使用組件并監(jiān)聽子組件拋出的事件及參數
<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
屬性,區(qū)分不同的插槽,可以有多個。
<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、組件編碼規(guī)范
使用
PascalCase
形式的組件名稱,提高了模板的可讀性,方便區(qū)分vue component
和原生HTML DOM
組件名格式給事件命名可以使用
camelCase
和kebab-case
(短橫線連字符) 形式,使用時用kebab-case
(短橫線連字符) 形式,使用camelCase
并沒有太多優(yōu)勢,推薦更貼近HTML
的kebab-case
書寫風格。
2、可復用性
- 組件內部樣式可覆蓋,盡可能不要寫死,提供參數去修改
- 組件內部頁面展示更加靈活,在合適的地方提供插槽,讓組件內布局可控、更加靈活
總結
到此這篇關于vue3學習筆記之自定義組件的文章就介紹到這了,更多相關vue3自定義組件內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
相關文章
vue-cli+iview項目打包上線之后圖標不顯示問題及解決方法
這篇文章主要介紹了解決vue-cli+iview項目打包上線之后圖標不顯示問題,本文通過兩種方法給大家介紹的非常詳細,具有一定的參考借鑒價值,需要的朋友可以參考下2019-10-10詳解使用Vue.Js結合Jquery Ajax加載數據的兩種方式
本篇文章主要介紹了詳解使用Vue.Js結合Jquery Ajax加載數據的兩種方式,具有一定的參考價值,感興趣的小伙伴們可以參考一下2017-01-01基于vue監(jiān)聽滾動事件實現錨點鏈接平滑滾動的方法
本篇文章主要介紹了基于vue監(jiān)聽滾動事件實現錨點鏈接平滑滾動的方法,非常具有實用價值,有興趣的可以了解一下2018-01-01