table组件完成

This commit is contained in:
chuan_wuhao 2022-12-09 16:00:39 +08:00
parent 26d8050fff
commit 73110d5e2a
13 changed files with 514 additions and 30 deletions

View File

@ -4,4 +4,5 @@ auto-imports.d.ts
components.d.ts
.gitignore
.vscode
public
public
yarn.*

1
components.d.ts vendored
View File

@ -10,5 +10,6 @@ declare module '@vue/runtime-core' {
RayTransitionComponent: typeof import('./src/components/RayTransitionComponent/index.vue')['default']
RouterLink: typeof import('vue-router')['RouterLink']
RouterView: typeof import('vue-router')['RouterView']
TableSetting: typeof import('./src/components/RayTable/src/components/TableSetting/index.vue')['default']
}
}

View File

@ -0,0 +1,51 @@
$iconSpace: 5px;
$width: 140px;
$activedColor: #2080f0;
.ray-table__setting-option--draggable {
display: grid;
grid-template-columns: repeat(1, $width);
grid-gap: 10px 0;
justify-items: center;
align-items: center;
justify-content: center;
& .draggable-item {
display: flex;
align-items: center;
cursor: pointer;
&:hover {
& .draggable-item__d--icon {
opacity: 1;
}
}
& .draggable-item__d--icon {
transition: opacity 0.3s var(--r-bezier), transform 0.3s var(--r-bezier);
opacity: 0;
}
& .draggable-item__d--icon,
& .draggable-item__icon {
padding: $iconSpace;
outline: none;
border: none;
}
& .draggable-item__icon {
cursor: pointer;
}
& .draggable-item__icon {
&.draggable-item__icon--actived {
color: $activedColor;
}
}
& .n-ellipsis {
max-width: 71px;
min-width: 71px;
}
}
}

View File

@ -9,15 +9,157 @@
* @remark
*/
import './index.scss'
import { NCard, NPopover, NEllipsis, NCheckbox } from 'naive-ui'
import RayIcon from '@/components/RayIcon/index'
import VueDraggable from 'vuedraggable'
import type {
RayTableProvider,
SettingOptions,
ActionOptions,
} from '@/components/RayTable/src/type'
const TableSetting = defineComponent({
name: 'TableSetting',
setup() {
return {}
emits: ['columnsUpdate'],
setup(_, { emit }) {
const rayTableProvider = inject('rayTableProvider', {} as RayTableProvider)
const settingOptions = ref(rayTableProvider.modelColumns.value) // 表格表头
const disableDraggable = ref(true) // 拖拽开关
const handleDraggableEnd = () => {
emit('columnsUpdate', settingOptions.value)
}
/**
*
* @param type
* @param idx
*
* @remark
*/
const handleFiexClick = (type: 'left' | 'right', idx: number) => {
const key = `${type}FiexActivated`
const value = settingOptions.value[idx]
value[key] = !value[key]
if (value[key]) {
value.fixed = type
} else {
value.fixed = void 0
}
settingOptions.value[idx] = value
emit('columnsUpdate', settingOptions.value)
}
return {
settingOptions,
handleDraggableEnd,
handleFiexClick,
disableDraggable,
}
},
render() {
return <></>
return (
<NPopover trigger="click" placement="bottom" showArrow={false} raw>
{{
trigger: () => (
<RayIcon
customClassName="ray-table__setting"
name="setting"
size="18"
/>
),
default: () => (
<NCard bordered={false} segmented={{ content: 'soft' }}>
{{
default: () => (
<VueDraggable
class={['ray-table__setting-option--draggable']}
v-model={this.settingOptions}
itemKey="key"
disabled={!this.disableDraggable}
onEnd={this.handleDraggableEnd.bind(this)}
>
{{
item: ({
element,
index,
}: {
element: ActionOptions
index: number
}) => (
<div class={['draggable-item']}>
<RayIcon
customClassName={`draggable-item__d--icon`}
name="draggable"
size="18"
/>
<NEllipsis>
<span>{element.title}</span>
</NEllipsis>
<NPopover>
{{
trigger: () => (
<RayIcon
customClassName={`draggable-item__icon ${
element.leftFiexActivated
? 'draggable-item__icon--actived'
: ''
}`}
name="left_arrow"
size="18"
onClick={this.handleFiexClick.bind(
this,
'left',
index,
)}
/>
),
default: () => '向左固定',
}}
</NPopover>
<NPopover>
{{
trigger: () => (
<RayIcon
customClassName={`draggable-item__icon ${
element.rightFiexActivated
? 'draggable-item__icon--actived'
: ''
}`}
name="right_arrow"
size="18"
onClick={this.handleFiexClick.bind(
this,
'right',
index,
)}
/>
),
default: () => '向右固定',
}}
</NPopover>
</div>
),
}}
</VueDraggable>
),
header: () => (
<NCheckbox v-model:checked={this.disableDraggable}>
</NCheckbox>
),
}}
</NCard>
),
}}
</NPopover>
)
},
})

View File

@ -10,42 +10,135 @@
*/
import './index.scss'
import { NDataTable, NCard } from 'naive-ui'
import { NDataTable, NCard, NDropdown } from 'naive-ui'
import props from './props'
import RayIcon from '@/components/RayIcon/index'
import TableSetting from './components/TableSetting/index'
import type { ActionOptions } from './type'
import type { WritableComputedRef } from 'vue'
import type { DropdownOption } from 'naive-ui'
const RayTable = defineComponent({
name: 'RayTable',
props: props,
setup(props) {
emits: ['update:columns', 'menuSelect'],
setup(props, { emit }) {
const modelRightClickMenu = computed(() => props.rightClickMenu)
const modelColumns = computed({
get: () => props.columns,
set: (arr) => {
emit('update:columns', arr)
},
}) as unknown as WritableComputedRef<ActionOptions[]>
const menuConfig = reactive({
x: 0,
y: 0,
showMenu: false,
})
let prevRightClickIndex = -1
provide('rayTableProvider', {
modelRightClickMenu,
modelColumns,
})
return {}
const handleColumnsUpdate = (arr: ActionOptions[]) => {
modelColumns.value = arr
}
/**
*
* @param key `key`
* @param option `item`
*
* @remark (key: string | number, index: number,option: DropdownOption) => void
*/
const handleRightMenuSelect = (
key: string | number,
option: DropdownOption,
) => {
emit('menuSelect', key, prevRightClickIndex, option)
menuConfig.showMenu = false
}
/**
*
* @param arr
* @param idx
* @returns
*
* @remark , ,
*/
const handleRowProps = (arr: ActionOptions, idx: number) => {
const interceptRowProps = props.rowProps?.(arr, idx)
return {
...interceptRowProps,
onContextmenu: (e: MouseEvent) => {
e.preventDefault()
prevRightClickIndex = idx
menuConfig.showMenu = false
nextTick().then(() => {
menuConfig.showMenu = true
menuConfig.x = e.clientX
menuConfig.y = e.clientY
})
},
}
}
return {
handleColumnsUpdate,
...toRefs(menuConfig),
handleRowProps,
handleRightMenuSelect,
}
},
render() {
return (
<NCard bordered={false}>
{{
default: () => (
<NDataTable {...this.$props}>
{{
empty: () => this.$slots?.empty,
loading: () => this.$slots?.loading,
}}
</NDataTable>
<div>
<NDataTable
{...this.$props}
rowProps={this.handleRowProps.bind(this)}
>
{{
empty: () => this.$slots?.empty,
loading: () => this.$slots?.loading,
}}
</NDataTable>
{this.showMenu ? (
<NDropdown
show={this.showMenu}
placement="bottom-start"
trigger="manual"
x={this.x}
y={this.y}
options={this.rightClickMenu}
onClickoutside={() => (this.showMenu = false)}
onSelect={this.handleRightMenuSelect.bind(this)}
/>
) : (
''
)}
</div>
),
header: () => this.title,
'header-extra': () => (
<RayIcon
customClassName="ray-table__setting"
name="setting"
size="18"
/>
),
'header-extra': () =>
this.action ? (
<TableSetting
onColumnsUpdate={this.handleColumnsUpdate.bind(this)}
/>
) : (
''
),
}}
</NCard>
)
@ -53,3 +146,16 @@ const RayTable = defineComponent({
})
export default RayTable
/**
*
* `NDataTable`
*
* , ,
*
* , `showMenu` 使
*
* `action` `false`
*
* `props` , `props.ts`
*/

View File

@ -58,6 +58,16 @@ const rayTableProps = {
type: Object as PropType<VNode>,
default: () => ({}),
},
showMenu: {
/**
*
*
*
*
*/
type: Boolean,
default: true,
},
} as const
export default rayTableProps
@ -66,5 +76,5 @@ export default rayTableProps
*
* `Ray Table Props`
*
* `naive ui Data Table`
* `Naive UI Data Table`
*/

View File

@ -3,13 +3,26 @@ import type {
DropdownGroupOption,
DropdownDividerOption,
DropdownRenderOption,
DataTableColumns,
DataTableBaseColumn,
} from 'naive-ui'
import type { ComputedRef, WritableComputedRef } from 'vue'
export interface ActionOptions extends DataTableColumns {}
export interface ActionOptions extends DataTableBaseColumn {
leftFiexActivated?: boolean // 向左固定
rightFiexActivated?: boolean // 向右固定
}
export type DropdownMixedOption =
| DropdownOption
| DropdownGroupOption
| DropdownDividerOption
| DropdownRenderOption
export type SettingOptions = WritableComputedRef<ActionOptions[]>
export type RightClickMenu = ComputedRef<DropdownMixedOption[]>
export interface RayTableProvider {
modelRightClickMenu: RightClickMenu
modelColumns: SettingOptions
}

3
src/icons/draggable.svg Normal file
View File

@ -0,0 +1,3 @@
<svg t="1670566360312" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="23119" width="64" height="64">
<path fill="currentColor" d="M368 672a64 64 0 1 1 0 128 64 64 0 0 1 0-128z m288 0a64 64 0 1 1 0 128 64 64 0 0 1 0-128zM368 448a64 64 0 1 1 0 128 64 64 0 0 1 0-128z m288 0a64 64 0 1 1 0 128 64 64 0 0 1 0-128z m-288-224a64 64 0 1 1 0 128 64 64 0 0 1 0-128z m288 0a64 64 0 1 1 0 128 64 64 0 0 1 0-128z" p-id="23120"></path>
</svg>

After

Width:  |  Height:  |  Size: 475 B

3
src/icons/left_arrow.svg Normal file
View File

@ -0,0 +1,3 @@
<svg t="1670552678924" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="21515" width="64" height="64">
<path d="M473.6 490.666667L789.333333 170.666667 853.333333 230.4l-260.266666 260.266667 260.266666 260.266666-64 59.733334-315.733333-320z m-302.933333 0L490.666667 170.666667l59.733333 59.733333-260.266667 260.266667 260.266667 260.266666-59.733333 59.733334L170.666667 490.666667z" fill="currentColor" p-id="21516"></path>
</svg>

After

Width:  |  Height:  |  Size: 480 B

View File

@ -0,0 +1,3 @@
<svg t="1670552691680" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="21718" width="64" height="64">
<path d="M550.4 490.666667L230.4 170.666667 170.666667 230.4l260.266666 260.266667L170.666667 750.933333 230.4 810.666667l320-320z m298.666667 0L533.333333 170.666667 469.333333 230.4l260.266667 260.266667-260.266667 260.266666 59.733334 59.733334 320-320z" fill="currentColor" p-id="21719"></path>
</svg>

After

Width:  |  Height:  |  Size: 453 B

View File

@ -1,4 +1,5 @@
@import "@/styles/animate.scss";
@import "@/styles/root.scss";
body,
h1,

3
src/styles/root.scss Normal file
View File

@ -0,0 +1,3 @@
:root {
--r-bezier: cubic-bezier(0.4, 0, 0.2, 1);
}

View File

@ -9,26 +9,173 @@
* @remark
*/
import { NLayout, NCard } from 'naive-ui'
import { NLayout, NCard, NTag, NButton } from 'naive-ui'
import RayTable from '@/components/RayTable/index'
import type { DataTableColumns } from 'naive-ui'
type RowData = {
key: number
name: string
age: number
address: string
tags: string[]
}
const TableView = defineComponent({
name: 'TableView',
setup() {
return {}
const baseColumns = [
{
title: 'Name',
key: 'name',
},
{
title: 'Age',
key: 'age',
},
{
title: 'Address',
key: 'address',
},
{
title: 'Tags',
key: 'tags',
render: (row: RowData) => {
const tags = row.tags.map((tagKey) => {
return h(
NTag,
{
style: {
marginRight: '6px',
},
type: 'info',
bordered: false,
},
{
default: () => tagKey,
},
)
})
return tags
},
},
{
title: 'Action',
key: 'actions',
render: (row: RowData) =>
h(
NButton,
{
size: 'small',
},
{ default: () => 'Send Email' },
),
},
]
const actionColumns = ref<DataTableColumns<RowData>>(
[...baseColumns].map((curr) => ({ ...curr, width: 400 })),
)
const tableData = ref([
{
key: 0,
name: 'John Brown',
age: 32,
address: 'New York No. 1 Lake Park',
tags: ['nice', 'developer'],
},
{
key: 1,
name: 'Jim Green',
age: 42,
address: 'London No. 1 Lake Park',
tags: ['wow'],
},
{
key: 2,
name: 'Joe Black',
age: 32,
address: 'Sidney No. 1 Lake Park',
tags: ['cool', 'teacher'],
},
])
const tableMenuOptions = [
{
label: '编辑',
key: 'edit',
},
{
label: () => h('span', { style: { color: 'red' } }, '删除'),
key: 'delete',
},
]
const handleMenuSelect = (key: string | number, idx: number) => {
if (key === 'delete') {
tableData.value.splice(idx, 1)
}
}
return {
tableData,
actionColumns,
baseColumns,
tableMenuOptions,
handleMenuSelect,
}
},
render() {
return (
<NLayout>
<NCard title="RayTable">
Naive UI DataTable . , ,
<p>
Naive UI DataTable . , ,
</p>
<p>RayTable DataTable </p>
<p>
props ,
src/components/RayTable/src/props.ts
</p>
</NCard>
<NCard title="基础使用" style={['margin-top: 18px']}>
<RayTable title="基础表格" />
<RayTable
title="基础表格"
data={this.tableData}
columns={this.baseColumns}
action={false}
/>
</NCard>
<NCard style={['margin-top: 18px']}>
<RayTable />
{{
header: () => (
<div>
<p>
使 columns action
</p>
<p></p>
<p>, </p>
</div>
),
default: () => (
<RayTable
title="带有拓展功能的表格"
data={this.tableData}
v-model:columns={this.actionColumns}
/>
),
}}
</NCard>
<NCard title="右键菜单" style={['margin-top: 18px']}>
<RayTable
title="右键菜单表格"
action={false}
data={this.tableData}
columns={this.baseColumns}
rightClickMenu={this.tableMenuOptions}
onMenuSelect={this.handleMenuSelect.bind(this)}
/>
</NCard>
</NLayout>
)