前言
Vue 是前端开发中非常常见的一种框架,它的易用性和灵活性使得它成为了很多开发者的首选。而在 Vue2 版本中,组件的开发也变得非常简单,但随着 Vue3 版本的发布,组件开发有了更多的特性和优化,为我们的业务开发带来了更多便利。本文将介绍如何使用 Vue3 开发业务组件,并通过代码实例进行演示。
一、自己封装组件
1、button 代码
在
src
目录下创建components
文件夹,并在该文件夹下创建Button
文件。
在Button
文件中创建index.vue
文件和index.ts
文件,并编写以下代码
在index.vue
文件中编写以下代码
<script lang="ts" setup name="ZButton">
defineProps({text: {type: String,default: ''},btnSize: {type: String,default: 'default'},size: {type: Number,default: 14},type: {type: String,default: 'default'},left: {type: Number,default: 0},right: {type: Number,default: 0},disabled: {type: Boolean,default: false},loading: {type: Boolean,default: false}
})
</script><template><div :type="type" :size="btnSize" :class="`z-button-${type}`" :disabled="disabled" :loading="loading" :style="{marginLeft: `${left}px`,marginRight: `${right}px`}">{{ text }}</div>
</template><style lang="scss" scoped>
.z-button-blue {background: #80d4fb;color: #fff;border: none;&:hover,&:focus,&:active {background: #80d4fb80;color: #fff;}.anticon {color: #fff;}
}.z-button-warn {background: #ec622b;color: #fff;border: none;outline: none;&:hover,&:focus,&:active {background-color: #ec622b80;color: #fff;}.anticon {color: #fff;}
}
</style>
在
index.ts
文件中编写以下代码
import ZButton from "./index.vue";export default ZButton
2、button 使用组件
我们在 home
页面导入组件来进行测试
<script setup lang="ts">
import { useRouter } from 'vue-router'
import useUserStore from '@/store/modules/user'
import ZButton from '@/components/Button/index' // 新增const router = useRouter()
const userStore = useUserStore()function goRouter(path: string): void {router.push(path)
}function getUserInfo(): void {console.log(userStore.userInfo, 'userStore.userInfo')
}
</script><template><div class="flex-c flex-align h-100"><el-button type="primary" @click="goRouter('/news')">go news</el-button><el-button type="primary" @click="goRouter('/user')">go user</el-button><el-button @click="getUserInfo">get user info</el-button><el-button type="primary" @click="goRouter('/table')">go table</el-button><!-- 新增 --><z-button type="blue" text="测试blue" :left="10"></z-button><!-- 新增 --><z-button type="warn" text="测试warn" :left="10"></z-button></div>
</template>
3、button 效果图
二、基于 Element-Plus 封装组件
1、table 代码
在
components
文件夹下创建Table
文件。在
Table
文件中创建index.vue
、index.ts
和types.ts
文件,并编写以下代码
在index.vue
文件中编写以下代码
<script setup lang="ts" name="ZTable">
import { ref, computed, watch, nextTick, defineExpose } from 'vue'
import { ElTable } from 'element-plus'
import { ZTableOptions } from './types'const props = withDefaults(defineProps<{// 表格配置选项propList: ZTableOptions[]// 表格数据data: any[]// 表格高度height?: string | numbermaxHeight?: string | number// 显示复选框showSelectColumn?: boolean// 显示复选框showExpand?: boolean// 显示序号showIndexColumn?: boolean// 显示操作columnoperation?: boolean// 操作column 宽度operationWidth?: stringmoreOperationsPopoverWidth?: string// 加载状态loading?: boolean// 加载文案loadingText?: string// 加载图标名elementLoadingSpinner?: string// 是否显示分页pagination?: boolean// 显示分页的对齐方式paginationAlign?: 'left' | 'center' | 'right'pageInfo?: any// 显示分页数据多少条的选项pageSizes?: number[]// 数据总条数total?: numberemptyImg?: boolean}>(),{propList: () => [],height: '100%',operation: true,operationWidth: '240px',moreOperationsPopoverWidth: '160px',paginationAlign: 'right',pageInfo: () => ({ page: 1, size: 10 }),pageSizes: () => [10, 15, 20, 30],total: 0,emptyImg: true}
)const ZTableRef = ref<InstanceType<typeof ElTable>>()
const tablePropList: any = ref([])watch(() => props.propList,(list) => {tablePropList.value = []nextTick(() => {tablePropList.value = JSON.parse(JSON.stringify(list))})},{immediate: true}
)// 表格分页的排列方式
const justifyContent = computed(() => {if (props.paginationAlign === 'left') return 'flex-start'else if (props.paginationAlign === 'right') return 'flex-end'else return 'center'
})const emits = defineEmits(['row-click','select-rows','page-change','sort-change','operation-click'
])const handleOperationClick = (row: any, code: string, index: number) => {emits('operation-click', code, row, index)
}
const selectable = (row: any, index: any) => {return !row.noSelectable
}
const handleRowClick = (row: any, column: any) => {if (column?.label == '操作') returnemits('row-click', row, column)
}
const handleSelectionChange = (list: any) => {emits('select-rows', list)
}
const handleSizeChange = (size: number) => {emits('page-change', { page: 1, size })
}
const handleCurrentChange = (page: number) => {emits('page-change', { ...props.pageInfo, page })
}
const changeTableSort = (value: any) => {emits('sort-change', value)
}
const toggleSelection = (rows?: any) => {if (rows) {rows.forEach((row: any) => {ZTableRef.value!.toggleRowSelection(row, true)})} else {ZTableRef.value!.clearSelection()}
}defineExpose({toggleSelection
})
</script><template><div class="z-table"><el-table :data="data" :height="height" :max-height="maxHeight" ref="ZTableRef" v-loading="loading":element-loading-text="loadingText" :element-loading-spinner="elementLoadingSpinner" stripe@sort-change="changeTableSort" @row-click="handleRowClick" @selection-change="handleSelectionChange"v-bind="$attrs"><template #empty v-if="emptyImg"><div class="empty-box"><el-empty></el-empty></div></template><el-table-column type="expand" v-if="showExpand"><template #default="scope"><slot name="baseExpandSlot" :row="scope.row"></slot></template></el-table-column><el-table-column v-if="showSelectColumn" type="selection" :selectable="selectable" fixed="left" align="center"width="55"></el-table-column><el-table-column v-if="showIndexColumn" fixed="left" type="index" label="序号" align="center"width="55"></el-table-column><template v-for="propItem in tablePropList" :key="propItem.prop"><template v-if="propItem.visible !== false"><template v-if="!propItem.slotName"><el-table-column v-bind="propItem"></el-table-column></template><template v-else><el-table-column v-bind="propItem"><template #default="scope"><slot :name="propItem.slotName" :format="propItem.dateFormat" :row="scope.row" :prop="propItem.prop":index="scope.$index"></slot></template></el-table-column></template></template></template><el-table-column v-if="operation" label="操作" :width="operationWidth" fixed="right"><template #default="scope"><template v-if="scope.row.operations"><div class="operations-wrap"><template v-for="(o, i) in scope.row.operations" :key="o.code"><el-button v-if="i < 3" text type="primary" size="small" :disabled="o.disabled"@click="handleOperationClick(scope.row, o.code, scope.$index)">{{ o.name }}</el-button></template><el-popover placement="bottom-end" :width="moreOperationsPopoverWidth"v-if="scope.row.operations.length > 3"><template #reference><el-icon color="#26A5FF" class="more-dot"><MoreFilled /></el-icon></template><div class="more-operations"><template v-for="(o, i) in scope.row.operations" :key="o.code"><el-button v-if="i > 2" text type="primary" size="small" :disabled="o.disabled" @click="handleOperationClick(scope.row, o.code, scope.$index)">{{ o.name }}</el-button></template></div></el-popover></div></template></template></el-table-column></el-table><div v-if="pagination" class="pagination" :style="{ justifyContent }"><el-pagination small :current-page="pageInfo.page" :page-sizes="pageSizes" :page-size="pageInfo.size"layout="total, sizes, prev, pager, next, jumper" :total="total" @size-change="handleSizeChange"@current-change="handleCurrentChange"></el-pagination></div></div>
</template><style lang="scss" scoped>
.operations-wrap {.el-button+.el-button {margin-left: 25px;}.more-dot {position: relative;top: 0.3em;margin-left: 25px;font-size: 20px;cursor: pointer;}
}.more-operations {display: flex;flex-wrap: wrap;.el-button {overflow: hidden;margin-left: 10px;height: 32px;border-radius: 8px;line-height: 32px;}
}.el-loading-mask {z-index: 1;
}.pagination {display: flex;margin-top: 16px;
}.el-table__expand-column .cell {width: 55px;
}.is-dark {max-width: 40%;
}
</style>
在
index.ts
文件中编写以下代码
import ZTable from './index.vue'export default ZTable
在
types.ts
文件中编写以下代码
export interface ZTableOptions {// 是否可见visible?: boolean// 自定义列模板的插槽名slotName?: string// 日期格式化dateFormat?: string// 表头label: string// 字段名称prop?: string// 对应列的宽度width?: string | numberminWidth?: string | number// 对齐方式align?: 'left' | 'center' | 'right'fixed?: true | 'left' | 'right'showOverflowTooltip?: booleansortable?: boolean | 'custom'
}
2、table 组件使用
在
table
文件中下添加index.vue
并添加对应路由文件,编写以下代码
<script lang="ts" setup>
import ZTable from '@/components/Table/index'
import { ref } from 'vue'
import { ZTableOptions } from '@/components/Table/types'const tableData: any = ref([{fileName: '测试文件01',fileType: 'pdf',submitterName: '张三',submitTime: '2024-01-04 09:34:18'},{fileName: '测试文件02',fileType: 'png',submitterName: '李四',submitTime: '2024-01-04 11:26:57'}
])const propList: ZTableOptions[] = [{showOverflowTooltip: true,label: '文件名称',prop: 'fileName',minWidth: 130,align: 'left'},{showOverflowTooltip: true,label: '文件类型',prop: 'fileType',minWidth: 130,align: 'left'},{label: '上传人',prop: 'submitterName',minWidth: 150,showOverflowTooltip: true},{label: '上传时间',prop: 'submitTime',minWidth: 160}
]
</script><template><div><z-table :propList="propList" :data="tableData" :operation="false"></z-table></div>
</template><style scoped lang="scss">
</style>
3、table 效果图
总结
通过以上的介绍和代码实例,我们可以看到 Vue3 提供了更多的特性和优化,让我们更加方便地开发业务组件。在实际开发中,我们可以根据实际需求选择合适的组件开发方式,并通过 Vue3 的特性来提升开发效率。希望本文能够帮助到你在 Vue3 开发中的业务组件开发。上文中的配置代码可在 github
仓库中直接 copy
,仓库路径:https://github.com/SmallTeddy/ProjectConstructionHub。