feat(components): [tour] target prop add more type (#15578)

* feat(components): [tour] target prop add more type

* docs(components): [tour] target prop add description

* docs(components): [tour] add example and version tag
This commit is contained in:
赵添
2024-01-19 11:46:49 +08:00
committed by GitHub
parent 1d2029ea8f
commit a4c17ee50f
5 changed files with 96 additions and 25 deletions

View File

@@ -57,6 +57,16 @@ tour/indicator
:::
## Target
Various parameter passing types of target. The string and Function types are supported since ^(2.5.2).
:::demo
tour/target
:::
## Tour API
:::tip
@@ -98,21 +108,21 @@ tour-step component configuration with the same name has higher priority
### TourStep Attributes
| Property | Description | Type | Default |
| ------------------------ | ------------------------------------------------------------------------------------------------------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------- |
| target | get the element the guide card points to. Empty makes it show in center of screen | `HTMLElement` | - |
| show-arrow | whether to show the arrow | `boolean` | `true` |
| title | title | `string` | - |
| description | description | `string` | - |
| placement | position of the guide card relative to the target element | ^[enum]`'top' \| 'top-start' \| 'top-end' \| 'bottom' \| 'bottom-start' \| 'bottom-end' \| 'left' \| 'left-start' \| 'left-end' \| 'right' \| 'right-start' \| 'right-end'` | `bottom` |
| content-style | custom style for content | `CSSProperties` | - |
| mask | whether to enable masking, change mask style and fill color by pass custom props | `boolean` \| ^[Object]`{ style?: CSSProperties; color?: string; }` | `true` |
| type | type, affects the background color and text color | `default` \| `primary` | `default` |
| next-button-props | properties of the Next button | ^[Object]`{ children: VueNode \| string; onClick: Function }` | - |
| prev-button-props | properties of the previous button | ^[Object]`{ children: VueNode \| string; onClick: Function }` | - |
| scroll-into-view-options | support pass custom scrollIntoView options, the default follows the `scrollIntoViewOptions` property of Tour | `boolean` \| `ScrollIntoViewOptions` | - |
| show-close | whether to show a close button | `boolean` | `true` |
| close-icon | custom close icon, default is Close | `string` \| `Component` | - |
| Property | Description | Type | Default |
| ------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------- |
| target | get the element the guide card points to. Empty makes it show in center of screen. the string and Function types are supported since ^(2.5.2). the string type is selectors of document.querySelector. | `HTMLElement` \| `string` \| ^[Function]`() => HTMLElement` | - |
| show-arrow | whether to show the arrow | `boolean` | `true` |
| title | title | `string` | - |
| description | description | `string` | - |
| placement | position of the guide card relative to the target element | ^[enum]`'top' \| 'top-start' \| 'top-end' \| 'bottom' \| 'bottom-start' \| 'bottom-end' \| 'left' \| 'left-start' \| 'left-end' \| 'right' \| 'right-start' \| 'right-end'` | `bottom` |
| content-style | custom style for content | `CSSProperties` | - |
| mask | whether to enable masking, change mask style and fill color by pass custom props | `boolean` \| ^[Object]`{ style?: CSSProperties; color?: string; }` | `true` |
| type | type, affects the background color and text color | `default` \| `primary` | `default` |
| next-button-props | properties of the Next button | ^[Object]`{ children: VueNode \| string; onClick: Function }` | - |
| prev-button-props | properties of the previous button | ^[Object]`{ children: VueNode \| string; onClick: Function }` | - |
| scroll-into-view-options | support pass custom scrollIntoView options, the default follows the `scrollIntoViewOptions` property of Tour | `boolean` \| `ScrollIntoViewOptions` | - |
| show-close | whether to show a close button | `boolean` | `true` |
| close-icon | custom close icon, default is Close | `string` \| `Component` | - |
### TourStep slots

View File

@@ -0,0 +1,36 @@
<template>
<el-button type="primary" @click="open = true">Begin Tour</el-button>
<el-divider />
<el-space>
<el-button id="btn1">upload</el-button>
<el-button id="btn2" type="primary">save</el-button>
<el-button ref="btnRef" :icon="MoreFilled" />
</el-space>
<el-tour v-model="open">
<el-tour-step
target="#btn1"
title="Upload File"
description="Put you files here."
/>
<el-tour-step :target="el" title="Save" description="Save your changes" />
<el-tour-step
:target="btnRef?.$el"
title="Other Actions"
description="Click to see other"
/>
</el-tour>
</template>
<script setup lang="ts">
import { ref } from 'vue'
import { MoreFilled } from '@element-plus/icons-vue'
import type { ButtonInstance } from 'element-plus'
const el = () => document.querySelector<HTMLElement>('#btn2')
const btnRef = ref<ButtonInstance>()
const open = ref(false)
</script>

View File

@@ -18,7 +18,14 @@ import {
offset as offsetMiddelware,
shift,
} from '@floating-ui/dom'
import { hasOwn, isArray, isClient, keysOf } from '@element-plus/utils'
import {
hasOwn,
isArray,
isClient,
isFunction,
isString,
keysOf,
} from '@element-plus/utils'
import type {
CSSProperties,
@@ -40,7 +47,9 @@ import type {
} from '@floating-ui/dom'
export const useTarget = (
target: Ref<HTMLElement | null | undefined>,
target: Ref<
string | HTMLElement | (() => HTMLElement | null) | null | undefined
>,
open: Ref<boolean>,
gap: Ref<TourGap>,
mergedMask: Ref<TourMask>,
@@ -48,15 +57,28 @@ export const useTarget = (
) => {
const posInfo: Ref<PosInfo | null> = ref(null)
const getTargetEl = () => {
let targetEl: HTMLElement | null | undefined
if (isString(target.value)) {
targetEl = document.querySelector<HTMLElement>(target.value)
} else if (isFunction(target.value)) {
targetEl = target.value()
} else {
targetEl = target.value
}
return targetEl
}
const updatePosInfo = () => {
if (!target.value || !open.value) {
const targetEl = getTargetEl()
if (!targetEl || !open.value) {
posInfo.value = null
return
}
if (!isInViewPort(target.value) && open.value) {
target.value.scrollIntoView(scrollIntoViewOptions.value)
if (!isInViewPort(targetEl) && open.value) {
targetEl.scrollIntoView(scrollIntoViewOptions.value)
}
const { left, top, width, height } = target.value.getBoundingClientRect()
const { left, top, width, height } = targetEl.getBoundingClientRect()
posInfo.value = {
left,
top,
@@ -104,8 +126,9 @@ export const useTarget = (
})
const triggerTarget = computed(() => {
if (!mergedMask.value || !target.value || !window.DOMRect) {
return target.value || undefined
const targetEl = getTargetEl()
if (!mergedMask.value || !targetEl || !window.DOMRect) {
return targetEl || undefined
}
return {

View File

@@ -8,7 +8,9 @@ export const tourStepProps = buildProps({
* @description get the element the guide card points to. empty makes it show in center of screen
*/
target: {
type: definePropType<HTMLElement | null>(Object),
type: definePropType<
string | HTMLElement | (() => HTMLElement | null) | null
>([String, Object, Function]),
},
/**
* @description the title of the tour content

View File

@@ -29,7 +29,7 @@ export interface PosInfo {
}
export interface UsedTourStepProps {
target?: HTMLElement | null
target?: string | HTMLElement | (() => HTMLElement | null) | null
showArrow?: boolean
placement?: Placement
contentStyle?: CSSProperties