// tooltip 中内容太长,导致超出屏幕,使用以下设置:
// - width: 'trigger', 宽度指定为父元素宽度
tooltip: {
width: 'trigger'
}
// tooltip 背景色和前景色差距不大导致不易读
// - filter: 'brightness', 提高前景色亮度
tooltip: {
contentStyle: {
filter: 'brightness(3)'
}
}
// 当表格出现横向滚动条时,最右侧的"操作"列(固定列)没有完全覆盖下方内容,导致出现视觉上的错位。
// 表格中的字段使用ecllipsis时,文本不能垂直居中
h(
NEllipsis,
{ lineClamp: 1, tooltip: { width: 'trigger' }, style: {'vertical-align': 'middle'} },
() => 'xxx'
)
// 前后端需要使用日期字符串
h(NDatePicker, {
valueFormat: 'yyyy-MM-dd',
class: 'w-full',
type: 'date',
formattedValue: formItem.value.value,
onUpdateFormattedValue: (value) => {
formItem.value.value = value
},
placeholder: '设备有效截止日期',
})
// naive ui card -ncard 设置高度,内部使用滚动条
// 因为card-content 使用了flex-1 所以就算给content-style 设置指定的高度
// n-scrollbar 滚动条高度100% 获取到的真实高度为空
// 此时应该将content 高度设置为0
import {toNumber} from '@/utils/number/number'
/**
* 转换为数值
* 只有当结果既不是 NaN 也不是无穷大时才返回结果
* @param value
* @returns
*/
export function toNumber(value: any): number | null {
const result = lodashToNumber(value)
if (!isNaN(result) && isFinite(result)) {
return result
}
return null
}
// 回显的时候需要保证value 是数值或null,如果先编辑再新增,此时表单项的值如果是undefined,value可能还是为上一次编辑的值,因此toNumber 需要返回null
<n-input-number v-model:value="toNumber(value)" />
回显时值必须是文本,否则会报错
/**
* 转换为字符串
* @param value
* @returns
*/
export function toString(value: any): string | null {
if (value === undefined || value === null) {
return null
}
return String(value)
}
// constructor 会导致报错
{
label: '施工单位',
key: 'constructor',
value: ref(null),
render: (formItem) => {
return h(NInput, {
value: formItem.value.value,
maxlength: 100,
showCount: true,
clearable: true,
onUpdateValue: (val) => {
formItem.value.value = val
},
placeholder: '施工单位',
})
},
},function handleFinish(options) {
// {
// "code": 200,
// "msg": "操作成功",
// "data": {
// "url": "http://172.16.97.202:9800/auth/2025/10/27/637efdecc24f45229fe219e0d4b79a89.png",
// "fileName": "下载.png",
// "ossId": "1982734315162771457"
// }
// }
const res = options.event.currentTarget.response;
}h(NLayout, {
style: {height: `calc(100vh - ${headerHeight.value}px - 86px)` }
}, {
default: () => [
h(NLayoutHeader, {
style: 'height: 64px; padding: 24px',
bordered: true
}, {
default: () => 666
}),
h(NLayout, {
hasSider: true,
position: 'absolute',
style: 'top: 64px; bottom: 64px'
}, {
default: () => [
h(NLayoutSider, {
bordered: true,
nativeScrollbar: false,
contentStyle: 'padding: 24px;'
}, {
default: () => h('div', {style: {height: '500px', background: 'red'}}, '123')
}),
h(NLayout, {
contentStyle: 'padding: 24px;',
nativeScrollbar: false
}, {
default: () => 234
})
]
}),
h(NLayoutFooter, {
bordered: true,
position: 'absolute',
style: 'height: 64px; padding: 24px'
}, {
default: () => 999
})
]
}) <n-layout :style="{ height: `calc(100vh - ${headerHeight}px - 86px)` }">
<!-- Header -->
<n-layout-header style="height: 64px; padding: 24px" bordered>
666
</n-layout-header>
<!-- Main Content with Sider -->
<n-layout has-sider position="absolute" style="top: 64px; bottom: 64px">
<n-layout-sider bordered :native-scrollbar="false" content-style="padding: 24px;">
<div style="height: 500px; background: red;">123</div>
</n-layout-sider>
<n-layout content-style="padding: 24px;" :native-scrollbar="false">
234
</n-layout>
</n-layout>
<!-- Footer -->
<n-layout-footer bordered position="absolute" style="height: 64px; padding: 24px">
999
</n-layout-footer>
</n-layout>import hljs from 'highlight.js/lib/core'
import json from 'highlight.js/lib/languages/json'
hljs.registerLanguage('json', json)
h('div', {
style: { whiteSpace: 'pre' },
innerHTML: hljs.highlight(value, { language: 'json' }).value
})
import { useDraggable } from 'vue-draggable-plus'
const tableRef = ref<any>()
async function draggableTable() {
if (tableRef.value && table.dataList.value.length > 0) {
await nextTick()
const itemsContainer = tableRef.value.$el.querySelector('.n-data-table-tbody')
if (itemsContainer) {
useDraggable(itemsContainer, table.dataList, {
animation: 150,
onUpdate() {
console.log('update')
}
})
}
{
console.warn('draggableTable itemsContainer is null')
}
}
}
// 拖动表格排序
async function draggableTable() {
async function draggableTable() {
if (tableRef.value && table.dataList.value.length > 0) {
await nextTick()
const itemsContainer = tableRef.value.$el.querySelector('.n-data-table-tbody')
if (itemsContainer) {
useDraggable(itemsContainer, table.dataList, {
animation: 150,
onUpdate(event: any) {
const { newIndex, oldIndex } = event
const rowData = table.dataList.value[newIndex]
if (newIndex > oldIndex) {
// 向下移动
const preMaxOrder = table.dataList.value
.slice(0, newIndex)
.reduce((max, item) => {
return Math.max(max, item.itemOrder ?? 0)
}, newIndex - 1)
rowData.itemOrder = preMaxOrder + 1
onUpdateItem(rowData)
} else {
// 向上移动
const nextMinOrder = table.dataList.value.slice(newIndex+1).reduce((min, item) => {
return Math.min(min, item.itemOrder ?? 0)
}, newIndex + 1)
rowData.itemOrder = nextMinOrder - 1
onUpdateItem(rowData)
}
}
})
}
{
console.warn('draggableTable itemsContainer is null')
}
}
}```
## ellipsis 使用
// align-middle 文本垂直居中 h(NEllipsis, {class: 'align-middle'}, { default: () => h('span', {}, item?.option?.categoryName) })
## 组件 颜色如何做到调整背景颜色其他内部颜色自动跟随变化
naive ui 组件默认支持以下属性:
theme => 只能获取到最原始的配置,只能切换dark和light,具体样式大概率被其他设置覆盖
themeOverrides => 可以使用
builtinThemeOverrides
naive ui组件中有以下变量(决定最后的css样式):
mergedTheme -> themeRef -> useTheme()
cssVars -> cssVarsRef -> themeRef
组件初始化完成后获取mergedTheme,再手动设置到themeOverrides
## 带装饰的标题
input 的 ref 使用函数,el为input组件实例
h(NTooltip, {
},
{
trigger: () => h(NButton, {
size: 'small',
text: true,
},
{
icon: () => h(NIcon, {component: StepForwardFilled}),
}),
default: () =>h(NInput, {
ref: async (el:any)=>{
await nextTick()
el?.focus()
},
})
])
含过滤时,搜索框有clearable,搜索框不能使用v-model="pattern",必须使用:value="pattern" @update:value="(val)=>pattern=val!=null&&val!=undefined?val:''",否则会报错
// 滚动条
:scroll-x="tableColumns.reduce((sum, col) => sum + (col.width as number ?? 0), 0)"
<n-cascader
v-model:value="value_"
:options="options"
remote
:filterable="true"
:clearable="clearable"
@load="handleLoad"
:show-path="true"
check-strategy="child"
:render-label="renderLabel"
@update:value="handleUpdateValue"
:theme-overrides="{columnWidth:'fit-content'}"
/>