forked from opentiny/tiny-vue
fix(mobile-first): fix mobile-first components bugs (#1426)
This commit is contained in:
parent
f08fb98c17
commit
c7618314f2
|
@ -25,6 +25,7 @@
|
|||
<!-- 预览 -->
|
||||
<!-- modeState.demoId === 'preview-in-dialog' 修复preview-in-dialog demo弹窗内容被遮罩层遮挡 -->
|
||||
<div
|
||||
:id="state.currDemo?.demoId"
|
||||
class="rel px20 minh200"
|
||||
:style="{ transform: modeState.demoId === 'preview-in-dialog' ? '' : 'translateX(0)' }"
|
||||
>
|
||||
|
@ -34,8 +35,7 @@
|
|||
</div>
|
||||
</div>
|
||||
<!-- API表格 -->
|
||||
<div v-if="state.currApi.length" class="mt20 f24 fw-bold">组件API</div>
|
||||
|
||||
<div v-if="state.currApi?.length" class="mt20 f24 fw-bold">组件API</div>
|
||||
<div v-for="(oneGroup, idx) in state.currApi" :key="idx">
|
||||
<div class="mt20 f-r f-pos-start fw-bold">
|
||||
<div :id="oneGroup.name" class="f18">
|
||||
|
@ -53,8 +53,8 @@
|
|||
<table class="api-table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th width="15%">名称</th>
|
||||
<th width="20%">类型</th>
|
||||
<th width="20%">名称</th>
|
||||
<th width="15%">类型</th>
|
||||
<th width="20%">默认值</th>
|
||||
<th width="55%">说明</th>
|
||||
</tr>
|
||||
|
@ -102,10 +102,11 @@
|
|||
import { hooks } from '@opentiny/vue-common'
|
||||
import { Floatbar, TreeMenu, Button, Tooltip, ConfigProvider } from '@opentiny/vue'
|
||||
import { iconStarActive, iconSelect } from '@opentiny/vue-icon'
|
||||
import { menuData, apis, demoStr, demoVue, mds } from './resourceMobileFirst.js'
|
||||
import { useModeCtx } from './uses'
|
||||
import designAuroraConfig from '@opentiny/vue-design-aurora'
|
||||
import designSaasConfig from '@opentiny/vue-design-saas'
|
||||
import { menuData, demos, demoStr, demoVue, mds } from './resourceMobileFirst.js'
|
||||
import { useModeCtx } from './uses'
|
||||
import { getDemosConfig, getApisConfig } from './utils/componentsDoc'
|
||||
|
||||
const isSaasMode = process.env.VITE_TINY_THEME === 'saas'
|
||||
|
||||
|
@ -165,18 +166,12 @@ export default {
|
|||
|
||||
// 以下私有方法,无须传递给vue模板的。
|
||||
async function _switchPath() {
|
||||
// 查找API
|
||||
const apiModule = apis[`../../sites/demos/mobile-first/app/${modeState.pathName}/webdoc/${modeState.pathName}.js`]
|
||||
if (apiModule) {
|
||||
const module = await apiModule()
|
||||
const apiRoot = module.default
|
||||
state.currApi = apiRoot.apis
|
||||
state.demos = apiRoot.demos || []
|
||||
const demosModule =
|
||||
demos[`../../sites/demos/mobile-first/app/${modeState.pathName}/webdoc/${modeState.pathName}.js`]
|
||||
const demosConfig = await getDemosConfig(demosModule)
|
||||
state.demos = demosConfig.demos
|
||||
state.currDemo = state.demos.find((d) => d.demoId === modeState.demoId) || state.demos?.[0]
|
||||
} else {
|
||||
state.currApi = null
|
||||
state.currDemos = []
|
||||
}
|
||||
state.currApi = (await getApisConfig(modeState.pathName, 'mobile-first')).apis
|
||||
await _switchDemo()
|
||||
}
|
||||
async function _switchDemo() {
|
||||
|
|
|
@ -22,7 +22,7 @@
|
|||
<div v-html="state.currDemo?.desc['zh-CN']"></div>
|
||||
</div>
|
||||
<!-- 预览 -->
|
||||
<div class="rel px20">
|
||||
<div class="rel px20" :id="state.currDemo?.demoId">
|
||||
<div class="phone-container" @dblclick="fn.openInVscode(state.currDemo)">
|
||||
<div class="mobile-view-container">
|
||||
<component :is="state.comp"></component>
|
||||
|
@ -31,8 +31,7 @@
|
|||
</div>
|
||||
</div>
|
||||
<!-- API表格 -->
|
||||
<div v-if="state.currApi.length" class="mt20 f24 fw-bold">组件API</div>
|
||||
|
||||
<div v-if="state.currApi?.length" class="mt20 f24 fw-bold">组件API</div>
|
||||
<div v-for="(oneGroup, idx) in state.currApi" :key="idx">
|
||||
<div class="mt20 f-r f-pos-start fw-bold">
|
||||
<div :id="oneGroup.name" class="f18">
|
||||
|
@ -47,12 +46,11 @@
|
|||
<div class="f18 py28">
|
||||
{{ key }}
|
||||
</div>
|
||||
|
||||
<table class="api-table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th width="15%">名称</th>
|
||||
<th width="20%">类型</th>
|
||||
<th width="20%">名称</th>
|
||||
<th width="15%">类型</th>
|
||||
<th width="20%">默认值</th>
|
||||
<th width="55%">说明</th>
|
||||
</tr>
|
||||
|
@ -76,7 +74,7 @@
|
|||
</div>
|
||||
</div>
|
||||
<!-- 右边浮动所有的demos -->
|
||||
<tiny-floatbar v-if="state.demos.length > 0" class="!top120 !z1 !right25">
|
||||
<tiny-floatbar v-if="state.demos?.length > 0" class="!top120 !z1 !right25">
|
||||
<div class="f12 ofy-auto">
|
||||
<div
|
||||
v-for="demo in state.demos"
|
||||
|
@ -100,8 +98,9 @@
|
|||
import { hooks } from '@opentiny/vue-common'
|
||||
import { Floatbar, TreeMenu, Button, Tooltip } from '@opentiny/vue'
|
||||
import { iconStarActive, iconSelect } from '@opentiny/vue-icon'
|
||||
import { menuData, apis, demoStr, demoVue, mds } from './resourceMobile.js'
|
||||
import { menuData, demos, demoStr, demoVue, mds } from './resourceMobile.js'
|
||||
import { useModeCtx } from './uses'
|
||||
import { getDemosConfig, getApisConfig } from './utils/componentsDoc'
|
||||
|
||||
export default {
|
||||
props: {
|
||||
|
@ -157,18 +156,11 @@ export default {
|
|||
|
||||
// 以下私有方法,无须传递给vue模板的。
|
||||
async function _switchPath() {
|
||||
// 查找API
|
||||
const apiModule = apis[`../../sites/demos/mobile/app/${modeState.pathName}/webdoc/${modeState.pathName}.js`]
|
||||
if (apiModule) {
|
||||
const module = await apiModule()
|
||||
const apiRoot = module.default
|
||||
state.currApi = apiRoot.apis
|
||||
state.demos = apiRoot.demos || []
|
||||
const demosModule = demos[`../../sites/demos/mobile/app/${modeState.pathName}/webdoc/${modeState.pathName}.js`]
|
||||
const demosConfig = await getDemosConfig(demosModule)
|
||||
state.demos = demosConfig.demos
|
||||
state.currDemo = state.demos.find((d) => d.demoId === modeState.demoId) || state.demos?.[0]
|
||||
} else {
|
||||
state.currApi = null
|
||||
state.currDemos = []
|
||||
}
|
||||
state.currApi = (await getApisConfig(modeState.pathName, 'mobile')).apis
|
||||
await _switchDemo()
|
||||
}
|
||||
async function _switchDemo() {
|
||||
|
|
|
@ -24,7 +24,7 @@
|
|||
<div v-html="state.currDemo?.desc['zh-CN']"></div>
|
||||
</div>
|
||||
<!-- 预览 -->
|
||||
<div class="rel px20 py60 b-a bs-dotted">
|
||||
<div class="rel px20 py60 b-a bs-dotted" :id="state.currDemo?.demoId">
|
||||
<div class="abs top10 right10">
|
||||
<span title="点击在vscode中打开">
|
||||
<IconOpeninVscode @click="fn.openInVscode(state.currDemo)" class="ml12 cur-hand" />
|
||||
|
@ -154,21 +154,13 @@ import Loading from '@opentiny/vue-loading'
|
|||
import designSmbConfig from '@opentiny/vue-design-smb'
|
||||
import designAuroraConfig from '@opentiny/vue-design-aurora'
|
||||
import designSaasConfig from '@opentiny/vue-design-saas'
|
||||
import { menuData, apis, demoStr, demoVue, mds } from './resourcePc.js'
|
||||
import { menuData, demoStr, demoVue, mds, demos } from './resourcePc.js'
|
||||
import { useTheme, useModeCtx } from './uses'
|
||||
import { getDemosConfig, getPath, getApisConfig } from './utils/componentsDoc'
|
||||
import SvgTheme from './assets/theme.svg'
|
||||
|
||||
const isSaasMode = process.env.VITE_TINY_THEME === 'saas'
|
||||
|
||||
const getPath = (path) => {
|
||||
if (path.startsWith('grid-')) {
|
||||
return 'grid'
|
||||
} else if (path.startsWith('chart-')) {
|
||||
return 'chart'
|
||||
}
|
||||
return path
|
||||
}
|
||||
|
||||
export default {
|
||||
props: {
|
||||
showFixedMenu: Boolean
|
||||
|
@ -235,20 +227,14 @@ export default {
|
|||
// 以下私有方法,无须传递给vue模板的。
|
||||
async function _switchPath() {
|
||||
state.demoLoading = true
|
||||
// 查找API
|
||||
const apiModule = apis[`../../sites/demos/pc/app/${getPath(modeState.pathName)}/webdoc/${modeState.pathName}.js`]
|
||||
const componentName = getPath(modeState.pathName)
|
||||
// 查找demos配置
|
||||
const demosModule = demos[`../../sites/demos/pc/app/${componentName}/webdoc/${modeState.pathName}.js`]
|
||||
|
||||
if (apiModule) {
|
||||
const module = await apiModule()
|
||||
const apiRoot = module.default
|
||||
state.currApi = apiRoot.apis
|
||||
state.demos = apiRoot.demos || []
|
||||
const demosConfig = await getDemosConfig(demosModule)
|
||||
state.demos = demosConfig.demos
|
||||
state.currDemo = state.demos.find((d) => d.demoId === modeState.demoId) || state.demos?.[0]
|
||||
} else {
|
||||
state.currApi = null
|
||||
state.currDemos = []
|
||||
}
|
||||
|
||||
state.currApi = (await getApisConfig(componentName, 'pc')).apis
|
||||
await _switchDemo()
|
||||
}
|
||||
async function _switchDemo() {
|
||||
|
|
|
@ -8,8 +8,8 @@ import { cmpMenus } from '../../sites/demos/mobile/menus.js'
|
|||
export const demoStr = import.meta.glob('../../sites/demos/mobile/app/**/*.vue', { eager: false, as: 'raw' })
|
||||
export const demoVue = import.meta.glob('../../sites/demos/mobile/app/**/*.vue', { eager: false })
|
||||
|
||||
// api属性
|
||||
export const apis = import.meta.glob('../../sites/demos/mobile/app/*/webdoc/*.js', { eager: false })
|
||||
// demos配置
|
||||
export const demos = import.meta.glob('../../sites/demos/mobile/app/*/webdoc/*.js', { eager: false })
|
||||
|
||||
// 组件的md
|
||||
const allMD = import.meta.glob('../../sites/demos/mobile/app/*/webdoc/*.cn.md', { eager: true })
|
||||
|
|
|
@ -3,8 +3,8 @@ import { cmpMenus } from '../../sites/demos/mobile-first/menus.js'
|
|||
export const demoStr = import.meta.glob('../../sites/demos/mobile-first/app/**/*.vue', { eager: false, as: 'raw' })
|
||||
export const demoVue = import.meta.glob('../../sites/demos/mobile-first/app/**/*.vue', { eager: false })
|
||||
|
||||
// api属性
|
||||
export const apis = import.meta.glob('../../sites/demos/mobile-first/app/*/webdoc/*.js', { eager: false })
|
||||
// demos配置
|
||||
export const demos = import.meta.glob('../../sites/demos/mobile-first/app/*/webdoc/*.js', { eager: false })
|
||||
|
||||
// 组件的md
|
||||
const allMD = import.meta.glob('../../sites/demos/mobile-first/app/*/webdoc/*.cn.md', { eager: true })
|
||||
|
|
|
@ -8,8 +8,8 @@ import { cmpMenus } from '../../sites/demos/pc/menus.js'
|
|||
export const demoStr = import.meta.glob('../../sites/demos/pc/app/**/*.vue', { eager: false, as: 'raw' })
|
||||
export const demoVue = import.meta.glob('../../sites/demos/pc/app/**/*.vue', { eager: false })
|
||||
|
||||
// api属性
|
||||
export const apis = import.meta.glob('../../sites/demos/pc/app/*/webdoc/*.js', { eager: false })
|
||||
// demos配置
|
||||
export const demos = import.meta.glob('../../sites/demos/pc/app/*/webdoc/*.js', { eager: false })
|
||||
|
||||
// 组件的md
|
||||
const allMD = import.meta.glob('../../sites/demos/pc/app/*/webdoc/*.cn.md', { eager: true })
|
||||
|
|
|
@ -0,0 +1,40 @@
|
|||
export const apis = import.meta.glob('../../../sites/demos/apis/*.js', { eager: false })
|
||||
|
||||
export const getPath = (path) => {
|
||||
if (path.startsWith('grid-')) {
|
||||
return 'grid'
|
||||
} else if (path.startsWith('chart-')) {
|
||||
return 'chart'
|
||||
}
|
||||
return path
|
||||
}
|
||||
|
||||
export const getApisConfig = async (component, mode) => {
|
||||
const apisModule = apis[`../../../sites/demos/apis/${component}.js`]
|
||||
if (apisModule) {
|
||||
const apisConfig = (await apisModule()).default
|
||||
const demoKey = mode === 'mobile-first' ? 'mfDemo' : `${mode}Demo`
|
||||
const apis = apisConfig.apis.map((item) => {
|
||||
Object.keys(item).forEach((key) => {
|
||||
const apiItem = item[key]
|
||||
if (Array.isArray(apiItem)) {
|
||||
item[key] = apiItem
|
||||
.filter((i) => !i.mode || i.mode.includes(mode))
|
||||
.map((filterItem) => ({ ...filterItem, demoId: filterItem[demoKey] }))
|
||||
}
|
||||
})
|
||||
return item
|
||||
})
|
||||
return { ...apisConfig, apis }
|
||||
}
|
||||
return {}
|
||||
}
|
||||
|
||||
export const getDemosConfig = async (module) => {
|
||||
if (module) {
|
||||
const demosModule = await module()
|
||||
const demosConfig = demosModule.default
|
||||
return demosConfig
|
||||
}
|
||||
return { demos: [] }
|
||||
}
|
|
@ -200,8 +200,7 @@ export default {
|
|||
defaultValue: '',
|
||||
desc: {
|
||||
'zh-CN': '弹出框标题',
|
||||
'en-US':
|
||||
'Height between the pop-up box and the top of the window. The default value is 15% of the screen height'
|
||||
'en-US': 'Pop-up Box Title'
|
||||
},
|
||||
mode: ['pc'],
|
||||
pcDemo: 'custom-dialog-title'
|
||||
|
@ -212,7 +211,7 @@ export default {
|
|||
defaultValue: '15vh',
|
||||
desc: {
|
||||
'zh-CN': '设置弹出框距离窗口顶部的高度',
|
||||
'en-US': 'Display and close pop-up boxes'
|
||||
'en-US': 'Set the height of the popup from the top of the window'
|
||||
},
|
||||
mode: ['pc'],
|
||||
pcDemo: 'dialog-top-height'
|
||||
|
|
|
@ -565,7 +565,7 @@ export default {
|
|||
type: 'number | string',
|
||||
defaultValue: '',
|
||||
desc: {
|
||||
'zh-CN': '设置表格内容区域(不含表格头部,底部)的最小高度。',
|
||||
'zh-CN': '设置表格内容区域(不含表格头部,底部)的最小高度',
|
||||
'en-US': 'Set the minimum height of the table content area (excluding the table header and bottom).'
|
||||
},
|
||||
mode: ['pc', 'mobile-first'],
|
||||
|
@ -1019,6 +1019,7 @@ export default {
|
|||
{
|
||||
name: 'tooltip-config',
|
||||
type: 'IToolTipConfig',
|
||||
typeAnchorName: 'IToolTipConfig',
|
||||
defaultValue: '',
|
||||
desc: {
|
||||
'zh-CN': 'Grid 内置 tooltip 配置项,请参考 Tooltip 组件属性说明',
|
||||
|
@ -2497,7 +2498,7 @@ export default {
|
|||
type: '',
|
||||
defaultValue: '',
|
||||
desc: {
|
||||
'zh-CN': '在表格中新增数据。 ',
|
||||
'zh-CN': '在表格中新增数据',
|
||||
'en-US': ''
|
||||
},
|
||||
mode: ['mobile-first'],
|
||||
|
@ -3330,7 +3331,7 @@ export default {
|
|||
type: "'left' | 'center' | 'right'",
|
||||
defaultValue: "'left'",
|
||||
desc: {
|
||||
'zh-CN': '列对其方式',
|
||||
'zh-CN': '列对齐方式',
|
||||
'en-US': 'Column pair mode; The optional values for this property are left, center, right'
|
||||
},
|
||||
mode: ['pc'],
|
||||
|
@ -3416,7 +3417,7 @@ export default {
|
|||
type: 'IFormatConfig',
|
||||
defaultValue: '',
|
||||
desc: {
|
||||
'zh-CN': '开启该列数据异步渲染。',
|
||||
'zh-CN': '开启该列数据异步渲染',
|
||||
'en-US': 'Enable the asynchronous rendering of the column data'
|
||||
},
|
||||
mode: ['pc'],
|
||||
|
@ -3824,7 +3825,7 @@ export default {
|
|||
type: 'boolean',
|
||||
defaultValue: '',
|
||||
desc: {
|
||||
'zh-CN': '工具栏组件开启表格刷新功能。',
|
||||
'zh-CN': '工具栏组件开启表格刷新功能',
|
||||
'en-US': 'The table refresh function is enabled for the toolbar component.'
|
||||
},
|
||||
mode: ['pc'],
|
||||
|
@ -3898,7 +3899,7 @@ export default {
|
|||
type: '()=> void',
|
||||
defaultValue: '',
|
||||
desc: {
|
||||
'zh-CN': '点击个性化面板的重置按钮触发该事件。',
|
||||
'zh-CN': '点击个性化面板的重置按钮触发该事件',
|
||||
'en-US': 'Click the Reset button on the personalized panel to trigger the event.'
|
||||
},
|
||||
mode: ['pc'],
|
||||
|
@ -4030,6 +4031,21 @@ interface IToolbarConfig {
|
|||
code: string
|
||||
name: string
|
||||
}[]
|
||||
}
|
||||
`
|
||||
},
|
||||
{
|
||||
name: 'IToolTipConfig',
|
||||
type: 'type',
|
||||
code: `
|
||||
interface IToolTipConfig {
|
||||
placement?: 'top' | 'top-start' | 'top-end' | 'bottom' | 'bottom-start' | 'bottom-end' | 'left' | 'left-start' | 'left-end' | 'right' | 'right-start' | 'right-end'
|
||||
visibleArrow?: boolean
|
||||
enterable?: boolean
|
||||
type?: 'normal' | 'warning' | 'error' | 'info' | 'success'
|
||||
effect?: 'dark' | 'light'
|
||||
// 自定义提示内容
|
||||
contentMethod?: ()=> string | VNode
|
||||
}
|
||||
`
|
||||
},
|
||||
|
@ -4379,27 +4395,11 @@ interface IToolbarButtonClickArgs {
|
|||
code: `
|
||||
interface ICellClickArgs {
|
||||
// 当前行
|
||||
row: object,
|
||||
row: IRow,
|
||||
// 当前行的下标
|
||||
rowIndex: number
|
||||
// 当前列
|
||||
column: object
|
||||
// 当前列的下标
|
||||
columnIndex: number
|
||||
}
|
||||
`
|
||||
},
|
||||
{
|
||||
name: 'ICellClickArgs',
|
||||
type: 'type',
|
||||
code: `
|
||||
interface ICellClickArgs {
|
||||
// 当前行
|
||||
row: object
|
||||
// 当前行的下标
|
||||
rowIndex: number
|
||||
// 当前列
|
||||
column: object
|
||||
column: IColumnConfig
|
||||
// 当前列的下标
|
||||
columnIndex: number
|
||||
}
|
||||
|
@ -4411,7 +4411,7 @@ interface ICellClickArgs {
|
|||
code: `
|
||||
interface ICellContextMenuArgs {
|
||||
// 当前行
|
||||
row: object
|
||||
row: IRow
|
||||
}
|
||||
`
|
||||
},
|
||||
|
@ -4421,11 +4421,11 @@ interface ICellContextMenuArgs {
|
|||
code: `
|
||||
interface ICellArgs {
|
||||
//当前行
|
||||
row: object
|
||||
row: IRow
|
||||
//当前行的下标
|
||||
rowIndex: number
|
||||
// 当前列
|
||||
column: object
|
||||
column: IColumnConfig
|
||||
// 当前列的下标
|
||||
columnIndex: number
|
||||
}
|
||||
|
@ -4437,7 +4437,7 @@ interface ICellArgs {
|
|||
code: `
|
||||
interface ICurrentChangeArgs {
|
||||
// 当前行
|
||||
row: object
|
||||
row: IRow
|
||||
}
|
||||
`
|
||||
},
|
||||
|
@ -4447,9 +4447,9 @@ interface ICurrentChangeArgs {
|
|||
code: `
|
||||
interface IEditActivedArgs {
|
||||
// 当前行
|
||||
row: object
|
||||
row: IRow
|
||||
// 当前列
|
||||
column: object
|
||||
column: IColumnConfig
|
||||
}
|
||||
`
|
||||
},
|
||||
|
@ -4459,9 +4459,9 @@ interface IEditActivedArgs {
|
|||
code: `
|
||||
interface IEditClosedArgs {
|
||||
// 当前行
|
||||
row: object
|
||||
row: IRow
|
||||
// 当前列
|
||||
column: object
|
||||
column: IColumnConfig
|
||||
}
|
||||
`
|
||||
},
|
||||
|
@ -4471,9 +4471,9 @@ interface IEditClosedArgs {
|
|||
code: `
|
||||
interface IEditDisabledArgs {
|
||||
//当前行
|
||||
row: object
|
||||
row: IRow
|
||||
// 当前列
|
||||
column: object
|
||||
column: IColumnConfig
|
||||
}
|
||||
`
|
||||
},
|
||||
|
@ -4501,7 +4501,7 @@ interface IFooterCellClickArgs {
|
|||
// 当前单元格节点
|
||||
cell: HTMLElement
|
||||
// 当前列信息
|
||||
column: object
|
||||
column: IColumnConfig
|
||||
columnIndex: number
|
||||
}
|
||||
`
|
||||
|
@ -4518,7 +4518,7 @@ interface IContextMenuArgs {
|
|||
// 当前单元格节点
|
||||
cell: HTMLElement
|
||||
// 当前列信息
|
||||
column: object
|
||||
column: IColumnConfig
|
||||
columnIndex: number
|
||||
// 配置清除等功能信息
|
||||
options: object[]
|
||||
|
@ -4539,7 +4539,7 @@ interface IFooterCellDblClickArgs {
|
|||
// 当前单元格节点
|
||||
cell: HTMLElement
|
||||
// 当前列信息
|
||||
column: object
|
||||
column: IColumnConfig
|
||||
columnIndex: number
|
||||
}
|
||||
`
|
||||
|
@ -4556,7 +4556,7 @@ interface IHeaderCellClickArgs {
|
|||
// 点击表头单元格
|
||||
cell: HTMLElement
|
||||
// 当前列信息
|
||||
column: object
|
||||
column: IColumnConfig
|
||||
columnIndex: number
|
||||
// 当前点击节点过滤标识
|
||||
triggerFilter: boolean
|
||||
|
@ -4571,7 +4571,7 @@ interface IHeaderCellClickArgs {
|
|||
code: `
|
||||
interface IHeaderCellDblClickArgs {
|
||||
// 列数据
|
||||
column: object
|
||||
column: IColumnConfig
|
||||
// 列索引
|
||||
columnIndex: number
|
||||
// table组件 vue实例
|
||||
|
@ -4589,7 +4589,7 @@ interface IResizableChangeArgs {
|
|||
// table组件的vue 实例
|
||||
$table: Component,
|
||||
// 列配置信息
|
||||
column: object
|
||||
column: IColumnConfig
|
||||
// 拖动列的索引
|
||||
columnIndex: number
|
||||
// 是否固定列
|
||||
|
|
|
@ -10,7 +10,7 @@ export default {
|
|||
type: 'Component',
|
||||
defaultValue: '',
|
||||
desc: {
|
||||
'zh-CN': '设置IP段之间的分隔符,默认图标为IconDotIpv4',
|
||||
'zh-CN': '设置 ip 段之间的分隔符,默认图标为 IconDotIpv4 ',
|
||||
'en-US': 'Set the separator between IP segments, default icon is icon-dot-ipv4'
|
||||
},
|
||||
mode: ['pc'],
|
||||
|
|
|
@ -369,6 +369,19 @@ export default {
|
|||
pcDemo: 'basic-usage',
|
||||
mfDemo: ''
|
||||
},
|
||||
{
|
||||
name: 'change-compat',
|
||||
type: 'boolean',
|
||||
defaultValue: 'false',
|
||||
desc: {
|
||||
'zh-CN': '设置除加减按钮及直接输入数值之外,值改变后是否触发change事件',
|
||||
'en-US':
|
||||
'Set whether to trigger the change event after the value is changed, except for the plus and minus buttons and direct input of values.'
|
||||
},
|
||||
mode: ['pc', 'mobile-first', 'mobile'],
|
||||
pcDemo: 'change-event',
|
||||
mfDemo: ''
|
||||
},
|
||||
{
|
||||
name: 'validate-event',
|
||||
type: 'Boolean',
|
||||
|
|
|
@ -1,7 +1,10 @@
|
|||
<template>
|
||||
<div>
|
||||
<div>场景1:单选 + 可搜索</div>
|
||||
<br />
|
||||
<tiny-select
|
||||
ref="select"
|
||||
v-model="value"
|
||||
v-model="value1"
|
||||
placeholder="请选择"
|
||||
filterable
|
||||
:filter-method="filter"
|
||||
|
@ -17,6 +20,31 @@
|
|||
>
|
||||
</tiny-option>
|
||||
</tiny-select>
|
||||
<br />
|
||||
<br />
|
||||
<div>场景2:多选 + 折叠tag + 可搜索</div>
|
||||
<br />
|
||||
<tiny-select
|
||||
ref="select"
|
||||
v-model="value2"
|
||||
placeholder="请选择"
|
||||
multiple
|
||||
collapse-tags
|
||||
filterable
|
||||
:filter-method="filter"
|
||||
clearable
|
||||
title="标题"
|
||||
>
|
||||
<tiny-option
|
||||
v-for="item in options"
|
||||
v-show="!item.filter"
|
||||
:key="item.value"
|
||||
:label="item.label"
|
||||
:value="item.value"
|
||||
>
|
||||
</tiny-option>
|
||||
</tiny-select>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
|
@ -51,7 +79,8 @@ export default {
|
|||
label: '北京烤鸭'
|
||||
}
|
||||
],
|
||||
value: ''
|
||||
value1: '',
|
||||
value2: []
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
|
|
|
@ -0,0 +1,24 @@
|
|||
<template>
|
||||
<div id="demo-loading"></div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { Loading } from '@opentiny/vue'
|
||||
|
||||
export default {
|
||||
mounted() {
|
||||
Loading.service({
|
||||
background: '#19191960',
|
||||
text: '自定义遮罩层背景色',
|
||||
target: document.getElementById('demo-loading'),
|
||||
tiny_mode: 'mobile'
|
||||
})
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
#demo-loading {
|
||||
height: 100%;
|
||||
}
|
||||
</style>
|
|
@ -1,14 +1,17 @@
|
|||
<template>
|
||||
<div>
|
||||
<button @click="closeLoading">close Loading</button>
|
||||
<div id="tiny-loading1" style="width: 100%; height: 120px"></div>
|
||||
<div class="demo-loading">
|
||||
<tiny-button type="secondary" @click="closeLoading">关闭 Loading</tiny-button>
|
||||
<div id="loading-box"></div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="jsx">
|
||||
import { Loading } from '@opentiny/vue'
|
||||
<script>
|
||||
import { Loading, Button } from '@opentiny/vue'
|
||||
|
||||
export default {
|
||||
components: {
|
||||
TinyButton: Button
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
loadingInstance: null
|
||||
|
@ -17,7 +20,7 @@ export default {
|
|||
mounted() {
|
||||
this.loadingInstance = Loading.service({
|
||||
tiny_mode: 'mobile',
|
||||
target: document.getElementById('tiny-loading1')
|
||||
target: document.getElementById('loading-box')
|
||||
})
|
||||
},
|
||||
methods: {
|
||||
|
@ -27,3 +30,10 @@ export default {
|
|||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
#loading-box {
|
||||
height: 200px;
|
||||
margin-top: 16px;
|
||||
}
|
||||
</style>
|
||||
|
|
|
@ -0,0 +1,29 @@
|
|||
<template>
|
||||
<div id="demo-loading"></div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { Loading } from '@opentiny/vue'
|
||||
|
||||
export default {
|
||||
mounted() {
|
||||
Loading.service({
|
||||
text: '自定义 loading 类名',
|
||||
customClass: 'my-loading',
|
||||
target: document.getElementById('demo-loading'),
|
||||
tiny_mode: 'mobile'
|
||||
})
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
#demo-loading {
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
:deep(.my-loading) {
|
||||
color: #fff;
|
||||
background: rgba(0, 0, 0, 0.5);
|
||||
}
|
||||
</style>
|
|
@ -0,0 +1,61 @@
|
|||
<template>
|
||||
<div class="demo-loading">
|
||||
<tiny-button type="secondary" @click="handleClick" v-loading.lock.fullscreen="showLoading">
|
||||
指令方式加载全屏Loading
|
||||
</tiny-button>
|
||||
|
||||
<tiny-button type="secondary" @click="handleClick2"> 静态方法加载全屏Loading </tiny-button>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { Loading, Button } from '@opentiny/vue'
|
||||
|
||||
export default {
|
||||
components: {
|
||||
TinyButton: Button
|
||||
},
|
||||
directives: {
|
||||
loading: Loading.directive
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
showLoading: false
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
handleClick() {
|
||||
this.showLoading = true
|
||||
setTimeout(() => {
|
||||
this.showLoading = false
|
||||
}, 3000)
|
||||
},
|
||||
handleClick2() {
|
||||
const loading = this.$loading({
|
||||
lock: true,
|
||||
text: 'Loading',
|
||||
tiny_mode: 'mobile'
|
||||
})
|
||||
setTimeout(() => {
|
||||
loading.close()
|
||||
}, 3000)
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.demo-loading {
|
||||
padding: 30px;
|
||||
}
|
||||
|
||||
.demo-loading .tiny-mobile-button {
|
||||
width: 100%;
|
||||
margin-bottom: 30px;
|
||||
}
|
||||
|
||||
#demo-loading {
|
||||
width: 100px;
|
||||
height: 100px;
|
||||
}
|
||||
</style>
|
|
@ -0,0 +1,59 @@
|
|||
<template>
|
||||
<div class="demo-loading">
|
||||
<div id="loading-box0"></div>
|
||||
<div id="loading-box1"></div>
|
||||
<div id="loading-box2"></div>
|
||||
<div id="loading-box3"></div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { Loading } from '@opentiny/vue'
|
||||
|
||||
export default {
|
||||
mounted() {
|
||||
// mini 尺寸
|
||||
Loading.service({
|
||||
size: 'mini',
|
||||
text: 'mini 尺寸',
|
||||
target: '#loading-box0',
|
||||
tiny_mode: 'mobile'
|
||||
})
|
||||
|
||||
// small 尺寸
|
||||
Loading.service({
|
||||
size: 'small',
|
||||
text: 'small 尺寸',
|
||||
target: '#loading-box1',
|
||||
tiny_mode: 'mobile'
|
||||
})
|
||||
|
||||
// medium 尺寸
|
||||
Loading.service({
|
||||
size: 'medium',
|
||||
text: 'medium 尺寸',
|
||||
target: '#loading-box2',
|
||||
tiny_mode: 'mobile'
|
||||
})
|
||||
|
||||
// large 尺寸
|
||||
Loading.service({
|
||||
size: 'large',
|
||||
text: 'large 尺寸',
|
||||
target: '#loading-box3',
|
||||
tiny_mode: 'mobile'
|
||||
})
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.demo-loading div {
|
||||
height: 100px;
|
||||
border-bottom: 4px solid #fff;
|
||||
}
|
||||
|
||||
#loading-box3 {
|
||||
height: 150px;
|
||||
}
|
||||
</style>
|
|
@ -0,0 +1,26 @@
|
|||
<template>
|
||||
<div id="demo-loading"></div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { Loading } from '@opentiny/vue'
|
||||
import { iconLoading } from '@opentiny/vue-icon'
|
||||
|
||||
export default {
|
||||
mounted() {
|
||||
Loading.service({
|
||||
spinner: iconLoading(),
|
||||
text: '自定义loading图标',
|
||||
target: document.getElementById('demo-loading'),
|
||||
background: '#fff',
|
||||
tiny_mode: 'mobile'
|
||||
})
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
#demo-loading {
|
||||
height: 120px;
|
||||
}
|
||||
</style>
|
|
@ -0,0 +1,23 @@
|
|||
<template>
|
||||
<div id="demo-loading"></div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { Loading } from '@opentiny/vue'
|
||||
|
||||
export default {
|
||||
mounted() {
|
||||
Loading.service({
|
||||
text: '加载中...',
|
||||
tiny_mode: 'mobile',
|
||||
target: document.getElementById('demo-loading')
|
||||
})
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
#demo-loading {
|
||||
height: 120px;
|
||||
}
|
||||
</style>
|
|
@ -6,25 +6,171 @@ export default {
|
|||
demoId: 'base',
|
||||
name: {
|
||||
'zh-CN': '基础用法',
|
||||
'en-US': 'button type'
|
||||
'en-US': 'Basic usage'
|
||||
},
|
||||
desc: {
|
||||
'zh-CN': '<p>基础用法</p>',
|
||||
'en-US': '<p>button type</p>'
|
||||
'zh-CN': '<p>通过 <code>service</code> 方法显示 Loading ,再通过 <code>close</code> 方法关闭。</p>',
|
||||
'en-US':
|
||||
'<p>Use the <code>service</code> method to display Loading, then close it using the <code>close</code> method.</p>'
|
||||
},
|
||||
codeFiles: ['base.vue']
|
||||
},
|
||||
{
|
||||
demoId: 'type',
|
||||
demoId: 'spinner',
|
||||
name: {
|
||||
'zh-CN': '类型',
|
||||
'en-US': 'button type'
|
||||
'zh-CN': '自定义加载图标',
|
||||
'en-US': 'Custom Icon'
|
||||
},
|
||||
desc: {
|
||||
'zh-CN': '<p>类型</p>',
|
||||
'en-US': '<p>button type</p>'
|
||||
'zh-CN': '<p>通过 <code>spinner</code> 属性自定义加载图标。<p>',
|
||||
'en-US': '<p>Customize loading icon using the <code>spinner</code> attribute.</p>'
|
||||
},
|
||||
codeFiles: ['type.vue']
|
||||
codeFiles: ['spinner.vue']
|
||||
},
|
||||
{
|
||||
demoId: 'tip-text',
|
||||
name: {
|
||||
'zh-CN': '自定义加载提示',
|
||||
'en-US': 'Custom Tip'
|
||||
},
|
||||
desc: {
|
||||
'zh-CN': '<p>通过 <code>text</code> 自定义加载文字的提示文本。<p>',
|
||||
'en-US': '<p>Use <code>text</code> to customize loading tip. </p>'
|
||||
},
|
||||
codeFiles: ['tip-text.vue']
|
||||
},
|
||||
{
|
||||
demoId: 'background',
|
||||
name: {
|
||||
'zh-CN': '自定义遮罩背景色',
|
||||
'en-US': 'CUstom Mask Background'
|
||||
},
|
||||
desc: {
|
||||
'zh-CN': '<p>通过 <code>background</code> 自定义遮罩层背景颜色。<p>',
|
||||
'en-US': '<p>Use <code>background</code> property to customize background color of mask.</p>'
|
||||
},
|
||||
codeFiles: ['background.vue']
|
||||
},
|
||||
{
|
||||
demoId: 'custom-class',
|
||||
name: {
|
||||
'zh-CN': '自定义样式',
|
||||
'en-US': 'events'
|
||||
},
|
||||
desc: {
|
||||
'zh-CN': '<p>通过 <code>custom-class</code> 指定类名进行样式修改。<p>',
|
||||
'en-US': '<p>Specify the class name using <code>custom-class</code> to modify the style.</p>'
|
||||
},
|
||||
codeFiles: ['custom-class.vue']
|
||||
},
|
||||
{
|
||||
demoId: 'size',
|
||||
name: {
|
||||
'zh-CN': '尺寸',
|
||||
'en-US': 'Size'
|
||||
},
|
||||
desc: {
|
||||
'zh-CN':
|
||||
'<p>通过在 <code>Loading.service</code> 中设置 <code>size</code> 属性加载不同的大小尺寸,包括 <code>large</code> | <code>medium</code> | <code>small</code> | <code>mini</code> 四种不同大小。不设置时为默认尺寸。<p>',
|
||||
'en-US':
|
||||
'<p>By setting the <code>size</code> attribute in the Loading.service, different size dimensions can be loaded, including <code>large</code>, <code>medium</code>, <code>small</code> and <code>mini</code>. If not set, the default size will be used.</p>'
|
||||
},
|
||||
codeFiles: ['size.vue']
|
||||
},
|
||||
{
|
||||
demoId: 'global-registry.',
|
||||
name: {
|
||||
'zh-CN': '全局加载',
|
||||
'en-US': 'Global Registry'
|
||||
},
|
||||
desc: {
|
||||
'zh-CN': `<p>通过 <code>v-loading.lock.fullscreen</code> 指令方式或者服务方式进行全局加载,如需使用指令方式全局加载需要如下操作:
|
||||
<p>在 Vue 2 版本环境中添加 <code>Vue.use(Loading)</code>;</p><p>在Vue 3 版本环境中添加 <code>app.use(Loading)</code>.<p>`,
|
||||
'en-US': `<p>Global loading can be achieved through the <code>v-loading.lock.fullscreen</code> directive or service. To use the directive for global loading, follow these steps:</p><p>For Vue 2 environment, add <code>Vue.use(Loading)</code>;</p><p>For Vue 3 environment, add <code>app.use(Loading)</code>.</p>`
|
||||
},
|
||||
codeFiles: ['global-registry.vue']
|
||||
}
|
||||
],
|
||||
apis: [
|
||||
{
|
||||
name: 'Loading', // 组件名称展示使用
|
||||
type: 'loading', // API 类型
|
||||
properties: [
|
||||
{
|
||||
name: 'type',
|
||||
type: 'string',
|
||||
defaultValue: 'primary',
|
||||
desc: {
|
||||
'zh-CN': '<p>通过type设置不同的加载样式</p>',
|
||||
'en-US': 'display different button'
|
||||
},
|
||||
demoId: 'type'
|
||||
},
|
||||
{
|
||||
name: 'background',
|
||||
type: 'string',
|
||||
defaultValue: `'#0000004b'`,
|
||||
desc: {
|
||||
'zh-CN': '遮罩层背景色',
|
||||
'en-US': 'mask background color'
|
||||
},
|
||||
demoId: 'background'
|
||||
},
|
||||
{
|
||||
name: 'custom-class',
|
||||
type: 'string',
|
||||
defaultValue: '--',
|
||||
desc: {
|
||||
'zh-CN': '自定义类名',
|
||||
'en-US': 'Custom class name'
|
||||
},
|
||||
demoId: 'custom-class'
|
||||
},
|
||||
{
|
||||
name: 'spinner',
|
||||
type: 'Component',
|
||||
defaultValue: '--',
|
||||
desc: {
|
||||
'zh-CN': '自定义加载图标',
|
||||
'en-US': 'display different button'
|
||||
},
|
||||
demoId: 'spinner'
|
||||
},
|
||||
{
|
||||
name: 'target',
|
||||
type: 'DOM',
|
||||
defaultValue: 'document.body',
|
||||
desc: {
|
||||
'zh-CN':
|
||||
'需要覆盖的 DOM 节点。可传入一个 DOM 对象或字符串;若传入字符串,则会将其作为参数传入 document.querySelector 以获取到对应 DOM 节点',
|
||||
'en-US':
|
||||
'The DOM node to be targeted for coverage. It can be a DOM object or a string; if a string is passed, it will be used as a parameter for document.querySelector to obtain the corresponding DOM node'
|
||||
},
|
||||
demoId: 'base'
|
||||
}
|
||||
],
|
||||
method: [
|
||||
{
|
||||
name: 'close',
|
||||
type: '() => void',
|
||||
defaultValue: '',
|
||||
desc: {
|
||||
'zh-CN': '关闭 Loading',
|
||||
'en-US': 'close loading'
|
||||
},
|
||||
demoId: 'base'
|
||||
},
|
||||
{
|
||||
name: 'service',
|
||||
type: '() => Component',
|
||||
defaultValue: '',
|
||||
desc: {
|
||||
'zh-CN': '创建一个 Loading 组件实例并展示',
|
||||
'en-US': 'Create a Loading component instance and display it'
|
||||
},
|
||||
demoId: 'base'
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
|
@ -14,7 +14,7 @@
|
|||
|
||||
<script setup>
|
||||
import { ref } from 'vue'
|
||||
import { Alert as TinyAlert, Switch as TinySwitch, Modal } from '@opentiny/vue'
|
||||
import { Alert as TinyAlert, Switch as TinySwitch, Notify } from '@opentiny/vue'
|
||||
import { iconCloseCircle } from '@opentiny/vue-icon'
|
||||
|
||||
const show = ref(true)
|
||||
|
@ -22,6 +22,11 @@ const show = ref(true)
|
|||
const TinyIconCloseCircle = iconCloseCircle()
|
||||
|
||||
const close = () => {
|
||||
Modal.message('关闭了')
|
||||
Notify({
|
||||
type: 'success',
|
||||
message: '触发关闭事件',
|
||||
position: 'top-right',
|
||||
duration: 1000
|
||||
})
|
||||
}
|
||||
</script>
|
||||
|
|
|
@ -49,7 +49,7 @@ test('关闭按钮事件', async ({ page }) => {
|
|||
// 点击关闭后警告消失,自定义事件modalBox提示出现
|
||||
await close.click()
|
||||
await expect(alertWarning).not.toBeVisible()
|
||||
await expect(page.locator('.tiny-modal__box').getByText('关闭了')).toBeVisible()
|
||||
await expect(page.locator('.tiny-notify__content').getByText('触发关闭事件')).toBeVisible()
|
||||
})
|
||||
|
||||
test('不可关闭警告', async ({ page }) => {
|
||||
|
|
|
@ -13,7 +13,7 @@
|
|||
</template>
|
||||
|
||||
<script>
|
||||
import { Alert, Modal, Switch } from '@opentiny/vue'
|
||||
import { Alert, Notify, Switch } from '@opentiny/vue'
|
||||
import { iconCloseCircle } from '@opentiny/vue-icon'
|
||||
|
||||
export default {
|
||||
|
@ -29,7 +29,12 @@ export default {
|
|||
},
|
||||
methods: {
|
||||
close() {
|
||||
Modal.message('关闭了')
|
||||
Notify({
|
||||
type: 'success',
|
||||
message: '触发关闭事件',
|
||||
position: 'top-right',
|
||||
duration: 10000
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -9,7 +9,7 @@ test('文件选择前确认', async ({ page }) => {
|
|||
await upload.click()
|
||||
await page.locator('.tiny-modal').filter({ hasText: 'beforeAddFile 钩子函数' }).isVisible()
|
||||
|
||||
const confirmBtn = page.getByRole('button', { name: '确认' })
|
||||
const confirmBtn = page.getByRole('button', { name: '确定' })
|
||||
const [fileChooser] = await Promise.all([page.waitForEvent('filechooser'), confirmBtn.click()])
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-require-imports, @typescript-eslint/no-var-requires
|
||||
|
|
|
@ -9,12 +9,12 @@ test('手动上传', async ({ page }) => {
|
|||
const lists = page.locator('.tiny-upload-list__item')
|
||||
const [fileChooser] = await Promise.all([page.waitForEvent('filechooser'), upload.click()])
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-require-imports, @typescript-eslint/no-var-requires
|
||||
const path = require('node:path')
|
||||
const currentPath = path.resolve(__dirname, '测试.jpg')
|
||||
|
||||
await fileChooser.setFiles(currentPath)
|
||||
await expect(lists).toHaveText(/测试.jpg/)
|
||||
await server.click()
|
||||
await lists.waitFor({ state: 'hidden', timeout: 3000 })
|
||||
await expect(lists).toHaveCount(0)
|
||||
})
|
||||
|
|
|
@ -20,6 +20,7 @@ test('照片墙', async ({ page }) => {
|
|||
const dialogClose = page.getByRole('button', { name: 'Close' })
|
||||
const { width, height } = await first.boundingBox()
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-require-imports, @typescript-eslint/no-var-requires
|
||||
const path = require('node:path')
|
||||
const currentPath = path.resolve(__dirname, '测试.jpg')
|
||||
|
||||
|
@ -34,5 +35,5 @@ test('照片墙', async ({ page }) => {
|
|||
await first.hover()
|
||||
await delButton.click()
|
||||
await page.waitForTimeout(200)
|
||||
await li.isHidden()
|
||||
await first.isHidden()
|
||||
})
|
||||
|
|
|
@ -16,7 +16,7 @@ test('图片列表缩略图', async ({ page }) => {
|
|||
const path = require('node:path')
|
||||
const currentPath = path.resolve(__dirname, '测试.jpg')
|
||||
|
||||
await expect(width).toBeGreaterThanOrEqual(700)
|
||||
await expect(width).toBeGreaterThanOrEqual(height)
|
||||
await expect(height).toBeGreaterThanOrEqual(56)
|
||||
await expect(lists).toHaveCount(2)
|
||||
await fileChooser.setFiles(currentPath)
|
||||
|
|
|
@ -13,7 +13,7 @@ test('文件列表', async ({ page }) => {
|
|||
const path = require('node:path')
|
||||
const currentPath = path.resolve(__dirname, '测试.jpg')
|
||||
|
||||
await expect(width).toBeGreaterThanOrEqual(700)
|
||||
await expect(width).toBeGreaterThanOrEqual(height)
|
||||
await expect(height).toBeGreaterThanOrEqual(25, 0)
|
||||
await expect(items).toHaveCount(2)
|
||||
await expect(items).toHaveText([/test1/, /test2/])
|
||||
|
|
|
@ -9,11 +9,11 @@ test('个性化按钮点击事件', async ({ page }) => {
|
|||
await expect(
|
||||
page.getByText('点击了确认按钮{"sortType":"page","pageSize":10,"columns":[{"property":"name","order":nu')
|
||||
).toBeVisible()
|
||||
await page.getByRole('button', { name: '确认' }).click()
|
||||
await page.getByRole('button', { name: '确定' }).click()
|
||||
await page.locator('.tiny-grid-custom__setting-btn').click()
|
||||
await page.getByRole('button', { name: '重置' }).click()
|
||||
await expect(page.getByText('点击了重置按钮')).toBeVisible()
|
||||
await page.getByRole('button', { name: '确认' }).click()
|
||||
await page.getByRole('button', { name: '确定' }).nth(1).click()
|
||||
await page.getByRole('button', { name: '取消' }).click()
|
||||
await expect(page.getByText('点击了取消按钮undefined')).toBeVisible
|
||||
})
|
||||
|
|
|
@ -0,0 +1,50 @@
|
|||
<template>
|
||||
<tiny-grid :data="tableData" :edit-config="{ trigger: 'click', mode: 'cell' }">
|
||||
<tiny-grid-column type="index" width="60"></tiny-grid-column>
|
||||
<tiny-grid-column field="created_date" title="创建时间"></tiny-grid-column>
|
||||
<tiny-grid-column
|
||||
field="employees"
|
||||
title="人数"
|
||||
:editor="{ component: 'input' }"
|
||||
:equals="employeesEquals"
|
||||
></tiny-grid-column>
|
||||
<tiny-grid-column field="introduction" title="公司简介"></tiny-grid-column>
|
||||
</tiny-grid>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref } from 'vue'
|
||||
import { Grid as TinyGrid, GridColumn as TinyGridColumn } from '@opentiny/vue'
|
||||
|
||||
const tableData = ref([
|
||||
{
|
||||
id: '1',
|
||||
created_date: '2014-04-30 00:56:00',
|
||||
employees: 800,
|
||||
introduction: '公司技术和研发实力雄厚,是国家863项目的参与者,并被政府认定为“高新技术企业”。'
|
||||
},
|
||||
{
|
||||
id: '2',
|
||||
created_date: '2016-07-08 12:36:22',
|
||||
employees: 300,
|
||||
introduction: '公司技术和研发实力雄厚,是国家863项目的参与者,并被政府认定为“高新技术企业”。'
|
||||
},
|
||||
{
|
||||
id: '3',
|
||||
created_date: '2014-02-14 14:14:14',
|
||||
employees: 1300,
|
||||
introduction: '公司技术和研发实力雄厚,是国家863项目的参与者,并被政府认定为“高新技术企业”。'
|
||||
},
|
||||
{
|
||||
id: '4',
|
||||
created_date: '2013-01-13 13:13:13',
|
||||
employees: 360,
|
||||
introduction: '公司技术和研发实力雄厚,是国家863项目的参与者,并被政府认定为“高新技术企业”。'
|
||||
}
|
||||
])
|
||||
|
||||
const employeesEquals = ({ value, originalValue }) => {
|
||||
// 如果数字相等就返回true
|
||||
return Number(value) === Number(originalValue)
|
||||
}
|
||||
</script>
|
|
@ -0,0 +1,10 @@
|
|||
import { test, expect } from '@playwright/test'
|
||||
|
||||
test('自定义比较方法', async ({ page }) => {
|
||||
page.on('pageerror', (exception) => expect(exception).toBeNull())
|
||||
await page.goto('grid-edit#edit-grid-equals')
|
||||
await page.getByText('800').click()
|
||||
await page.getByRole('row', { name: '1 2014-04-30 00:56:00' }).getByRole('textbox').fill('800')
|
||||
await page.getByRole('cell', { name: '人数' }).locator('div').first().click()
|
||||
await expect(page.locator('.tiny-grid .col__dirty')).toHaveCount(0)
|
||||
})
|
|
@ -0,0 +1,60 @@
|
|||
<template>
|
||||
<tiny-grid :data="tableData" :edit-config="{ trigger: 'click', mode: 'cell' }">
|
||||
<tiny-grid-column type="index" width="60"></tiny-grid-column>
|
||||
<tiny-grid-column field="created_date" title="创建时间"></tiny-grid-column>
|
||||
<tiny-grid-column
|
||||
field="employees"
|
||||
title="人数"
|
||||
:editor="{ component: 'input' }"
|
||||
:equals="employeesEquals"
|
||||
></tiny-grid-column>
|
||||
<tiny-grid-column field="introduction" title="公司简介"></tiny-grid-column>
|
||||
</tiny-grid>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { Grid, GridColumn } from '@opentiny/vue'
|
||||
|
||||
export default {
|
||||
components: {
|
||||
TinyGrid: Grid,
|
||||
TinyGridColumn: GridColumn
|
||||
},
|
||||
methods: {
|
||||
employeesEquals({ value, originalValue }) {
|
||||
// 如果数字相等就返回true
|
||||
return Number(value) === Number(originalValue)
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
tableData: [
|
||||
{
|
||||
id: '1',
|
||||
created_date: '2014-04-30 00:56:00',
|
||||
employees: 800,
|
||||
introduction: '公司技术和研发实力雄厚,是国家863项目的参与者,并被政府认定为“高新技术企业”。'
|
||||
},
|
||||
{
|
||||
id: '2',
|
||||
created_date: '2016-07-08 12:36:22',
|
||||
employees: 300,
|
||||
introduction: '公司技术和研发实力雄厚,是国家863项目的参与者,并被政府认定为“高新技术企业”。'
|
||||
},
|
||||
{
|
||||
id: '3',
|
||||
created_date: '2014-02-14 14:14:14',
|
||||
employees: 1300,
|
||||
introduction: '公司技术和研发实力雄厚,是国家863项目的参与者,并被政府认定为“高新技术企业”。'
|
||||
},
|
||||
{
|
||||
id: '4',
|
||||
created_date: '2013-01-13 13:13:13',
|
||||
employees: 360,
|
||||
introduction: '公司技术和研发实力雄厚,是国家863项目的参与者,并被政府认定为“高新技术企业”。'
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
|
@ -7,7 +7,7 @@ test('检查数据是否改变', async ({ page }) => {
|
|||
await page.getByRole('row', { name: '1 保存' }).locator('input[type="text"]').fill('sdf')
|
||||
await page.getByRole('row', { name: '1 保存' }).getByRole('button', { name: '保存' }).click()
|
||||
await expect(page.getByText('保存成功!')).toBeVisible()
|
||||
await page.getByRole('button', { name: '确认' }).click()
|
||||
await page.getByRole('button', { name: '确定' }).click()
|
||||
await page
|
||||
.getByRole('row', {
|
||||
name: '2 WWWW科技YX公司 华南区 深圳福田区 公司技术和研发实力雄厚,是国家863项目的参与者,并被政府认定为“高新技术企业”。 保存'
|
||||
|
@ -15,5 +15,5 @@ test('检查数据是否改变', async ({ page }) => {
|
|||
.getByRole('button', { name: '保存' })
|
||||
.click()
|
||||
await expect(page.getByText('当前数据未改变!')).toBeVisible()
|
||||
await page.getByRole('button', { name: '确认' }).click()
|
||||
await page.getByRole('button', { name: '确定' }).click()
|
||||
})
|
||||
|
|
|
@ -14,23 +14,23 @@ test('获取表格行方法', async ({ page }) => {
|
|||
await expect(
|
||||
page.getByText('当前行数据是:{"id":"1","name":"GFD科技YX公司","area":"华东区","address":"福州","introduction":"')
|
||||
).toBeVisible()
|
||||
await page.getByRole('button', { name: '确认' }).click()
|
||||
await page.getByRole('button', { name: '确定' }).click()
|
||||
await page.getByRole('button', { name: '当前行号' }).click()
|
||||
|
||||
await expect(page.getByText('当前选中行号是:0')).toBeVisible()
|
||||
await page.getByRole('button', { name: '确认' }).click()
|
||||
await page.getByRole('button', { name: '确定' }).click()
|
||||
await page.getByRole('button', { name: 'Radio单选选中行' }).click()
|
||||
|
||||
await expect(
|
||||
page.getByText('单选选中行数据是:{"id":"1","name":"GFD科技YX公司","area":"华东区","address":"福州","introduction"')
|
||||
).toBeVisible()
|
||||
await page.getByRole('button', { name: '确认' }).click()
|
||||
await page.getByRole('button', { name: '确定' }).click()
|
||||
await page.getByRole('button', { name: 'rowId获取当前行' }).click()
|
||||
|
||||
await expect(
|
||||
page.getByText('根据 rowId 获取的当前行:{"id":"1","name":"GFD科技YX公司","area":"华东区","address":"福州","introd')
|
||||
).toBeVisible()
|
||||
await page.getByRole('button', { name: '确认' }).click()
|
||||
await page.getByRole('button', { name: '确定' }).click()
|
||||
await page.getByRole('button', { name: 'tr元素获取行信息' }).click()
|
||||
|
||||
await expect(
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
<template>
|
||||
<tiny-grid border :data="tableData">
|
||||
<tiny-grid :data="tableData">
|
||||
<tiny-grid-column type="index" width="60" fixed="left"></tiny-grid-column>
|
||||
<tiny-grid-column type="selection" width="60" fixed="left"></tiny-grid-column>
|
||||
<tiny-grid-column field="name" title="公司名称" width="500"></tiny-grid-column>
|
||||
|
|
|
@ -0,0 +1,132 @@
|
|||
<template>
|
||||
<tiny-grid
|
||||
:data="tableData"
|
||||
column-min-width="100"
|
||||
auto-resize
|
||||
:column-anchor="columnAnchor"
|
||||
:optimization="{ scrollX: { gt: 20 } }"
|
||||
>
|
||||
<tiny-grid-column field="name0" title="名称0" sortable fixed="left"></tiny-grid-column>
|
||||
<tiny-grid-column field="name1" title="名称1" sortable fixed="left"></tiny-grid-column>
|
||||
<tiny-grid-column field="name2" title="名称2" sortable fixed="left"></tiny-grid-column>
|
||||
<tiny-grid-column field="name3" title="名称3" sortable></tiny-grid-column>
|
||||
<tiny-grid-column field="name4" title="名称4" sortable></tiny-grid-column>
|
||||
<tiny-grid-column field="name5" title="名称5" sortable></tiny-grid-column>
|
||||
<tiny-grid-column field="name6" title="名称6" sortable></tiny-grid-column>
|
||||
<tiny-grid-column field="name7" title="名称7" sortable></tiny-grid-column>
|
||||
<tiny-grid-column field="name8" title="名称8" sortable></tiny-grid-column>
|
||||
<tiny-grid-column field="name9" title="名称9" sortable></tiny-grid-column>
|
||||
<tiny-grid-column field="name10" title="名称10" sortable></tiny-grid-column>
|
||||
<tiny-grid-column field="name" title="名称" sortable></tiny-grid-column>
|
||||
<tiny-grid-column field="name11" title="名称11" sortable></tiny-grid-column>
|
||||
<tiny-grid-column field="name12" title="名称12" sortable></tiny-grid-column>
|
||||
<tiny-grid-column field="name13" title="名称13" sortable></tiny-grid-column>
|
||||
<tiny-grid-column field="name14" title="名称14" sortable></tiny-grid-column>
|
||||
<tiny-grid-column field="name15" title="名称15" sortable></tiny-grid-column>
|
||||
<tiny-grid-column field="name16" title="名称16" sortable></tiny-grid-column>
|
||||
<tiny-grid-column field="name17" title="名称17" sortable></tiny-grid-column>
|
||||
<tiny-grid-column field="name18" title="名称18" sortable></tiny-grid-column>
|
||||
<tiny-grid-column field="name19" title="名称19" sortable></tiny-grid-column>
|
||||
<tiny-grid-column field="name20" title="名称20" sortable></tiny-grid-column>
|
||||
<tiny-grid-column field="employees" title="员工数" sortable></tiny-grid-column>
|
||||
<tiny-grid-column field="name21" title="名称21" sortable></tiny-grid-column>
|
||||
<tiny-grid-column field="name22" title="名称22" sortable></tiny-grid-column>
|
||||
<tiny-grid-column field="name23" title="名称23" sortable></tiny-grid-column>
|
||||
<tiny-grid-column field="name24" title="名称24" sortable></tiny-grid-column>
|
||||
<tiny-grid-column field="name25" title="名称25" sortable></tiny-grid-column>
|
||||
<tiny-grid-column field="name26" title="名称26" sortable></tiny-grid-column>
|
||||
<tiny-grid-column field="name27" title="名称27" sortable></tiny-grid-column>
|
||||
<tiny-grid-column field="name28" title="名称28" sortable></tiny-grid-column>
|
||||
<tiny-grid-column field="name29" title="名称29" sortable></tiny-grid-column>
|
||||
<tiny-grid-column field="name30" title="名称30" sortable></tiny-grid-column>
|
||||
<tiny-grid-column field="address" title="地址"></tiny-grid-column>
|
||||
<tiny-grid-column field="name31" title="名称31" sortable></tiny-grid-column>
|
||||
<tiny-grid-column field="name32" title="名称32" sortable></tiny-grid-column>
|
||||
<tiny-grid-column field="name33" title="名称33" sortable></tiny-grid-column>
|
||||
<tiny-grid-column field="name34" title="名称34" sortable></tiny-grid-column>
|
||||
<tiny-grid-column field="name35" title="名称35" sortable></tiny-grid-column>
|
||||
<tiny-grid-column field="name36" title="名称36" sortable></tiny-grid-column>
|
||||
<tiny-grid-column field="name37" title="名称37" sortable></tiny-grid-column>
|
||||
<tiny-grid-column field="name38" title="名称38" sortable></tiny-grid-column>
|
||||
<tiny-grid-column field="name39" title="名称39" sortable></tiny-grid-column>
|
||||
<tiny-grid-column field="name40" title="名称40" sortable></tiny-grid-column>
|
||||
<tiny-grid-column field="name41" title="名称41" sortable></tiny-grid-column>
|
||||
<tiny-grid-column field="name42" title="名称42" sortable></tiny-grid-column>
|
||||
<tiny-grid-column field="name43" title="名称43" sortable></tiny-grid-column>
|
||||
<tiny-grid-column field="name44" title="名称44" sortable></tiny-grid-column>
|
||||
<tiny-grid-column field="name45" title="名称45" sortable></tiny-grid-column>
|
||||
<tiny-grid-column field="name46" title="名称46" sortable></tiny-grid-column>
|
||||
<tiny-grid-column field="name47" title="名称47" sortable></tiny-grid-column>
|
||||
<tiny-grid-column field="introduction" title="公司简介" show-overflow></tiny-grid-column>
|
||||
<tiny-grid-column field="name48" title="名称48" sortable fixed="right"></tiny-grid-column>
|
||||
<tiny-grid-column field="name49" title="名称49" sortable fixed="right"></tiny-grid-column>
|
||||
</tiny-grid>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { Grid, GridColumn } from '@opentiny/vue'
|
||||
import { IconMarkOn } from '@opentiny/vue-icon'
|
||||
|
||||
export default {
|
||||
components: {
|
||||
TinyGrid: Grid,
|
||||
TinyGridColumn: GridColumn
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
columnAnchor: [
|
||||
'name',
|
||||
'address',
|
||||
['introduction', '简单介绍'],
|
||||
[
|
||||
'employees',
|
||||
[
|
||||
'雇员数量-自定义渲染',
|
||||
({ h, anchor: { active, field, label }, action }) =>
|
||||
h(
|
||||
'div',
|
||||
{
|
||||
class: { 'tiny-grid__column-anchor-item': true, 'tiny-grid__column-anchor-item--active': active },
|
||||
on: { click: (e) => action(field, e) }
|
||||
},
|
||||
[active ? h(IconMarkOn(), { class: 'tiny-grid__column-anchor-item-icon' }) : null, h('span', label)]
|
||||
)
|
||||
]
|
||||
]
|
||||
],
|
||||
tableData: [
|
||||
{
|
||||
id: '1',
|
||||
name: 'GFD科技有限公司',
|
||||
address: '福州',
|
||||
introduction: '公司技术和研发实力雄厚,是国家863项目的参与者,并被政府认定为“高新技术企业”。',
|
||||
employees: 800,
|
||||
name0: '1-name-0',
|
||||
name1: '1-name-1',
|
||||
name2: '1-name-2'
|
||||
},
|
||||
{
|
||||
id: '2',
|
||||
name: 'WWW科技有限公司',
|
||||
address: '深圳福田区',
|
||||
introduction: '公司技术和研发实力雄厚,是国家863项目的参与者,并被政府认定为“高新技术企业”。',
|
||||
employees: 300,
|
||||
name0: '2-name-0',
|
||||
name1: '2-name-1',
|
||||
name2: '2-name-2'
|
||||
},
|
||||
{
|
||||
id: '3',
|
||||
name: 'RFV有限责任公司',
|
||||
address: '中山市',
|
||||
introduction: '公司技术和研发实力雄厚,是国家863项目的参与者,并被政府认定为“高新技术企业”。',
|
||||
employees: 1300,
|
||||
name0: '3-name-0',
|
||||
name1: '3-name-1',
|
||||
name2: '3-name-2'
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
|
@ -3,7 +3,7 @@ import { test, expect } from '@playwright/test'
|
|||
test('滚动到指定位置', async ({ page }) => {
|
||||
page.on('pageerror', (exception) => expect(exception).toBeNull())
|
||||
await page.goto('grid-large-data#large-data-scroll-to')
|
||||
await page.waitForTimeout(1000)
|
||||
await page.waitForTimeout(3000)
|
||||
await page.getByRole('button', { name: '滚动到500列' }).click()
|
||||
await page.waitForTimeout(200)
|
||||
await expect(page.getByText('col508')).toBeVisible()
|
||||
|
|
|
@ -4,5 +4,5 @@ test('开启加载中状态', async ({ page }) => {
|
|||
page.on('pageerror', (exception) => expect(exception).toBeNull())
|
||||
await page.goto('grid-loading#loading-grid-loading-tip')
|
||||
await page.getByRole('button', { name: '重试' }).click()
|
||||
await expect(page.locator('.tiny-grid-loading__wrap')).toBeVisible()
|
||||
await expect(page.locator('.tiny-grid-loading')).toBeVisible()
|
||||
})
|
||||
|
|
|
@ -122,6 +122,6 @@ function getData({ page }) {
|
|||
}
|
||||
|
||||
function pageChange() {
|
||||
Modal.message('取消分页')
|
||||
Modal.message({ message: '取消分页', status: 'info' })
|
||||
}
|
||||
</script>
|
||||
|
|
|
@ -129,7 +129,7 @@ export default {
|
|||
})
|
||||
},
|
||||
pageChange() {
|
||||
Modal.message('取消分页')
|
||||
Modal.message({ message: '取消分页', status: 'info' })
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,40 @@
|
|||
<template>
|
||||
<tiny-grid :data="tableData">
|
||||
<tiny-grid-column type="index" width="60"></tiny-grid-column>
|
||||
<tiny-grid-column field="date1" title="日期1" format-text="date"></tiny-grid-column>
|
||||
<tiny-grid-column field="date2" title="日期2" format-text="date"></tiny-grid-column>
|
||||
<tiny-grid-column
|
||||
field="date3"
|
||||
title="日期3"
|
||||
format-text="date"
|
||||
:format-config="{ valueFormat: 'dd/MM/yyyy' }"
|
||||
></tiny-grid-column>
|
||||
<tiny-grid-column
|
||||
field="date4"
|
||||
title="日期4"
|
||||
format-text="date"
|
||||
:format-config="{ valueFormat: 'dd/MM/yyyy' }"
|
||||
></tiny-grid-column>
|
||||
<tiny-grid-column
|
||||
field="date5"
|
||||
title="日期5"
|
||||
format-text="date"
|
||||
:format-config="{ valueFormat: 'MM/dd/yyyy' }"
|
||||
></tiny-grid-column>
|
||||
</tiny-grid>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref } from 'vue'
|
||||
import { Grid as TinyGrid, GridColumn as TinyGridColumn } from '@opentiny/vue'
|
||||
const tableData = ref([
|
||||
{
|
||||
id: '1',
|
||||
date1: 1719849600000,
|
||||
date2: new Date(),
|
||||
date3: '07/02/2024', // Date.parse 能正常解析,但是被解析为 7 月 2 号
|
||||
date4: '15/02/2024', // Date.parse 不能正常解析
|
||||
date5: '02/15/2024' // Date.parse 能正常解析为 2 月 15 号
|
||||
}
|
||||
])
|
||||
</script>
|
|
@ -0,0 +1,9 @@
|
|||
import { test, expect } from '@playwright/test'
|
||||
|
||||
test('日期渲染器', async ({ page }) => {
|
||||
page.on('pageerror', (exception) => expect(exception).toBeNull())
|
||||
await page.goto('grid-renderer#renderer-inner-renderer-date')
|
||||
await expect(page.getByText('-07-02')).toBeVisible()
|
||||
await expect(page.getByText('-02-15').first()).toBeVisible()
|
||||
await expect(page.getByText('-02-15').nth(1)).toBeVisible()
|
||||
})
|
|
@ -0,0 +1,50 @@
|
|||
<template>
|
||||
<tiny-grid :data="tableData">
|
||||
<tiny-grid-column type="index" width="60"></tiny-grid-column>
|
||||
<tiny-grid-column field="date1" title="日期1" format-text="date"></tiny-grid-column>
|
||||
<tiny-grid-column field="date2" title="日期2" format-text="date"></tiny-grid-column>
|
||||
<tiny-grid-column
|
||||
field="date3"
|
||||
title="日期3"
|
||||
format-text="date"
|
||||
:format-config="{ valueFormat: 'dd/MM/yyyy' }"
|
||||
></tiny-grid-column>
|
||||
<tiny-grid-column
|
||||
field="date4"
|
||||
title="日期4"
|
||||
format-text="date"
|
||||
:format-config="{ valueFormat: 'dd/MM/yyyy' }"
|
||||
></tiny-grid-column>
|
||||
<tiny-grid-column
|
||||
field="date5"
|
||||
title="日期5"
|
||||
format-text="date"
|
||||
:format-config="{ valueFormat: 'MM/dd/yyyy' }"
|
||||
></tiny-grid-column>
|
||||
</tiny-grid>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { Grid, GridColumn } from '@opentiny/vue'
|
||||
|
||||
export default {
|
||||
components: {
|
||||
TinyGrid: Grid,
|
||||
TinyGridColumn: GridColumn
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
tableData: [
|
||||
{
|
||||
id: '1',
|
||||
date1: 1719849600000,
|
||||
date2: new Date(),
|
||||
date3: '07/02/2024', // Date.parse 能正常解析,但是被解析为 7 月 2 号
|
||||
date4: '15/02/2024', // Date.parse 不能正常解析
|
||||
date5: '02/15/2024' // Date.parse 能正常解析为 2 月 15 号
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
|
@ -1,33 +1,40 @@
|
|||
<template>
|
||||
<p>medium</p>
|
||||
<tiny-grid :data="tableData" size="medium">
|
||||
<tiny-tabs v-model="activeName" tab-style="card">
|
||||
<tiny-tab-item title="medium" name="medium">
|
||||
<tiny-grid :data="tableData" size="medium" :auto-resize="true">
|
||||
<tiny-grid-column type="index" width="60"></tiny-grid-column>
|
||||
<tiny-grid-column type="selection" width="60"></tiny-grid-column>
|
||||
<tiny-grid-column field="employees" title="员工数"></tiny-grid-column>
|
||||
<tiny-grid-column field="createdDate" title="创建日期"></tiny-grid-column>
|
||||
<tiny-grid-column field="city" title="城市"></tiny-grid-column>
|
||||
</tiny-grid>
|
||||
<p>small</p>
|
||||
<tiny-grid :data="tableData" size="small">
|
||||
</tiny-tab-item>
|
||||
<tiny-tab-item title="small" name="small">
|
||||
<tiny-grid :data="tableData" size="small" :auto-resize="true">
|
||||
<tiny-grid-column type="index" width="60"></tiny-grid-column>
|
||||
<tiny-grid-column type="selection" width="60"></tiny-grid-column>
|
||||
<tiny-grid-column field="employees" title="员工数"></tiny-grid-column>
|
||||
<tiny-grid-column field="createdDate" title="创建日期"></tiny-grid-column>
|
||||
<tiny-grid-column field="city" title="城市"></tiny-grid-column>
|
||||
</tiny-grid>
|
||||
<p>mini</p>
|
||||
<tiny-grid :data="tableData" size="mini">
|
||||
</tiny-tab-item>
|
||||
<tiny-tab-item title="mini" name="mini">
|
||||
<tiny-grid :data="tableData" size="mini" :auto-resize="true">
|
||||
<tiny-grid-column type="index" width="60"></tiny-grid-column>
|
||||
<tiny-grid-column type="selection" width="60"></tiny-grid-column>
|
||||
<tiny-grid-column field="employees" title="员工数"></tiny-grid-column>
|
||||
<tiny-grid-column field="createdDate" title="创建日期"></tiny-grid-column>
|
||||
<tiny-grid-column field="city" title="城市"></tiny-grid-column>
|
||||
</tiny-grid>
|
||||
</tiny-tab-item>
|
||||
</tiny-tabs>
|
||||
</template>
|
||||
|
||||
<script setup lang="jsx">
|
||||
<script setup>
|
||||
import { ref } from 'vue'
|
||||
import { Grid as TinyGrid, GridColumn as TinyGridColumn } from '@opentiny/vue'
|
||||
import { Grid as TinyGrid, GridColumn as TinyGridColumn, Tabs as TinyTabs, TabItem as TinyTabItem } from '@opentiny/vue'
|
||||
|
||||
const activeName = ref('medium')
|
||||
|
||||
const tableData = ref([
|
||||
{
|
||||
|
|
|
@ -5,11 +5,15 @@ test('尺寸', async ({ page }) => {
|
|||
await page.goto('grid-size#size-grid-size')
|
||||
const mediumTd = page.locator('.size__medium .tiny-grid-body__column').first()
|
||||
const { height: heightMedium } = await mediumTd.boundingBox()
|
||||
await page.getByText('small').click()
|
||||
await page.waitForTimeout(500)
|
||||
const smallTd = page.locator('.size__small .tiny-grid-body__column').first()
|
||||
const { height: heightSamll } = await smallTd.boundingBox()
|
||||
const miniTd = page.locator('.size__small .tiny-grid-body__column').first()
|
||||
await page.getByText('mini').click()
|
||||
await page.waitForTimeout(500)
|
||||
const miniTd = page.locator('.size__mini .tiny-grid-body__column').first()
|
||||
const { height: heightMini } = await miniTd.boundingBox()
|
||||
|
||||
await expect(heightMedium).toBeGreaterThanOrEqual(heightSamll)
|
||||
await expect(heightSamll).toBeGreaterThanOrEqual(heightMini)
|
||||
await expect(heightMedium).toBeGreaterThan(heightSamll)
|
||||
await expect(heightSamll).toBeGreaterThan(heightMini)
|
||||
})
|
||||
|
|
|
@ -1,35 +1,42 @@
|
|||
<template>
|
||||
<p>medium</p>
|
||||
<tiny-grid :data="tableData" size="medium">
|
||||
<tiny-tabs v-model="activeName" tab-style="card">
|
||||
<tiny-tab-item title="medium" name="medium">
|
||||
<tiny-grid :data="tableData" size="medium" :auto-resize="true">
|
||||
<tiny-grid-column type="index" width="60"></tiny-grid-column>
|
||||
<tiny-grid-column type="selection" width="60"></tiny-grid-column>
|
||||
<tiny-grid-column field="employees" title="员工数"></tiny-grid-column>
|
||||
<tiny-grid-column field="createdDate" title="创建日期"></tiny-grid-column>
|
||||
<tiny-grid-column field="city" title="城市"></tiny-grid-column>
|
||||
</tiny-grid>
|
||||
<p>small</p>
|
||||
<tiny-grid :data="tableData" size="small">
|
||||
</tiny-tab-item>
|
||||
<tiny-tab-item title="small" name="small">
|
||||
<tiny-grid :data="tableData" size="small" :auto-resize="true">
|
||||
<tiny-grid-column type="index" width="60"></tiny-grid-column>
|
||||
<tiny-grid-column type="selection" width="60"></tiny-grid-column>
|
||||
<tiny-grid-column field="employees" title="员工数"></tiny-grid-column>
|
||||
<tiny-grid-column field="createdDate" title="创建日期"></tiny-grid-column>
|
||||
<tiny-grid-column field="city" title="城市"></tiny-grid-column>
|
||||
</tiny-grid>
|
||||
<p>mini</p>
|
||||
<tiny-grid :data="tableData" size="mini">
|
||||
</tiny-tab-item>
|
||||
<tiny-tab-item title="mini" name="mini">
|
||||
<tiny-grid :data="tableData" size="mini" :auto-resize="true">
|
||||
<tiny-grid-column type="index" width="60"></tiny-grid-column>
|
||||
<tiny-grid-column type="selection" width="60"></tiny-grid-column>
|
||||
<tiny-grid-column field="employees" title="员工数"></tiny-grid-column>
|
||||
<tiny-grid-column field="createdDate" title="创建日期"></tiny-grid-column>
|
||||
<tiny-grid-column field="city" title="城市"></tiny-grid-column>
|
||||
</tiny-grid>
|
||||
</tiny-tab-item>
|
||||
</tiny-tabs>
|
||||
</template>
|
||||
|
||||
<script lang="jsx">
|
||||
import { Grid, GridColumn } from '@opentiny/vue'
|
||||
import { Grid, GridColumn, Tabs, TabItem } from '@opentiny/vue'
|
||||
|
||||
export default {
|
||||
components: {
|
||||
TinyTabs: Tabs,
|
||||
TinyTabItem: TabItem,
|
||||
TinyGrid: Grid,
|
||||
TinyGridColumn: GridColumn
|
||||
},
|
||||
|
@ -101,7 +108,8 @@ export default {
|
|||
}
|
||||
]
|
||||
return {
|
||||
tableData
|
||||
tableData,
|
||||
activeName: 'medium'
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -8,7 +8,6 @@
|
|||
:data="tableData"
|
||||
ref="grid"
|
||||
highlight-current-row
|
||||
border
|
||||
:edit-config="{ trigger: 'click', mode: 'cell', showStatus: true }"
|
||||
>
|
||||
<tiny-grid-column type="index" width="60"></tiny-grid-column>
|
||||
|
|
|
@ -0,0 +1,65 @@
|
|||
<template>
|
||||
<tiny-teleport to="body" :disabled="!isFullscreen">
|
||||
<tiny-grid :data="tableData" :style="fullscreenStyle" @toolbar-button-click="toolbarButtonClick">
|
||||
<template #toolbar>
|
||||
<tiny-grid-toolbar :buttons="toolbarButtons"></tiny-grid-toolbar>
|
||||
</template>
|
||||
<tiny-grid-column field="name" title="名称"></tiny-grid-column>
|
||||
<tiny-grid-column field="area" title="所属区域"></tiny-grid-column>
|
||||
<tiny-grid-column field="address" title="地址"></tiny-grid-column>
|
||||
<tiny-grid-column field="introduction" title="公司简介" show-overflow></tiny-grid-column>
|
||||
</tiny-grid>
|
||||
</tiny-teleport>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { Teleport as TinyTeleport } from '@opentiny/vue-common'
|
||||
import { ref, nextTick } from 'vue'
|
||||
import { Grid as TinyGrid, GridColumn as TinyGridColumn, GridToolbar as TinyGridToolbar } from '@opentiny/vue'
|
||||
|
||||
const isFullscreen = ref(false)
|
||||
const fullscreenStyle = ref('')
|
||||
|
||||
const toolbarButtons = [
|
||||
{ code: 'enterFullscreen', name: '进入全屏模式' },
|
||||
{ code: 'exitFullscreen', name: '退出全屏模式' }
|
||||
]
|
||||
|
||||
const tableData = ref([
|
||||
{
|
||||
id: '1',
|
||||
name: 'GFD科技有限公司',
|
||||
area: '华东区',
|
||||
address: '福州',
|
||||
introduction: '公司技术和研发实力雄厚,是国家863项目的参与者,并被政府认定为“高新技术企业”。'
|
||||
},
|
||||
{
|
||||
id: '2',
|
||||
name: 'WWWW科技有限公司',
|
||||
area: '华南区',
|
||||
address: '深圳福田区',
|
||||
introduction: '公司技术和研发实力雄厚,是国家863项目的参与者,并被政府认定为“高新技术企业”。'
|
||||
},
|
||||
{
|
||||
id: '3',
|
||||
name: 'RFV有限责任公司',
|
||||
area: '华南区',
|
||||
address: '中山市',
|
||||
introduction: '公司技术和研发实力雄厚,是国家863项目的参与者,并被政府认定为“高新技术企业”。'
|
||||
}
|
||||
])
|
||||
|
||||
const toolbarButtonClick = ({ code, $grid }) => {
|
||||
isFullscreen.value = false
|
||||
fullscreenStyle.value = ''
|
||||
|
||||
if (code === 'enterFullscreen') {
|
||||
isFullscreen.value = true
|
||||
fullscreenStyle.value = 'position:fixed;width:100vw;height:100vh;z-index:9999;top:0;left:0;'
|
||||
}
|
||||
|
||||
nextTick(() => {
|
||||
$grid.recalculate()
|
||||
})
|
||||
}
|
||||
</script>
|
|
@ -0,0 +1,10 @@
|
|||
import { test, expect } from '@playwright/test'
|
||||
|
||||
test('推荐基于 Teleport 的全屏方案', async ({ page }) => {
|
||||
page.on('pageerror', (exception) => expect(exception).toBeNull())
|
||||
await page.goto('grid-toolbar#toolbar-grid-full-screen-teleport')
|
||||
await page.getByRole('button', { name: '进入全屏模式' }).click()
|
||||
await expect(page.locator('body>.tiny-grid')).toBeVisible()
|
||||
await page.getByRole('button', { name: '退出全屏模式' }).click()
|
||||
await expect(page.locator('body>.tiny-grid')).toHaveCount(0)
|
||||
})
|
|
@ -0,0 +1,73 @@
|
|||
<template>
|
||||
<tiny-teleport to="body" :disabled="!isFullscreen">
|
||||
<tiny-grid :data="tableData" :style="fullscreenStyle" @toolbar-button-click="toolbarButtonClick">
|
||||
<template #toolbar>
|
||||
<tiny-grid-toolbar :buttons="toolbarButtons"></tiny-grid-toolbar>
|
||||
</template>
|
||||
<tiny-grid-column field="name" title="名称"></tiny-grid-column>
|
||||
<tiny-grid-column field="area" title="所属区域"></tiny-grid-column>
|
||||
<tiny-grid-column field="address" title="地址"></tiny-grid-column>
|
||||
<tiny-grid-column field="introduction" title="公司简介" show-overflow></tiny-grid-column>
|
||||
</tiny-grid>
|
||||
</tiny-teleport>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { Teleport } from '@opentiny/vue-common'
|
||||
import { Grid, GridColumn, GridToolbar } from '@opentiny/vue'
|
||||
|
||||
export default {
|
||||
components: {
|
||||
TinyTeleport: Teleport,
|
||||
TinyGrid: Grid,
|
||||
TinyGridColumn: GridColumn,
|
||||
TinyGridToolbar: GridToolbar
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
isFullscreen: false,
|
||||
fullscreenStyle: '',
|
||||
toolbarButtons: [
|
||||
{ code: 'enterFullscreen', name: '进入全屏模式' },
|
||||
{ code: 'exitFullscreen', name: '退出全屏模式' }
|
||||
],
|
||||
tableData: [
|
||||
{
|
||||
id: '1',
|
||||
name: 'GFD科技有限公司',
|
||||
area: '华东区',
|
||||
address: '福州',
|
||||
introduction: '公司技术和研发实力雄厚,是国家863项目的参与者,并被政府认定为“高新技术企业”。'
|
||||
},
|
||||
{
|
||||
id: '2',
|
||||
name: 'WWWW科技有限公司',
|
||||
area: '华南区',
|
||||
address: '深圳福田区',
|
||||
introduction: '公司技术和研发实力雄厚,是国家863项目的参与者,并被政府认定为“高新技术企业”。'
|
||||
},
|
||||
{
|
||||
id: '3',
|
||||
name: 'RFV有限责任公司',
|
||||
area: '华南区',
|
||||
address: '中山市',
|
||||
introduction: '公司技术和研发实力雄厚,是国家863项目的参与者,并被政府认定为“高新技术企业”。'
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
toolbarButtonClick({ code, $grid }) {
|
||||
this.isFullscreen = false
|
||||
this.fullscreenStyle = ''
|
||||
|
||||
if (code === 'enterFullscreen') {
|
||||
this.isFullscreen = true
|
||||
this.fullscreenStyle = 'position:fixed;width:100vw;height:100vh;z-index:9999;top:0;left:0;'
|
||||
}
|
||||
|
||||
this.$nextTick(() => $grid.recalculate())
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
|
@ -8,7 +8,7 @@ test.describe('树表增删改功能', () => {
|
|||
await page.getByRole('row', { name: '1 新数据' }).getByRole('textbox').click()
|
||||
await page.getByRole('row', { name: '1 新数据' }).getByRole('textbox').fill('zzcd')
|
||||
await page.locator('.tiny-grid-toolbar').click()
|
||||
await page.getByRole('button', { name: '确认' }).click()
|
||||
await page.getByRole('button', { name: '确定' }).click()
|
||||
await expect(page.getByRole('cell', { name: 'zzcd' })).toBeVisible()
|
||||
await page.getByRole('row', { name: '1 新数据' }).locator('path').nth(1).click()
|
||||
await page.getByRole('button', { name: '移除选中' }).click()
|
||||
|
|
|
@ -13,7 +13,7 @@ test('提交前校验', async ({ page }) => {
|
|||
await page.getByRole('button', { name: '提交数据' }).click()
|
||||
await expect(page.getByText('校验不通过', { exact: true })).toBeVisible()
|
||||
|
||||
await page.getByRole('button', { name: '确认' }).click()
|
||||
await page.getByRole('button', { name: '确定' }).click()
|
||||
await page.getByRole('button', { name: '保存 Promise' }).click()
|
||||
await expect(page.getByText('校验不通过,触发了 catch', { exact: true })).toBeVisible()
|
||||
})
|
||||
|
|
|
@ -79,6 +79,17 @@ export default {
|
|||
},
|
||||
'codeFiles': ['edit/status-of-editing.vue']
|
||||
},
|
||||
{
|
||||
'demoId': 'edit-grid-equals',
|
||||
'name': { 'zh-CN': '自定义比较方法', 'en-US': 'Enable editing' },
|
||||
'desc': {
|
||||
'zh-CN':
|
||||
'<p>配置列属性 <code>equals</code> 可实现列值自定义比较。此方法接收字段原始值和当前值等作为参数,期望用户返回布尔结果。返回 <code>false</code> 表示已改变,<code>true</code> 表示未改变,其它值表示使用内部预置比较。表格也支持 <code>equals</code> 属性,用于定义所有字段的比较方法,使用参数 <code>field</code> 区分具体的字段,此方式的影响范围是整个表格,需要谨慎使用。</p>',
|
||||
'en-US':
|
||||
'<p>Table attribute settings<code>edit-config</code>Enable the editing mode, Set <code>showStatus</code> in the attribute object to enable or disable the cell update status (inverted triangle update flag in the upper left corner of the cell). The default value is <code>true</code>. </p>\n'
|
||||
},
|
||||
'codeFiles': ['edit/grid-equals.vue']
|
||||
},
|
||||
{
|
||||
'demoId': 'edit-trigger-mode-for-editing',
|
||||
'name': { 'zh-CN': '触发编辑方式', 'en-US': 'Click to trigger editing' },
|
||||
|
|
|
@ -30,55 +30,7 @@ export default {
|
|||
'name': { 'zh-CN': '树表虚拟滚动', 'en-US': 'Virtual scrolling of the tree table' },
|
||||
'desc': {
|
||||
'zh-CN': `
|
||||
<p> <code>optimization</code> 虚拟滚动具体配置如下:</p>
|
||||
<table class="api-table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>名称</th>
|
||||
<th>类型</th>
|
||||
<th>描述</th>
|
||||
<th>默认值</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>optimization.scrollX.gt</td> <td>number</td>
|
||||
<td>指定大于多少列时自动启动 X 虚拟滚动</td>
|
||||
<td>100</td></tr> <tr><td>optimization.scrollX.rSize</td>
|
||||
<td>number</td>
|
||||
<td>每次渲染列数</td>
|
||||
<td></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>optimization.scrollX.vSize</td>
|
||||
<td>number</td>
|
||||
<td>指定可视区域列数</td>
|
||||
<td></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>optimization.scrollX.adaptive</td> <td>boolean</td>
|
||||
<td>自动适配最优的渲染方式(设置为 false 列数组只会在滚动完成后截取一次,便于大数据场景提升性能,但是会短暂白屏,渲染完成后即恢复)</td>
|
||||
<td>true</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>optimization.scrollY.gt</td>
|
||||
<td>number</td>
|
||||
<td>指定大于多少行时自动启动 Y 虚拟滚动</td>
|
||||
<td>500</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>optimization.scrollY.rSize</td>
|
||||
<td>number</td> <td>每次渲染行数</td>
|
||||
<td></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>optimization.scrollY.adaptive</td>
|
||||
<td>boolean</td>
|
||||
<td>自动适配最优的渲染方式(设置为 false 行数组只会在滚动完成后截取一次,便于大数据场景提升性能,但是会短暂白屏,渲染完成后即恢复)</td>
|
||||
<td>true</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<p>通过 <code>optimization</code> 属性配置树表虚拟滚动执行方式,具体参考类型:<code>IOptimizationConfig</code> 。</p>
|
||||
`,
|
||||
'en-US': ''
|
||||
},
|
||||
|
|
|
@ -44,6 +44,17 @@ export default {
|
|||
},
|
||||
'codeFiles': ['renderer/custom-renderer.vue']
|
||||
},
|
||||
{
|
||||
'demoId': 'renderer-inner-renderer-date',
|
||||
'name': { 'zh-CN': '日期渲染器', 'en-US': 'Custom Renderer' },
|
||||
'desc': {
|
||||
'zh-CN':
|
||||
'<p>在日期字段为字符串值时,需要给日期渲染器提供 <code>valueFormat</code> 配置才能正常解析日期字符串。</p>\n',
|
||||
'en-US':
|
||||
'<p>The custom renderer can customize the rendering of cells or a <code>vue component</code>. Configure <code>renderer</code> in the <code>grid-column</code> column to support method and object configuration. For details, see the following example. </p>\n'
|
||||
},
|
||||
'codeFiles': ['renderer/inner-renderer-date.vue']
|
||||
},
|
||||
{
|
||||
'demoId': 'render-async-colunm-render',
|
||||
'name': { 'zh-CN': '列异步数据渲染', 'en-US': 'Column Asynchronous Data Rendering' },
|
||||
|
|
|
@ -114,6 +114,15 @@ export default {
|
|||
},
|
||||
'codeFiles': ['toolbar/grid-full-screen-height.vue']
|
||||
},
|
||||
{
|
||||
'demoId': 'toolbar-grid-full-screen-teleport',
|
||||
'name': { 'zh-CN': '推荐基于 Teleport 的全屏方案', 'en-US': 'Change the table height in full screen mode' },
|
||||
'desc': {
|
||||
'zh-CN': '<p>通过 <code>teleport</code> 实现表格全屏。</p>',
|
||||
'en-US': 'For details, see the following example.'
|
||||
},
|
||||
'codeFiles': ['toolbar/grid-full-screen-teleport.vue']
|
||||
},
|
||||
{
|
||||
'demoId': 'toolbar-custom-toolbar',
|
||||
'name': { 'zh-CN': '工具栏自定义插槽', 'en-US': 'Toolbar Custom Slot' },
|
||||
|
|
|
@ -22,14 +22,14 @@ function baseClick() {
|
|||
{
|
||||
on: {
|
||||
click: (e) => {
|
||||
params.footerSlotParams.confirm(e)
|
||||
params.confirm(e)
|
||||
}
|
||||
},
|
||||
props: { type: 'primary' }
|
||||
},
|
||||
'点我确定'
|
||||
),
|
||||
h(TinyButton, { on: { click: (e) => params.footerSlotParams.cancel(e) } }, '点我取消')
|
||||
h(TinyButton, { on: { click: (e) => params.cancel(e) } }, '点我取消')
|
||||
]
|
||||
}
|
||||
})
|
||||
|
|
|
@ -1,10 +1,13 @@
|
|||
<template>
|
||||
<tiny-numeric v-model="value" @change="onChange"></tiny-numeric>
|
||||
<div style="display: flex">
|
||||
<tiny-numeric :change-compat="false" v-model="value" @change="onChange"></tiny-numeric>
|
||||
<tiny-button @click="clickChange">修改</tiny-button>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref } from 'vue'
|
||||
import { Numeric as TinyNumeric, Modal } from '@opentiny/vue'
|
||||
import { Numeric as TinyNumeric, Modal, Button as TinyButton } from '@opentiny/vue'
|
||||
|
||||
const value = ref(1)
|
||||
|
||||
|
@ -14,4 +17,8 @@ const onChange = (newVal: number, oldVal: number) => {
|
|||
status: 'info'
|
||||
})
|
||||
}
|
||||
|
||||
const clickChange = () => {
|
||||
value.value = 22
|
||||
}
|
||||
</script>
|
||||
|
|
|
@ -1,13 +1,17 @@
|
|||
<template>
|
||||
<tiny-numeric v-model="value" @change="onChange"></tiny-numeric>
|
||||
<div style="display: flex">
|
||||
<tiny-numeric :change-compat="false" v-model="value" @change="onChange"></tiny-numeric>
|
||||
<tiny-button @click="clickChange">修改</tiny-button>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { Numeric, Modal } from '@opentiny/vue'
|
||||
import { Numeric, Modal, Button } from '@opentiny/vue'
|
||||
|
||||
export default {
|
||||
components: {
|
||||
TinyNumeric: Numeric
|
||||
TinyNumeric: Numeric,
|
||||
TinyButton: Button
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
|
@ -20,6 +24,9 @@ export default {
|
|||
message: '新值:' + newVal + ',旧值:' + oldVal,
|
||||
status: 'info'
|
||||
})
|
||||
},
|
||||
clickChange() {
|
||||
this.value = 22
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
<template>
|
||||
<p>1、数值精度</p>
|
||||
<tiny-numeric v-model="value" :precision="precision" :format="format"></tiny-numeric>
|
||||
<tiny-numeric v-model="value" :precision="precision"></tiny-numeric>
|
||||
<p>2、数值格式</p>
|
||||
<tiny-numeric style="width: 300px" v-model="value1" :format="format"></tiny-numeric>
|
||||
</template>
|
||||
|
|
|
@ -4,19 +4,18 @@ test('数值精度', async ({ page }) => {
|
|||
page.on('pageerror', (exception) => expect(exception).toBeNull())
|
||||
await page.goto('numeric#precision')
|
||||
|
||||
const numericInput = page.getByRole('spinbutton')
|
||||
await numericInput.fill('2.2222')
|
||||
await numericInput.blur()
|
||||
const numericInput = page.getByRole('spinbutton').first()
|
||||
let actualValue = await numericInput.inputValue()
|
||||
expect(actualValue).toEqual('2.22')
|
||||
|
||||
await numericInput.fill('8.88888')
|
||||
await page.locator('#precision').getByRole('button').nth(1).click()
|
||||
await page.locator('#precision').getByRole('button').first().click()
|
||||
await numericInput.blur()
|
||||
actualValue = await numericInput.inputValue()
|
||||
expect(actualValue).toEqual('8.89')
|
||||
expect(actualValue).toEqual('1.00')
|
||||
|
||||
await numericInput.fill('6.66')
|
||||
await numericInput.blur()
|
||||
actualValue = await numericInput.inputValue()
|
||||
expect(actualValue).toEqual('6.66')
|
||||
const numericFormatInput = page.getByRole('spinbutton').nth(1)
|
||||
let actualFormatValue = await numericFormatInput.inputValue()
|
||||
await page.locator('#precision').getByRole('button').nth(3).click()
|
||||
await page.locator('#precision').getByRole('button').nth(2).click()
|
||||
await numericFormatInput.blur()
|
||||
expect(actualFormatValue).toEqual('$12,34,56,879.4455@')
|
||||
})
|
||||
|
|
|
@ -9,7 +9,7 @@ test('分页变更前置处理', async ({ page }) => {
|
|||
const prev = pager.locator('.tiny-pager__btn-prev')
|
||||
const next = pager.locator('.tiny-pager__btn-next')
|
||||
const tipModal = page.locator('.tiny-modal__box').filter({ hasText: '消息提示' })
|
||||
const confirmBtn = tipModal.getByRole('button', { name: '确认' })
|
||||
const confirmBtn = tipModal.getByRole('button', { name: '确定' })
|
||||
|
||||
await pager.locator('li').getByText('6').click()
|
||||
await expect(tipModal).toBeVisible()
|
||||
|
|
|
@ -13,7 +13,7 @@ test('禁用和尺寸', async ({ page }) => {
|
|||
|
||||
await demo.locator('.tiny-switch').click()
|
||||
await expect(sizeChange).toHaveCSS('color', 'rgb(138, 142, 153)')
|
||||
await expect(sizeChange).toHaveCSS('border-top-color', 'rgb(223, 225, 230)')
|
||||
await expect(sizeChange).toHaveCSS('border-top-color', 'rgba(0, 0, 0, 0)')
|
||||
await expect(prev).toBeDisabled()
|
||||
await expect(next).toBeDisabled()
|
||||
await expect(pageItem.first()).toHaveCSS('cursor', 'not-allowed')
|
||||
|
|
|
@ -11,7 +11,7 @@
|
|||
import { ref } from 'vue'
|
||||
import { Steps as TinySteps, Modal } from '@opentiny/vue'
|
||||
|
||||
const advancedActive = ref(2)
|
||||
const advancedActive = ref(1)
|
||||
const data = ref([
|
||||
{ name: 'Basic Info', count: 3, status: 'doing' },
|
||||
{ name: 'BOQ Info', count: 0, status: 'done' },
|
||||
|
|
|
@ -11,11 +11,11 @@ test('高级向导', async ({ page }) => {
|
|||
|
||||
await expect(stepsWrapper).toBeVisible()
|
||||
await expect(nodes.first()).toHaveClass('doing')
|
||||
await expect(nodes.nth(1)).toHaveClass('done')
|
||||
await expect(nodes.nth(2)).toHaveClass(/current/)
|
||||
await expect(nodes.nth(1)).toHaveClass(/done/)
|
||||
await expect(nodes.nth(1)).toHaveClass(/current/)
|
||||
await nodes.nth(3).click()
|
||||
await expect(nodes.nth(3)).toHaveClass(/current/)
|
||||
await expect(nodes.nth(2)).not.toHaveClass(/current/)
|
||||
await expect(nodes.nth(1)).not.toHaveClass(/current/)
|
||||
|
||||
// advanced 高级向导模式
|
||||
const advancedSteps = page.locator('.pc-demo .tiny-steps-senior')
|
||||
|
|
|
@ -16,7 +16,7 @@ export default {
|
|||
},
|
||||
data() {
|
||||
return {
|
||||
advancedActive: 2,
|
||||
advancedActive: 1,
|
||||
data: [
|
||||
{ name: 'Basic Info', count: 3, status: 'done' },
|
||||
{ name: 'BOQ Info', count: 0, status: 'doing' },
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
<tiny-button type="primary" @click="changeShape">
|
||||
点击切换 shape 为 {{ shape === 'dot' ? 'circle' : 'dot' }}
|
||||
</tiny-button>
|
||||
<tiny-time-line vertical :data="data" :shape="shape"></tiny-time-line>
|
||||
<tiny-time-line vertical :data="data" :shape="shape" :active="active" @click="onClick"></tiny-time-line>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
|
@ -17,12 +17,15 @@ const data = reactive([
|
|||
{ name: '已签收', time: '2019-11-13 20:45:50' },
|
||||
{ name: '已评价', time: '2019-11-14 20:45:50' }
|
||||
])
|
||||
|
||||
const active = ref(1)
|
||||
const shape = ref('dot')
|
||||
|
||||
const changeShape = () => {
|
||||
shape.value = shape.value === 'dot' ? 'circle' : 'dot'
|
||||
}
|
||||
const onClick = (index: number) => {
|
||||
active.value = index
|
||||
}
|
||||
</script>
|
||||
|
||||
<style>
|
||||
|
|
|
@ -7,6 +7,8 @@ test('圆点外观', async ({ page }) => {
|
|||
const timeline = page.locator('#shape .tiny-steps-timeline')
|
||||
await expect(timeline.locator('.dot').first()).toBeVisible()
|
||||
await expect(timeline.locator('.tiny-timeline-item__content .time').first()).toBeVisible()
|
||||
await timeline.getByText('已签收').click()
|
||||
await expect(timeline.locator('.tiny-timeline-item').nth(2)).toHaveClass(/process-current/)
|
||||
|
||||
await page.getByRole('button', { name: '点击切换 shape 为 circle' }).click()
|
||||
await expect(timeline.locator('.dot').first()).not.toBeVisible()
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
<tiny-button type="primary" @click="changeShape">
|
||||
点击切换 shape 为 {{ shape === 'dot' ? 'circle' : 'dot' }}
|
||||
</tiny-button>
|
||||
<tiny-time-line vertical :data="data" :shape="shape"></tiny-time-line>
|
||||
<tiny-time-line vertical :data="data" :shape="shape" :active="active" @click="onClick"></tiny-time-line>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
|
@ -23,12 +23,16 @@ export default {
|
|||
{ name: '已签收', time: '2019-11-13 20:45:50' },
|
||||
{ name: '已评价', time: '2019-11-14 20:45:50' }
|
||||
],
|
||||
active: 1,
|
||||
shape: 'dot'
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
changeShape() {
|
||||
this.shape = this.shape === 'dot' ? 'circle' : 'dot'
|
||||
},
|
||||
onClick(index: number) {
|
||||
this.active = index
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
<template>
|
||||
<div>
|
||||
<div class="box">
|
||||
Effects 示例:
|
||||
<tiny-tooltip content="dark 提示文字" placement="top">
|
||||
|
@ -26,6 +27,7 @@
|
|||
<tiny-button>success</tiny-button>
|
||||
</tiny-tooltip>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="jsx">
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
<template>
|
||||
<div>
|
||||
<div class="box">
|
||||
Effects 示例:
|
||||
<tiny-tooltip content="dark 提示文字" placement="top">
|
||||
|
@ -26,6 +27,7 @@
|
|||
<tiny-button>success</tiny-button>
|
||||
</tiny-tooltip>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="jsx">
|
||||
|
|
|
@ -8,6 +8,7 @@ import { reactive } from 'vue'
|
|||
|
||||
const data = reactive({
|
||||
imgUrl: `${import.meta.env.VITE_APP_BUILD_BASE_URL}static/images/ld.png`,
|
||||
userName: '张三',
|
||||
roleNumber: 'z00100001',
|
||||
values: [
|
||||
{ text: '部门', value: '某部门' },
|
||||
|
|
|
@ -16,7 +16,7 @@ export default {
|
|||
},
|
||||
desc: {
|
||||
'zh-CN':
|
||||
'<p>通过 <code>content</code> 属性设置水印的文字。</br>通过 <code>font</code> 属性设置水印的样式</p>。',
|
||||
'<p>通过 <code>content</code> 属性设置水印的文字。</br>通过 <code>font</code> 属性设置水印的样式。</p>',
|
||||
'en-US':
|
||||
'Set the text of the watermark through the <code>content</code> attribute.</br> Set the style of the watermark through the <code>font</code> attribute. '
|
||||
},
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "@opentiny/vue-docs",
|
||||
"version": "2.2.13",
|
||||
"version": "2.2.20",
|
||||
"license": "MIT",
|
||||
"scripts": {
|
||||
"start": "vite",
|
||||
|
|
|
@ -36,6 +36,19 @@ const getRuntime = (version) => {
|
|||
return `${cdnHost}/@opentiny/vue@${useVersion}/runtime/`
|
||||
}
|
||||
|
||||
const changeImportSuffix = (imports, verison) => {
|
||||
const newImports = {}
|
||||
Object.keys(imports).forEach((key) => {
|
||||
const url = imports[key]
|
||||
if (url.startsWith(getRuntime(verison))) {
|
||||
newImports[key] = url.replace('.mjs', '.js')
|
||||
} else {
|
||||
newImports[key] = url
|
||||
}
|
||||
})
|
||||
return newImports
|
||||
}
|
||||
|
||||
const createImportMap = (version) => {
|
||||
const imports = {
|
||||
'@opentiny/vue': `${getRuntime(version)}tiny-vue.mjs`,
|
||||
|
@ -54,7 +67,7 @@ const createImportMap = (version) => {
|
|||
imports['@opentiny/vue-icon'] = `${getRuntime(version)}tiny-vue-icon-saas.mjs`
|
||||
}
|
||||
return {
|
||||
imports
|
||||
imports: changeImportSuffix(imports, version)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -62,6 +75,9 @@ const getTinyTheme = (version) => {
|
|||
if (isMobileFirst) {
|
||||
return `${getRuntime(version)}tailwind.css`
|
||||
}
|
||||
if (isSaas) {
|
||||
return `${getRuntime(version)}index.css`
|
||||
}
|
||||
let theme = tinyTheme
|
||||
if (!['smb', 'default', 'aurora', 'saas'].includes(theme)) {
|
||||
theme = 'default'
|
||||
|
|
|
@ -452,6 +452,7 @@ table.api-table {
|
|||
text-decoration: none;
|
||||
color: #5e7ce0;
|
||||
cursor: pointer;
|
||||
word-wrap: break-word;
|
||||
}
|
||||
|
||||
tbody tr:hover {
|
||||
|
|
|
@ -30,7 +30,7 @@
|
|||
"@playwright/test": "^1.40.1",
|
||||
"@vitest/ui": "^0.31.0",
|
||||
"@vue/babel-helper-vue-jsx-merge-props": "^1.4.0",
|
||||
"@vue/composition-api": "1.2.2",
|
||||
"@vue/composition-api": "1.7.2",
|
||||
"@vue/runtime-dom": "^3.2.31",
|
||||
"@vue/test-utils": "^1.3.3",
|
||||
"jsdom": "^21.0.0",
|
||||
|
|
|
@ -33,7 +33,21 @@ export const getVuePlugins = (vueVersion: string) => {
|
|||
}
|
||||
}
|
||||
}),
|
||||
vue2SvgPlugin({ svgoConfig: { plugins: ['preset-default', 'prefixIds'] } })
|
||||
vue2SvgPlugin({
|
||||
svgoConfig: {
|
||||
plugins: [
|
||||
{
|
||||
name: 'preset-default',
|
||||
params: {
|
||||
overrides: {
|
||||
removeViewBox: false
|
||||
}
|
||||
}
|
||||
},
|
||||
'prefixIds'
|
||||
]
|
||||
}
|
||||
})
|
||||
]
|
||||
},
|
||||
'2.7': () => {
|
||||
|
@ -52,7 +66,21 @@ export const getVuePlugins = (vueVersion: string) => {
|
|||
}
|
||||
}),
|
||||
vue27JsxPlugin({ injectH: false }),
|
||||
vue2SvgPlugin({ svgoConfig: { plugins: ['preset-default', 'prefixIds'] } })
|
||||
vue2SvgPlugin({
|
||||
svgoConfig: {
|
||||
plugins: [
|
||||
{
|
||||
name: 'preset-default',
|
||||
params: {
|
||||
overrides: {
|
||||
removeViewBox: false
|
||||
}
|
||||
}
|
||||
},
|
||||
'prefixIds'
|
||||
]
|
||||
}
|
||||
})
|
||||
]
|
||||
},
|
||||
'3': () => {
|
||||
|
@ -68,7 +96,22 @@ export const getVuePlugins = (vueVersion: string) => {
|
|||
}
|
||||
}),
|
||||
vue3JsxPlugin(),
|
||||
vue3SvgPlugin({ defaultImport: 'component', svgoConfig: { plugins: ['preset-default', 'prefixIds'] } })
|
||||
vue3SvgPlugin({
|
||||
defaultImport: 'component',
|
||||
svgoConfig: {
|
||||
plugins: [
|
||||
{
|
||||
name: 'preset-default',
|
||||
params: {
|
||||
overrides: {
|
||||
removeViewBox: false
|
||||
}
|
||||
}
|
||||
},
|
||||
'prefixIds'
|
||||
]
|
||||
}
|
||||
})
|
||||
]
|
||||
}
|
||||
}
|
||||
|
@ -146,7 +189,7 @@ export const getBaseConfig = ({ vueVersion, dtsInclude, dts, buildTarget, isRunt
|
|||
})
|
||||
|
||||
if (filePath.includes('vue-common') && vueVersion === '2') {
|
||||
dependencies['@vue/composition-api'] = '~1.2.2'
|
||||
dependencies['@vue/composition-api'] = '1.7.2'
|
||||
}
|
||||
|
||||
const matchList = ['vue-icon', 'vue-icon-saas', 'vue', 'design/smb', 'design/aurora', 'design/saas']
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "opentiny-vue",
|
||||
"version": "3.7.12",
|
||||
"version": "3.14.0",
|
||||
"private": true,
|
||||
"packageManager": "pnpm@8.3.1",
|
||||
"description": "An enterprise-class UI component library, support both Vue.js 2 and Vue.js 3, as well as PC and mobile.",
|
||||
|
@ -136,7 +136,7 @@
|
|||
"dev:solid": "pnpm -C examples/solid-docs run dev"
|
||||
},
|
||||
"dependencies": {
|
||||
"@vue/composition-api": "1.2.2",
|
||||
"@vue/composition-api": "1.7.2",
|
||||
"color": "^4.2.3",
|
||||
"cropperjs": "1.5.12",
|
||||
"crypto-js": "4.2.0",
|
||||
|
|
|
@ -7,6 +7,7 @@ import Form from './src/form'
|
|||
import Grid from './src/grid'
|
||||
import Switch from './src/switch'
|
||||
import Select from './src/select'
|
||||
import Loading from './src/loading'
|
||||
import Popover from './src/popover'
|
||||
import TimeLine from './src/time-line'
|
||||
import TimelineItem from './src/timeline-item'
|
||||
|
@ -14,6 +15,7 @@ import Input from './src/input'
|
|||
import DateRange from './src/date-range'
|
||||
import Pager from './src/pager'
|
||||
import Wizard from './src/wizard'
|
||||
import DialogBox from './src/dialog-box'
|
||||
import { version } from './package.json'
|
||||
|
||||
export default {
|
||||
|
@ -30,11 +32,13 @@ export default {
|
|||
Switch,
|
||||
Select,
|
||||
Popover,
|
||||
Loading,
|
||||
TimeLine,
|
||||
TimelineItem,
|
||||
Input,
|
||||
DateRange,
|
||||
Pager,
|
||||
Wizard
|
||||
Wizard,
|
||||
DialogBox
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "@opentiny/vue-design-aurora",
|
||||
"version": "3.13.0",
|
||||
"version": "3.14.0",
|
||||
"main": "index.ts",
|
||||
"sideEffects": false,
|
||||
"type": "module",
|
||||
|
|
|
@ -0,0 +1,6 @@
|
|||
export default {
|
||||
state: {
|
||||
// 覆盖 dialog-box top 默认值
|
||||
top: '0'
|
||||
}
|
||||
}
|
|
@ -0,0 +1,7 @@
|
|||
import loadingImg from '@opentiny/vue-theme-saas/images/loading.png'
|
||||
|
||||
export default {
|
||||
props: {
|
||||
loadingImg
|
||||
}
|
||||
}
|
|
@ -15,6 +15,7 @@ import Loading from './src/loading'
|
|||
import Input from './src/input'
|
||||
import DateRange from './src/date-range'
|
||||
import Pager from './src/pager'
|
||||
import DialogBox from './src/dialog-box'
|
||||
import { version } from './package.json'
|
||||
|
||||
export default {
|
||||
|
@ -37,6 +38,7 @@ export default {
|
|||
TimelineItem,
|
||||
Input,
|
||||
DateRange,
|
||||
Pager
|
||||
Pager,
|
||||
DialogBox
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "@opentiny/vue-design-saas",
|
||||
"version": "3.13.0",
|
||||
"version": "3.14.0",
|
||||
"main": "index.ts",
|
||||
"sideEffects": false,
|
||||
"type": "module",
|
||||
|
|
|
@ -0,0 +1,5 @@
|
|||
export default {
|
||||
state: {
|
||||
top: '0'
|
||||
}
|
||||
}
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "@opentiny/vue-design-smb",
|
||||
"version": "3.13.0",
|
||||
"version": "3.14.0",
|
||||
"sideEffects": false,
|
||||
"type": "module",
|
||||
"main": "index.ts",
|
||||
|
|
|
@ -99,10 +99,10 @@ export const vc = VueClassName
|
|||
|
||||
export const getElementCssClass = (classes = {}, key) => {
|
||||
if (typeof key === 'object') {
|
||||
const keys = Object.keys(key)
|
||||
const keys = Array.isArray(key) ? key : Object.keys(key).filter((k) => key[k])
|
||||
let cls = ''
|
||||
keys.forEach((k) => {
|
||||
if (key[k] && classes[k]) cls += `${classes[k]} `
|
||||
if (classes[k]) cls += `${classes[k]} `
|
||||
})
|
||||
return cls
|
||||
} else {
|
||||
|
|
|
@ -99,10 +99,10 @@ export const vc = VueClassName
|
|||
|
||||
export const getElementCssClass = (classes = {}, key) => {
|
||||
if (typeof key === 'object') {
|
||||
const keys = Object.keys(key)
|
||||
const keys = Array.isArray(key) ? key : Object.keys(key).filter((k) => key[k])
|
||||
let cls = ''
|
||||
keys.forEach((k) => {
|
||||
if (key[k] && classes[k]) cls += `${classes[k]} `
|
||||
if (classes[k]) cls += `${classes[k]} `
|
||||
})
|
||||
return cls
|
||||
} else {
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
{
|
||||
"name": "@opentiny/vue-renderless",
|
||||
"private": true,
|
||||
"version": "3.13.0",
|
||||
"version": "3.14.0",
|
||||
"description": "An enterprise-class UI component library, support both Vue.js 2 and Vue.js 3, as well as PC and mobile.",
|
||||
"homepage": "https://opentiny.design/tiny-vue",
|
||||
"keywords": [
|
||||
|
|
|
@ -115,7 +115,7 @@ export const watchCheckedValue =
|
|||
}
|
||||
|
||||
nextTick(() => {
|
||||
dispatch(constants.COMPONENT_NAME.FormItem, constants.EVENT_NAME.FormBlur, [
|
||||
dispatch(constants.COMPONENT_NAME.FormItem, constants.EVENT_NAME.FormChange, [
|
||||
state.multiple ? state.presentText : state.inputValue
|
||||
])
|
||||
})
|
||||
|
|
|
@ -81,6 +81,9 @@ const getTimezone = (date) => {
|
|||
*/
|
||||
export const isLeapYear = (year) => year % 400 === 0 || (year % 4 === 0 && year % 100 !== 0)
|
||||
|
||||
const getMilliseconds = (milliseconds) =>
|
||||
milliseconds > maxDateValues.MILLISECOND ? Number(String(milliseconds).substring(0, 3)) : milliseconds
|
||||
|
||||
const getDateFromData = ({ year, month, date, hours, minutes, seconds, milliseconds }) => {
|
||||
let daysInMonth = daysInMonths[month]
|
||||
|
||||
|
@ -89,7 +92,7 @@ const getDateFromData = ({ year, month, date, hours, minutes, seconds, milliseco
|
|||
}
|
||||
|
||||
if (date <= daysInMonth) {
|
||||
return new Date(year, month, date, hours, minutes, seconds, milliseconds)
|
||||
return new Date(year, month, date, hours, minutes, seconds, getMilliseconds(milliseconds))
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -176,7 +179,8 @@ const iso8601DateParser = (m) => {
|
|||
actHours = sign === '+' ? hours - offsetHours - offset / 60 : Number(hours) + Number(offsetHours) - offset / 60
|
||||
actMinutes = sign === '+' ? minutes - offsetMinutes : Number(minutes) + Number(offsetMinutes)
|
||||
}
|
||||
return new Date(year, month, date, actHours, actMinutes, seconds, milliseconds)
|
||||
|
||||
return new Date(year, month, date, actHours, actMinutes, seconds, getMilliseconds(milliseconds))
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -441,24 +445,26 @@ export const format = function (date, dateFormat = 'yyyy/MM/dd hh:mm:ss') {
|
|||
/**
|
||||
* 将当前操作的时间变更时区,主要用于转换一个其他时区的时间。
|
||||
*
|
||||
* let date = new Date(2017, 0, 1)
|
||||
* var date = new Date(2017, 0, 1)
|
||||
* getDateWithNewTimezone(date, 0, -2)
|
||||
*
|
||||
* @param {Date} date Date 实例或日期字符串
|
||||
* @param {Number} otz 原时区 -12~13
|
||||
* @param {Number} ntz 目标时区 -12~13 默认为当前时区
|
||||
* @param {Boolean} TimezoneOffset 时区偏移量
|
||||
* @returns {Date}
|
||||
*/
|
||||
export const getDateWithNewTimezone = (date, otz, ntz) => {
|
||||
if (!isDate(date) || !isNumeric(otz) || !isNumeric(ntz)) {
|
||||
export const getDateWithNewTimezone = (date, otz, ntz, timezoneOffset = 0) => {
|
||||
if (!isDate(date) || !isNumeric(otz) || !isNumeric(ntz) || !isNumeric(timezoneOffset)) {
|
||||
return
|
||||
}
|
||||
|
||||
const otzOffset = -otz * 60
|
||||
const ntzOffset = -ntz * 60
|
||||
const dstOffeset = timezoneOffset * 60
|
||||
const utc = date.getTime() + otzOffset * 60000
|
||||
|
||||
return new Date(utc - ntzOffset * 60000)
|
||||
return new Date(utc - (ntzOffset - dstOffeset) * 60000)
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -23,15 +23,18 @@ if (!isServer) {
|
|||
|
||||
on(document, 'mouseup', (event) => {
|
||||
nodeList.forEach((node) => node[nameSpace].documentHandler(event, startClick))
|
||||
startClick = void 0
|
||||
})
|
||||
}
|
||||
|
||||
const createDocumentHandler = (el, binding, vnode) =>
|
||||
function (mouseup = {}, mousedown = {}) {
|
||||
let popperElm = vnode.context.popperElm || vnode.context.state.popperElm
|
||||
let popperElm = vnode.context.popperElm || (vnode.context.state && vnode.context.state.popperElm)
|
||||
|
||||
if (
|
||||
!mouseup ||
|
||||
!mouseup.target ||
|
||||
!mousedown ||
|
||||
!mousedown.target ||
|
||||
el.contains(mouseup.target) ||
|
||||
el.contains(mousedown.target) ||
|
||||
|
@ -89,6 +92,10 @@ export default {
|
|||
}
|
||||
}
|
||||
|
||||
if (nodeList.length === 0 && startClick) {
|
||||
startClick = null
|
||||
}
|
||||
|
||||
delete el[nameSpace]
|
||||
}
|
||||
}
|
||||
|
|
|
@ -10,7 +10,7 @@
|
|||
*
|
||||
*/
|
||||
|
||||
import { on, off } from './dom'
|
||||
import { on, off, isDisplayNone } from './dom'
|
||||
import PopupManager from './popup-manager'
|
||||
import globalConfig from '../global'
|
||||
import { typeOf } from '../type'
|
||||
|
@ -25,11 +25,12 @@ const DEFAULTS = {
|
|||
boundariesPadding: 5,
|
||||
flipBehavior: 'flip', // 全局没有修改过它,所以它一直是flip
|
||||
forceAbsolute: false,
|
||||
gpuAcceleration: true, // 这个用不到了,默认使用tranform3d
|
||||
gpuAcceleration: true,
|
||||
offset: 0,
|
||||
placement: 'bottom',
|
||||
preventOverflowOrder: positions,
|
||||
modifiers // 此处是string数组, 构造函数调用之后转为函数数组
|
||||
modifiers, // 此处是string数组, 构造函数调用之后转为函数数组
|
||||
updateHiddenPopperOnScroll: false // 滚动过程中是否更新隐藏的弹出层位置
|
||||
}
|
||||
|
||||
/** 用 styles 对象赋值el.style */
|
||||
|
@ -292,6 +293,7 @@ interface PopperState {
|
|||
scrollTarget: HTMLElement | null
|
||||
scrollTargets: HTMLElement[] | null
|
||||
updateBoundFn: () => void
|
||||
scrollUpdate: () => void
|
||||
}
|
||||
|
||||
interface ReferenceOffsets {
|
||||
|
@ -753,6 +755,14 @@ class Popper {
|
|||
|
||||
_setupEventListeners() {
|
||||
this.state.updateBoundFn = this.update.bind(this)
|
||||
this.state.scrollUpdate = () => {
|
||||
if (this._options.updateHiddenPopperOnScroll) {
|
||||
this.state.updateBoundFn()
|
||||
} else {
|
||||
if (isDisplayNone(this._popper)) return
|
||||
this.state.updateBoundFn()
|
||||
}
|
||||
}
|
||||
|
||||
on(window, 'resize', this.state.updateBoundFn)
|
||||
|
||||
|
@ -770,10 +780,10 @@ class Popper {
|
|||
|
||||
this.state.scrollTargets = targets || []
|
||||
targets.forEach((target) => {
|
||||
on(target, 'scroll', this.state.updateBoundFn)
|
||||
on(target, 'scroll', this.state.scrollUpdate)
|
||||
})
|
||||
} else {
|
||||
on(target, 'scroll', this.state.updateBoundFn)
|
||||
on(target, 'scroll', this.state.scrollUpdate)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -782,7 +792,7 @@ class Popper {
|
|||
off(window, 'resize', this.state.updateBoundFn)
|
||||
|
||||
if (this._options.boundariesElement !== 'window' && this.state.scrollTarget) {
|
||||
off(this.state.scrollTarget, 'scroll', this.state.updateBoundFn)
|
||||
off(this.state.scrollTarget, 'scroll', this.state.scrollUpdate)
|
||||
this.state.scrollTarget = null
|
||||
|
||||
// 移除祖先监听
|
||||
|
@ -790,13 +800,14 @@ class Popper {
|
|||
let targets = this.state.scrollTargets || []
|
||||
|
||||
targets.forEach((target) => {
|
||||
off(target, 'scroll', this.state.updateBoundFn)
|
||||
off(target, 'scroll', this.state.scrollUpdate)
|
||||
})
|
||||
this.state.scrollTargets = null
|
||||
}
|
||||
}
|
||||
|
||||
this.state.updateBoundFn = null as any
|
||||
this.state.scrollUpdate = null as any
|
||||
}
|
||||
|
||||
/** 实时计算一下Boundary的位置 */
|
||||
|
|
|
@ -1,45 +0,0 @@
|
|||
/**
|
||||
* Copyright (c) 2022 - present TinyVue Authors.
|
||||
* Copyright (c) 2022 - present Huawei Cloud Computing Technologies Co., Ltd.
|
||||
*
|
||||
* Use of this source code is governed by an MIT-style license.
|
||||
*
|
||||
* THE OPEN SOURCE SOFTWARE IN THIS PRODUCT IS DISTRIBUTED IN THE HOPE THAT IT WILL BE USEFUL,
|
||||
* BUT WITHOUT ANY WARRANTY, WITHOUT EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY OR FITNESS FOR
|
||||
* A PARTICULAR PURPOSE. SEE THE APPLICABLE LICENSES FOR MORE DETAILS.
|
||||
*
|
||||
*/
|
||||
|
||||
!(function () {
|
||||
let lastTime = 0
|
||||
const vendors = ['ms', 'moz', 'webkit', 'o']
|
||||
|
||||
for (let x = 0; x < vendors.length && !window.requestAnimationFrame; ++x) {
|
||||
window.requestAnimationFrame = window[vendors[x] + 'RequestAnimationFrame']
|
||||
|
||||
window.cancelAnimationFrame =
|
||||
window[vendors[x] + 'CancelAnimationFrame'] || window[vendors[x] + 'CancelRequestAnimationFrame']
|
||||
}
|
||||
|
||||
if (!window.requestAnimationFrame) {
|
||||
window.requestAnimationFrame = function (callback) {
|
||||
const now = new Date().getTime()
|
||||
const timeToCall = Math.max(0, 16 - (now - lastTime))
|
||||
const timeCallback = now + timeToCall
|
||||
|
||||
const id = window.setTimeout(() => {
|
||||
callback(timeCallback)
|
||||
}, timeToCall)
|
||||
|
||||
lastTime = now + timeToCall
|
||||
|
||||
return id
|
||||
}
|
||||
}
|
||||
|
||||
if (!window.cancelAnimationFrame) {
|
||||
window.cancelAnimationFrame = function (id) {
|
||||
clearTimeout(id)
|
||||
}
|
||||
}
|
||||
})()
|
|
@ -293,7 +293,7 @@ export default class Node {
|
|||
|
||||
if (!(child instanceof Node)) {
|
||||
if (!batch) {
|
||||
const children = this.getChildren(true)
|
||||
const children = this.getChildren(true) || []
|
||||
|
||||
if (!~children.indexOf(child.data)) {
|
||||
insertNode({ arr: children, index, item: child.data })
|
||||
|
|
|
@ -12,7 +12,7 @@
|
|||
|
||||
import PopupManager from './popup-manager'
|
||||
import PopperJS from './popper'
|
||||
import { on } from './dom'
|
||||
import { on, off, isDisplayNone } from './dom'
|
||||
import type { ISharedRenderlessFunctionParams } from 'types/shared.type'
|
||||
import type Popper from './popper'
|
||||
|
||||
|
@ -92,7 +92,7 @@ export default (options: IPopperInputParams) => {
|
|||
const { followReferenceHide = true } = props?.popperOptions || {}
|
||||
const { _popper: popper, _reference: reference } = popperInstance
|
||||
|
||||
if (followReferenceHide && getComputedStyle(reference).position !== 'fixed' && reference.offsetParent === null) {
|
||||
if (followReferenceHide && isDisplayNone(reference)) {
|
||||
popper.style.display = 'none'
|
||||
}
|
||||
}
|
||||
|
@ -108,7 +108,7 @@ export default (options: IPopperInputParams) => {
|
|||
return
|
||||
}
|
||||
|
||||
const options = props.popperOptions || {}
|
||||
const options = props.popperOptions || { gpuAcceleration: false }
|
||||
state.popperElm = state.popperElm || props.popper || vm.$refs.popper || popperVmRef.popper
|
||||
const popper = state.popperElm
|
||||
let reference = getReference({ state, props, vm, slots })
|
||||
|
@ -185,6 +185,7 @@ export default (options: IPopperInputParams) => {
|
|||
const destroyPopper = (remove: 'remove' | boolean) => {
|
||||
if (remove) {
|
||||
if (state.popperElm) {
|
||||
off(state.popperElm, 'click', stop)
|
||||
state.popperElm.remove()
|
||||
}
|
||||
}
|
||||
|
@ -207,13 +208,17 @@ export default (options: IPopperInputParams) => {
|
|||
onBeforeUnmount(() => {
|
||||
nextTick(() => {
|
||||
doDestroy(true)
|
||||
if (props.appendToBody || props.popperAppendToBody) {
|
||||
destroyPopper('remove')
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
onDeactivated(() => {
|
||||
doDestroy(true)
|
||||
if (props.appendToBody || props.popperAppendToBody) {
|
||||
destroyPopper('remove')
|
||||
}
|
||||
})
|
||||
|
||||
return { updatePopper, destroyPopper, doDestroy, ...toRefs(state) }
|
||||
|
|
|
@ -202,7 +202,7 @@ export const DATEPICKER = {
|
|||
queryClass: '.tiny-picker-panel__content',
|
||||
disableClass: '.time-select-item:not(.disabled)',
|
||||
defaultClass: '.default',
|
||||
Qurtyli: 'li',
|
||||
Qurtyli: '[data-tag="li"]',
|
||||
MappingKeyCode: { 40: 1, 38: -1 },
|
||||
DatePicker: 'DatePicker',
|
||||
TimePicker: 'TimePicker'
|
||||
|
|
|
@ -12,7 +12,7 @@
|
|||
|
||||
import { isPlainObject, isNumber, isNumeric, isNull } from './type'
|
||||
import { getObj, toJsonStr } from './object'
|
||||
import { toFixed } from './decimal'
|
||||
import { toFixed, Decimal } from './decimal'
|
||||
|
||||
/**
|
||||
* 文本替换格式类型
|
||||
|
@ -711,7 +711,7 @@ export const toBoolValue = (value) => {
|
|||
* @returns {String}
|
||||
*/
|
||||
export const toRate = (value, total = 1, fraction = 2) =>
|
||||
isNumber(value) && isNumber(total) ? `${toDecimal((value * 100) / total, fraction)}%` : value
|
||||
isNumber(value) && isNumber(total) ? toDecimal(Decimal(value).mul(100).div(total).toNumber(), fraction) + '%' : value
|
||||
|
||||
/**
|
||||
* 文件大小值 单位互相转换。
|
||||
|
|
|
@ -23,13 +23,13 @@ export const computedAnimationName =
|
|||
export const computedAddUnit = (value: string): string => (isNaN(Number(value)) ? value : value + 'px')
|
||||
|
||||
export const computedStyle =
|
||||
({ props, state }: Pick<IDialogBoxRenderlessParams, 'props' | 'state'>) =>
|
||||
({ props, state, designConfig }: Pick<IDialogBoxRenderlessParams, 'props' | 'state' | 'designConfig'>) =>
|
||||
(): IDialogBoxStyle => {
|
||||
const style = {} as IDialogBoxStyle
|
||||
let style = {} as IDialogBoxStyle
|
||||
let { width, top, rightSlide, maxHeight } = props
|
||||
|
||||
if (top === undefined) {
|
||||
top = rightSlide ? '0' : '15vh'
|
||||
top = rightSlide ? '0' : designConfig?.state?.top ? '' : '15vh'
|
||||
}
|
||||
|
||||
width = computedAddUnit(width)
|
||||
|
@ -49,6 +49,10 @@ export const computedStyle =
|
|||
}
|
||||
}
|
||||
|
||||
if (state.dragStyle) {
|
||||
style = { ...style, ...state.dragStyle }
|
||||
}
|
||||
|
||||
return style
|
||||
}
|
||||
|
||||
|
@ -155,15 +159,35 @@ export const unMounted =
|
|||
}
|
||||
}
|
||||
|
||||
export const useMouseEventDown =
|
||||
({ state }: Pick<IDialogBoxRenderlessParams, 'state'>) =>
|
||||
(event: MouseEvent): void => {
|
||||
state.mouseDownWrapperFlag = false
|
||||
if (/tiny-dialog-box__wrapper/.test(event.target.className) && event.type === 'mousedown') {
|
||||
state.mouseDownWrapperFlag = true
|
||||
}
|
||||
}
|
||||
|
||||
export const useMouseEventUp =
|
||||
({ state }: Pick<IDialogBoxRenderlessParams, 'state'>) =>
|
||||
(event: MouseEvent): void => {
|
||||
state.mouseUpWrapperFlag = false
|
||||
if (/tiny-dialog-box__wrapper/.test(event.target.className) && event.type === 'mouseup') {
|
||||
state.mouseUpWrapperFlag = true
|
||||
}
|
||||
}
|
||||
|
||||
export const handleWrapperClick =
|
||||
({ api, props }: Pick<IDialogBoxRenderlessParams, 'api' | 'props'>) =>
|
||||
({ api, props, state }: Pick<IDialogBoxRenderlessParams, 'api' | 'props' | 'state'>) =>
|
||||
(): void => {
|
||||
if (!props.closeOnClickModal) {
|
||||
return
|
||||
}
|
||||
|
||||
// mouseDownFlag、mouseUpFlag判断是否点击wrapper状态
|
||||
if (state.mouseDownWrapperFlag && state.mouseUpWrapperFlag) {
|
||||
api.handleClose('mask')
|
||||
}
|
||||
}
|
||||
|
||||
export const handleClose =
|
||||
({
|
||||
|
@ -315,8 +339,8 @@ export const handleDrag =
|
|||
top = event.clientY < 0 ? -disY : top > maxY ? maxY : top
|
||||
}
|
||||
|
||||
modalBoxElem.style.left = `${left}px`
|
||||
modalBoxElem.style.top = `${top}px`
|
||||
state.dragStyle = { left: `${left}px`, top: `${top}px` }
|
||||
|
||||
state.left = `${left}px`
|
||||
state.top = `${top}px`
|
||||
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue