-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: ✨️新增获取当前实例、下拉加载更多、分页拉取数据钩子,新增列表组件
- Loading branch information
Showing
18 changed files
with
457 additions
and
42 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -37,7 +37,7 @@ withDefaults( | |
scrollbar: boolean | ||
}>(), | ||
{ | ||
scrollbar: false, | ||
scrollbar: true, | ||
}, | ||
) | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,133 @@ | ||
<!-- | ||
* 列表组件 | ||
--> | ||
<template> | ||
<div class="gc-list"> | ||
<div class="gc-list__wrapper"> | ||
<a | ||
v-for="(item, index) in list" | ||
:key="index" | ||
href="javascript:void(0)" | ||
class="gc-list__item is-active:text-[#26224e] is-active:bg-white is-active:shadow-[5px_15px_30px_0px_#f0f0f0] last:border-b-0 hover:bg-white hover:text-[#26224e] hover:shadow-[5px_15px_30px_0px_#f0f0f0]" | ||
:class="{ | ||
'is-active': currentIndex === getObjectAttrValue(item, options.key), | ||
}" | ||
:draggable="draggable" | ||
@click="handleChangeItem(item)" | ||
@click.right="handleContextMenu($event, item)" | ||
> | ||
<slot :item="item" :index="index"> | ||
{{ getObjectAttrValue(item, options.label) }} | ||
</slot> | ||
</a> | ||
<el-empty v-if="isEmpty" :image-size="60" description="暂无数据" /> | ||
</div> | ||
</div> | ||
</template> | ||
<script> | ||
import { useCurrentInstance } from '@/hooks' | ||
import { get as getObjectAttrValue } from 'lodash' | ||
import { computed, nextTick, ref } from 'vue' | ||
|
||
export default { | ||
name: 'GcList', | ||
props: { | ||
list: { | ||
type: Array, | ||
default: () => [], | ||
}, | ||
options: { | ||
type: Object, | ||
default: () => ({ | ||
// 主键key字段 | ||
key: 'id', | ||
// 展示内容字段 | ||
label: 'name', | ||
}), | ||
}, | ||
// item是否可以拖拽 | ||
draggable: { | ||
type: Boolean, | ||
default: false, | ||
}, | ||
// 切换标签前的回调函数,返回 false 可阻止切换,支持返回 Promise | ||
beforeChange: { | ||
type: Function, | ||
default: null, | ||
}, | ||
}, | ||
emits: ['click-item', 'change', 'context-menu'], | ||
setup(props, { emit }) { | ||
const { $is } = useCurrentInstance() | ||
const { isFunction, isAsyncFunction } = $is | ||
|
||
const currentIndex = ref('') | ||
|
||
const isEmpty = computed(() => { | ||
return props.list.length === 0 | ||
}) | ||
|
||
// 切换item选择 | ||
const handleChangeItem = async (item) => { | ||
emit('click-item', item) | ||
|
||
const index = props.list.findIndex((listItem) => { | ||
return getObjectAttrValue(listItem, props.options.key) === getObjectAttrValue(item, props.options.key) | ||
}) | ||
|
||
const value = getObjectAttrValue(props.list[index], props.options.key) | ||
|
||
if (isFunction(props.beforeChange)) { | ||
let changeConfirm | ||
|
||
if (isAsyncFunction(props.beforeChange)) { | ||
await new Promise((resolve) => { | ||
props | ||
.beforeChange(index, item, value) | ||
.then((status) => { | ||
changeConfirm = status | ||
resolve() | ||
}) | ||
.catch(() => { | ||
changeConfirm = false | ||
resolve() | ||
}) | ||
}) | ||
} else { | ||
changeConfirm = props.beforeChange(index, item, value) | ||
} | ||
|
||
if (changeConfirm === false) { | ||
return | ||
} | ||
|
||
if (index !== -1) { | ||
currentIndex.value = value | ||
emit('change', currentIndex.value, props.list[index]) | ||
} | ||
} else { | ||
currentIndex.value = value | ||
emit('change', currentIndex.value, props.list[index]) | ||
} | ||
} | ||
|
||
// 鼠标右键点击 | ||
const handleContextMenu = (event, item) => { | ||
handleChangeItem(item) | ||
nextTick(() => { | ||
emit('context-menu', event, currentIndex.value, item) | ||
}) | ||
} | ||
|
||
return { | ||
getObjectAttrValue, | ||
currentIndex, | ||
isEmpty, | ||
handleChangeItem, | ||
handleContextMenu, | ||
} | ||
}, | ||
} | ||
</script> | ||
|
||
<style scoped></style> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
export * from './modules/useCurrentInstance.ts' | ||
export * from './modules/useLoadMore.ts' | ||
export * from './modules/usePageList.ts' |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,47 @@ | ||
/* | ||
* @description: 当前组件实例hooks,用以提供常用工具等 | ||
*/ | ||
|
||
import type { ComponentInternalInstance, ComponentPublicInstance } from 'vue' | ||
import { getCurrentInstance } from 'vue' | ||
import { useRoute, useRouter } from 'vue-router' | ||
|
||
// 定义 proxy 上的自定义属性类型 | ||
interface CustomProperties { | ||
$api: any | ||
$HTTP: any | ||
$HTTP_CODE: any | ||
$dict: any | ||
$is: any | ||
$date: any | ||
} | ||
|
||
export const useCurrentInstance = () => { | ||
const router = useRouter() | ||
const route = useRoute() | ||
|
||
const currentInstance = getCurrentInstance() | ||
|
||
if (!currentInstance) { | ||
throw new Error('useCurrentInstance must be called within a setup function') | ||
} | ||
|
||
const { proxy } = currentInstance as ComponentInternalInstance & { proxy: ComponentPublicInstance & CustomProperties } | ||
|
||
const { $api, $HTTP, $HTTP_CODE, $dict, $is, $date } = proxy | ||
|
||
// console.log('useCurrentInstance', currentInstance, proxy, $api, $HTTP, $HTTP_CODE, $dict, $is, $date) | ||
|
||
return { | ||
router, | ||
route, | ||
currentInstance, | ||
proxy, | ||
$api, | ||
$HTTP, | ||
$HTTP_CODE, | ||
$dict, | ||
$is, | ||
$date, | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,67 @@ | ||
/** | ||
* @description: 加载更多 | ||
*/ | ||
import { debounce } from 'lodash-es' | ||
import { onActivated, onBeforeUnmount, onDeactivated } from 'vue' | ||
|
||
interface UseLoadMoreOptions { | ||
type?: 'top' | 'bottom' | 'both' | ||
scrollTopCallback?: () => void | ||
scrollBottomCallback?: () => void | ||
container?: HTMLElement | ||
distance?: number | ||
} | ||
|
||
export const useLoadMore = (options: UseLoadMoreOptions = {}) => { | ||
const { | ||
type = 'both', | ||
scrollTopCallback, | ||
scrollBottomCallback, | ||
container = document.documentElement, | ||
distance = 0, | ||
} = options | ||
|
||
// 判断滚动条是否滚动到顶部 | ||
const isScrollTop = (distance: number = 0) => { | ||
const scrollTop = container.scrollTop | ||
return scrollTop - distance <= 0 | ||
} | ||
|
||
// 判断滚动条是否滚动到底部 | ||
const isScrollBottom = (distance: number = 0) => { | ||
const scrollHeight = container.scrollHeight | ||
const scrollTop = container.scrollTop | ||
const clientHeight = container.clientHeight | ||
return scrollHeight - distance <= scrollTop + clientHeight | ||
} | ||
|
||
// 滚动监听回调 | ||
const handleScroll = debounce(() => { | ||
if (['top', 'both'].includes(type) && isScrollTop(distance)) { | ||
scrollTopCallback?.() | ||
} | ||
|
||
if (['bottom', 'both'].includes(type) && isScrollBottom(distance)) { | ||
scrollBottomCallback?.() | ||
} | ||
}, 300) | ||
|
||
container.addEventListener('scroll', handleScroll) | ||
|
||
onBeforeUnmount(() => { | ||
container.removeEventListener('scroll', handleScroll) | ||
}) | ||
|
||
onActivated(() => { | ||
container.addEventListener('scroll', handleScroll) | ||
}) | ||
|
||
onDeactivated(() => { | ||
container.removeEventListener('scroll', handleScroll) | ||
}) | ||
|
||
return { | ||
isScrollTop, | ||
isScrollBottom, | ||
} | ||
} |
Oops, something went wrong.