diff --git a/devui/breadcrumb/__tests__/breadcrumb.spec.ts b/devui/breadcrumb/__tests__/breadcrumb.spec.ts new file mode 100644 index 0000000000000000000000000000000000000000..f05cf80d70b205cc2d6e103c1dd970cef04f98c0 --- /dev/null +++ b/devui/breadcrumb/__tests__/breadcrumb.spec.ts @@ -0,0 +1,55 @@ +import { mount } from '@vue/test-utils' +import DBreadcrumb from '../src/breadcrumb' +import DBreadcrumbItem from '../src/breadcrumb-item' + +describe('breadcrumb', () => { + it('should breadcrumb display correctly', () => { + const wrapper = mount({ + components: { + DBreadcrumb, + DBreadcrumbItem + }, + template: ` + + DevUI + + + Breadcrumb + + ` + }) + const items = wrapper.findAll('.devui-breadcrumb-item') + const separators = wrapper.findAll('.devui-breadcrumb-separator') + expect(items.length).toBe(2) + expect(separators.length).toBe(2) + }) + it('should separator support custom', () => { + const wrapper = mount({ + components: { + DBreadcrumb, + DBreadcrumbItem + }, + template: ` + + A + + ` + }) + expect(wrapper.find('.devui-breadcrumb-separator').text()).toBe('?') + }) + + it('should `to` work correctly', () => { + const wrapper = mount({ + components: { + DBreadcrumb, + DBreadcrumbItem + }, + template: ` + + A + + ` + }) + expect(wrapper.find('.is-link')).toBeTruthy() + }) +}) diff --git a/devui/breadcrumb/src/breadcrumb-item-types.ts b/devui/breadcrumb/src/breadcrumb-item-types.ts index 04542fad750a46614191d744c0e68a15b24cb422..a118789c0dfba2cdb45d2128fd0a244a7220ef1b 100644 --- a/devui/breadcrumb/src/breadcrumb-item-types.ts +++ b/devui/breadcrumb/src/breadcrumb-item-types.ts @@ -26,6 +26,20 @@ export const breadcrumbItemProps = { isSearch: { type: Boolean, dafault: false + }, + /** + * 路由跳转对象,同 vue-router 的 to + */ + to: { + type: [String, Object] as PropType>, + default: '' + }, + /** + * 在使用 to 进行路由跳转时,启用 replace 将不会向 history 添加新记录 + */ + replace: { + type: Boolean, + default: false } } as const diff --git a/devui/breadcrumb/src/breadcrumb-item.scss b/devui/breadcrumb/src/breadcrumb-item.scss index dd06a51aa8420085696847f4577bba91ee02c269..5c3a604685145422edde0ea44ec1e0bee8dc9d51 100644 --- a/devui/breadcrumb/src/breadcrumb-item.scss +++ b/devui/breadcrumb/src/breadcrumb-item.scss @@ -30,6 +30,15 @@ color $devui-animation-duration-slow $devui-animation-ease-in-out-smooth; } + + .is-link { + cursor: pointer; + + &:hover { + color: $devui-text; + text-decoration: none; + } + } } .devui-breadcrumb-separator { diff --git a/devui/breadcrumb/src/breadcrumb-item.tsx b/devui/breadcrumb/src/breadcrumb-item.tsx index 39a2674a21fba7658b348db97c8b824b8a99eede..f8f1ff686f9fa5f973ad8512de8f311ea15aaa72 100644 --- a/devui/breadcrumb/src/breadcrumb-item.tsx +++ b/devui/breadcrumb/src/breadcrumb-item.tsx @@ -1,4 +1,11 @@ -import { defineComponent, inject } from 'vue' +import { + defineComponent, + inject, + onMounted, + onBeforeUnmount, + ref, + getCurrentInstance +} from 'vue' import { breadcrumbItemProps, @@ -11,13 +18,31 @@ export default defineComponent({ props: breadcrumbItemProps, setup(props: BreadcrumbItemProps, { slots }) { const separatorIcon = inject('separatorIcon') + const linkClass = props.to ? 'is-link' : '' + const link = ref(null) + const instance = getCurrentInstance() + const router = instance.appContext.config.globalProperties.$router + const handleClickLink = () => { + if (!props.to || !router) return + props.replace ? router.replace(props.to) : router.push(props.to) + } + onMounted(() => { + link.value.addEventListener('click', handleClickLink) + }) + + onBeforeUnmount(() => { + link.value.removeEventListener('click', handleClickLink) + }) + return () => { const renderBreadcrumbSperator = () => { return {separatorIcon} } return (
- {slots?.default()} + + {slots?.default()} + {renderBreadcrumbSperator()}
) diff --git a/devui/breadcrumb/src/breadcrumb-types.ts b/devui/breadcrumb/src/breadcrumb-types.ts index f8d43be8c3b06343c891aaa22d5d33cac4cd8998..caebf81bf3e903663ea1946f586e2925af6e3859 100644 --- a/devui/breadcrumb/src/breadcrumb-types.ts +++ b/devui/breadcrumb/src/breadcrumb-types.ts @@ -5,6 +5,8 @@ export interface SourceConfig { link?: string // 跳转的路径 target?: string // 规定在何处打开链接文档 noNavigation?: boolean // 链接是否不可跳转,一般用于当前所处位置不可跳转的配置 + linkType?: 'hrefLink' | 'routerLink' // 链接类型,默认为'hrefLink'方式,可选'hrefLink' 或 'routerLink' + replace: boolean // 在使用 to 进行路由跳转时,启用 replace 将不会向 history 添加新记录 } export const breadcrumbProps = { diff --git a/devui/breadcrumb/src/breadcrumb.tsx b/devui/breadcrumb/src/breadcrumb.tsx index 0da81a2945e7805bb4276a664fe65abf5d6f3a9f..6b5ffeb24d2c3eef01f5af35e43ff5e71bfbaf28 100644 --- a/devui/breadcrumb/src/breadcrumb.tsx +++ b/devui/breadcrumb/src/breadcrumb.tsx @@ -18,15 +18,28 @@ export default defineComponent({ const separatorIcon = getPropsSlot(slots, props, 'separatorIcon') ?? '/' provide('separatorIcon', separatorIcon) + const renderBreadcrumbItemRouted = (item) => { + return ( + + {item.title} + + ) + } const renderBreadItemList = (source: SourceConfig[]) => { return source.map((item: SourceConfig) => { + if (!item.noNavigation && item.linkType === 'routerLink') { + return renderBreadcrumbItemRouted(item) + } return ( - {!item.noNavigation ? ( + {/* hrefLink */} + {!item.noNavigation && + (!item.linkType || item.linkType === 'hrefLink') ? ( {item.title} ) : null} + {/* normal */} {item.noNavigation ? {item.title} : null} ) diff --git a/docs/components/breadcrumb/index.md b/docs/components/breadcrumb/index.md index 2289ae81233295cb21ba0883e0bcec576b49aa5c..243c160b98357b89d99788830ec172e90f96cdc4 100644 --- a/docs/components/breadcrumb/index.md +++ b/docs/components/breadcrumb/index.md @@ -14,6 +14,7 @@ ```vue