@meleon/uni-ui
v1.2.0
Published
A uniapp components library written in vue3 and typescript
Downloads
285
Maintainers
Readme
开发指南
一、快速上手
演示
使用微信扫描下方的小程序码,在线查看组件的渲染效果。
[注:如果因为网络等原因,小程序码图片无法加载,也可以直接输入 Meleon Uni-ui
关键字查询]
安装
# npm
npm install @meleon/uni-ui
引入
H5 端
import MeleonUI from "@meleon/uni-ui"
export function createApp() {
const app = createSSRApp(App)
app.use(MeleonUI)
return { app }
}
微信小程序端
对比分别在项目入口文件 main.ts 和组件库的入口文件 meleon-ui.ts 里注册的组件,被编译到微信小程序上的结果:
// main.ts
import { createSSRApp } from 'vue'
import MeleonUI from "@meleon/uni-ui";
import MlButton from '@meleon/uni-ui/lib/ml-button/index.vue'
import App from './App.vue'
export function createApp() {
const app = createSSRApp(App)
app.use(MeleonUI)
app.component('MlButtonGlobal', MlButton)
return {
app
}
}
// meleon-ui.ts
import type { App, Plugin } from 'vue'
import MlButton from './ml-button'
const components: Record<string, Plugin> = {
MlButton,
}
const install = (app: App) => {
for (const key in components) {
if (Object.prototype.hasOwnProperty.call(components, key)) {
app.use(components[key])
}
}
}
const MeleonUI = { install }
export default MeleonUI
// ml-button/index.ts
import type { App } from 'vue'
import _Button from './index.vue'
const install = async (app: App) => {
app.component('MlButton', _Button)
}
export default { install }
虽然本质上都是使用 app.component
实现注册组件,但 uniapp 编译的结果却并不完全相同
在 main.ts
中注册 MlButtonGroup
组件被编译成函数
而 meleon-ui.ts
里的组件被编译成对象
在使用时也是前者可以被正常渲染成组件展示到页面上
因此,如果希望在微信小程序端实现批量注册组件,需要使用 uniapp 提供的 easycom
方法
详细内容可跳转:https://uniapp.dcloud.net.cn/collocation/pages.html#easycom
// page.json
{
"easycom": {
"custom": {
"^ml-(.*)": "@meleon/uni-ui/lib/ml-$1/index.vue"
}
}
}
二、定制主题
MeleonUI 为用户提供了自定义主题的方法,可以通过向 ml-config-provider
组件传入 themes
属性,同时修改当前页面所有 ml- 组件的主题色
<!-- template -->
<ml-config-provider :themes="themes">
<!-- 消息提示 -->
<ml-message ref="messageRef" />
<!-- 导航栏 -->
<ml-navigator
:title="$t('home.navigation.title')"
title-color="#FFFFFF"
background="#7A98B3"
></ml-navigator>
<ml-button
type="primary"
@click="onNavigate('/pages/componentList/index')"
>
{{ $t('home.actions.start') }}
<ml-icon icon="ml-arrow-right--line" color="#FFFFFF" />
</ml-button>
</ml-config-provider>
// script
import type { ConfigProviderProps } from '@meleon/uni-ui'
const themes: ConfigProviderProps['themes'] = {
primary: '#D74B4B',
}
themes 支持以下属性,可根据项目的设计风格批量修改,当然,直接通过 CSS 修改样式也是可以的。
export type ColorType = 'primary' | 'info' | 'success' | 'warning' | 'danger'
三、类型声明
在使用组件时,为了得到更好的类型提示,可以在 tsconfig.json
中注入 MeleonUI
的类型声明文件,如下所示。
如果你的编辑器中安装了 Volar
插件,注入成功后应该可以看到组件标签的颜色发生了变化,且当尝试传入组件 props 时,编辑器也会给出可选值的提示信息。
{
"types": ["@dcloudio/types", "@meleon/uni-ui"]
}
四、更新日志
1.2.0
- refactor: 打包结果调整
- 去除初始的 .ts 文件
- 去除用于 重新导出 的
index.js
和index.d.ts
文件 - 使用 terser 压缩代码,大幅降低组件库构建到小程序后的体积
@meleon/uni-ui
小程序主包的构建体积从优化前的 2.2MB 降低到现在的 958KB- **注:**如果准备将
1.1
版本升级到1.2
版本,最好检查下之前对组件库内部方法、类型的引用路径是否存在问题,避免出现 bug
- feat: 调整
ml-form
组件,添加下拉选框、多选、日期选择器、开关等表单项
- refactor: 打包结果调整
1.1.13
- feat: 新增
ml-form
组件【暂时仅支持 input 组件作为表单项】 - feat: 新增
ml-transition
组件
- feat: 新增
1.1.12
- style:
ml-drawer
组件添加动效 - fix:
ml-list
组件修改虚拟列表插槽名称错误 - feat: 新增
ml-datetime-picker
、ml-time-picker
两个时间选择组件
- style:
1.1.11
- feat: 调整
ml-navigator
组件的结构,完善功能 - feat: 添加
ml-switch
组件 - feat:
ml-cell
组件添加SWITCH
类型 - fix:
ml-cell
组件传入的 value 发生变化时未触发页面更新 - feat: 新增
ml-list
组件,初步支持基础列表和虚拟列表功能
- feat: 调整
1.1.10
- fix:
ml-checkbox
设置 direction 失效的问题 - fix:
ml-image
预览层层级过低的问题 - fix:
ml-select
无激活样式的问题 - fix:
ml-input-tag
确认后未触发新增标签 - docs:
@meleon/uni-ui
上线微信小程序,可体验各个组件的使用效果【微信扫描“演示”小程序码】
- fix:
1.1.9
- fix:
ml-loading
图标缺失,ml-button
组件设置 loading 不生效 - feat: 新增
ml-image
组件 - feat:
ml-tree
组件模块拆分,支持自定义 title 节点 - feat: 新增
ml-icon-switcher
小组件 - fix:
ml-button
单图标按钮图标偏移的问题 - feat:
ml-tree
组件基本功能完善,支持文本选中、复选框选择、自定义标题节点等 - fix: 去除
ml-checkbox
组件无文本时样式的偏移 - feat:
ml-tree
组件新增对外暴露的 expand、check 及 select 等方法
- fix:
1.1.8
- feat: 新增
ml-cell
、ml-cell-group
组件 - feat: 新增
ml-uploader
组件
- feat: 新增
1.1.7
- feat: 新增
ml-config-provider
组件 - docs: 调整项目接口,补全TS类型,新增 README 文档
- feat: 新增
组件
头像 Avatar
基本使用
如果头像内容是文字的话,会自动调节字体大小,来适应头像框
<!-- 基础使用 -->
<ml-avatar>Meleon</ml-avatar>
<!-- 设置尺寸 -->
<ml-avatar :size="36">Meleon</ml-avatar>
<!-- 设置形状 -->
<ml-avatar :size="28" shape="circle">Meleon</ml-avatar>
<!-- 插入图片 -->
<ml-avatar shape="circle">
<image src="@/assets/home/avatar.png" mode="widthFix" />
</ml-avatar>
APIs
| prop | type | default | | ----- | ---------------- | ------- | | size | number | 32 | | shape | square | circle | square |
Slots
| name | desc | | ------- | ------------------------ | | default | 默认插槽,传递文本或图片 |
头像组 AvatarGroup
基本使用
除了 maxCount 等属性,还可以传入 Avatar 的 size、shape 等属性实现批量设置
<ml-avatar-group :size="36" :offset="10" shape="circle">
<ml-avatar>Meleon</ml-avatar>
<ml-avatar>Aliee</ml-avatar>
<ml-avatar>Bob</ml-avatar>
</ml-avatar-group>
APIs
| prop | type | default | desc | | -------- | ---------------- | ------- | ---------------------------- | | maxCount | number | 3 | 多出的部分会显示剩余的 count | | offset | number | 0 | 头像组件之前的偏移量 | | size | number | 32 | 头像组件的尺寸 | | shape | square | circle | square | 头像组件的形状 |
按钮 Button
基本使用
<ml-button
type="primary"
size="mini"
status="success"
>
Primary
</ml-button>
<ml-button
type="secondary"
size="mini"
shape="round"
status="success"
>
Secondary
</ml-button>
<ml-button
type="outline"
size="mini"
status="success"
>
Outline
</ml-button>
<ml-button
type="text"
size="mini"
status="success"
@click="handleClick"
>
Text
</ml-button>
APIs
| prop | type | desc | | -------- | --------------------------------------- | ---------- | | type | primary | secondary | outline | text | 按钮类型 | | size | mini | small | medium | large | 按钮尺寸 | | shape | square | round | circle | 按钮形状 | | status | normal | success | warning | danger | 按钮状态 | | loading | boolean | 是否加载中 | | disabled | boolean | 是否禁用 |
Slots
| name | desc | | ------- | ---------------------------- | | default | 默认插槽 | | icon | 图标插槽【位于默认插槽左侧】 |
Emits
| event | dessc | | ----- | -------- | | click | 点击事件 |
单元格 Cell
基本使用
<ml-cell-group title="测试分组" style="width: 100%">
<ml-cell
:type="CellTypeEnum.TEXT"
label="测试标题"
value="测试内容"
description="测试描述"
disabled
allow-edit
style="width: 100%"
@change="handleCellChange"
></ml-cell>
<ml-cell
:type="CellTypeEnum.BUTTON"
label="测试按钮"
btn-status="danger"
disabled
style="width: 100%"
@btn-click="handleClick"
></ml-cell>
<ml-cell
:type="CellTypeEnum.NAV"
label="测试回到首页"
value="回首页"
url="/pages/home/index"
:disabled="false"
style="width: 100%"
>
<template #rightIcon>
<ml-icon name="ml-arrow-right--line" color="var(--info-color-7)"></ml-icon>
</template>
<template #value>
<text style="font-size: 14px; color: var(--info-color-7)">通过插槽展示内容</text>
</template>
</ml-cell>
</ml-cell-group>
APIs
| prop | type | default | desc |
| ----------- | -------------------------------------- | ------- | ----------------------------------------------------------- |
| label | string | '' | 左侧标题 |
| description | string | '' | 左侧描述 |
| value | string | '' | 右侧 值 |
| type | text | button | navigator | text | 单元格类型【推荐使用 CellTypeEnum
枚举变量赋值】 |
| disabled | boolean | false | 是否禁用 |
| allowEdit | boolean | false | 文本单元格是否允许修改 |
| btnStatus | normal | success | warning | danger | normal | 按钮单元格的按钮类型 |
| url | string | '' | 导航单元格的跳转地址【小程序页面地址需要保留前面的 / 字符】 |
Slots
| name | desc | | --------- | ------------------------------------------------------ | | label | 左侧标题插槽【会覆盖默认的 label 和 description 区域】 | | value | 右侧内容插槽 | | rightIcon | 导航单元格生效【覆盖右侧图标】 |
Emits
| name | desc | | -------- | ---------------------------------------------------------- | | change | 文本单元格修改内容后触发 | | btnClick | 按钮单元格点击触发 | | navigate | 导航单元格点击跳转后触发【暂不暴露,考虑有没有必要放出来】 |
CellGroup APIs
| prop | type | default | desc | | ----- | ------ | ------- | -------- | | title | string | '' | 分组名称 |
CellGroup Slots
| name | desc | | ----- | ------------------------ | | title | 标题插槽【覆盖标题内容】 |
选择框 Checkbox
基本使用
<ml-checkbox v-model:checked="checked1">Radio</ml-checkbox>
<ml-checkbox indeterminate>Radio</ml-checkbox>
<ml-checkbox v-model:checked="checked1" disabled>Radio</ml-checkbox>
APIs
| props | type | default | desc | | ------------- | ---------------- | ------- | ----------------------------- | | checked | boolean | false | 是否选中 | | indeterminate | boolean | false | 是否为半选状态 | | disabled | boolean | false | 是否禁用 | | value | string | number | '' | CheckboxGroup 下的 value 标识 |
Slots
| name | desc | | ------- | -------------- | | default | 选择框右侧内容 |
Emits
| event | desc | | -------------- | -------- | | update:checked | 切换事件 |
选择框分组 CheckboxGroup
基本使用
<ml-checkbox-group
v-model:checked-list="checked3"
mode="multi"
:max="3"
:min="1"
>
<ml-checkbox value="A">RadioA</ml-checkbox>
<ml-checkbox value="B">RadioB</ml-checkbox>
<ml-checkbox value="C">RadioC</ml-checkbox>
<ml-checkbox value="D">RadioD</ml-checkbox>
<ml-checkbox value="E">RadioE</ml-checkbox>
</ml-checkbox-group>
APIs
| prop | type | default | desc | | ----------- | ----------------------- | ---------- | -------------- | | checkedList | Array<string | number> | 必填 | 选中的选项列表 | | min | number | 0 | 至少选中数量 | | max | max | Infinity | 至多选中数量 | | direction | vertical | horizontal | horizontal | 纵向或横向排列 | | mode | single | multi | single | 切换单选或多选 |
Emits
| event | desc | | ------------------ | -------------- | | update:checkedList | 更新选中的列表 |
全局配置 ConfigProvider
基本使用
设置全局主题色
<ml-config-provider :themes="themes">
<ml-button type="primary"></ml-button>
<ml-button type="success"></ml-button>
<ml-button type="warning"></ml-button>
<ml-button type="danger"></ml-button>
</ml-config-provider>
import type { ConfigProviderProps } from '~/lib/ml-config-provider/index.interface'
const themes: ConfigProviderProps['themes'] = {
primary: '#D74B4B'
}
APIs
| prop | type | example | | ------ | ----------------------------- | ---------------------- | | themes | ConfigProviderProps['themes'] | { primary: '#D74B4B' } |
数值显示 CountTo
基本使用
<ml-count-to
:from="0"
:to="1250.44"
animation
:animation-duration="5000"
:value-style="{ color: '#0fbf60' }"
>
<template #suffix>
<text>%</text>
</template>
</ml-count-to>
APIs
| prop | type | default | desc | | ----------------- | ------------------- | -------- | ---------------------- | | from | number | 0 | 起始值 | | to | number | required | 结束时展示的数据,必填 | | animation | boolean | false | 是否开启动画 | | animationDuration | number | 1000 | 动画持续时间 | | showSeperator | boolean | false | 是否显示千分位分隔符 | | valueStyle | Record<string, any> | {} | 数据的样式 |
Slots
| name | desc | | ------ | -------------- | | prefix | 数值左侧的内容 | | suffix | 数值右侧的内容 |
Expose
| name | desc | | ------- | -------- | | start | 开启动画 | | pause | 暂停动画 | | restart | 继续动画 |
时间选择器 DatetimePicker
基本使用
<ml-datetime-picker
v-model="value"
mode="date"
:disabled-date="isDateDisabled"
style="width: 100%"
@change="handleValueChange"
>
<template #trigger>
<ml-cell
label="日期选择器"
:value="formatToDateTime(value)"
style="width: 100%"
></ml-cell>
</template>
</ml-datetime-picker>
const value = ref(new Date())
const isDateDisabled = (current: Date) => {
return current.getTime() < new Date().getTime() - 24 * 60 * 60 * 1000
}
const handleValueChange = (value: DatetimePickerProps['modelValue']) => {
console.log('change', value)
}
APIs
| prop | type | default | desc | | ------------------ | -------------------------- | ------------ | ---------------------- | | modelValue | Date, string, number | '' | 选择的日期时间 | | defaultModelValue | Date, string, number | '' | 默认展示的日期时间 | | pickerValue | Date, string, number | '' | 面板头部展示的时间 | | defaultPickerValue | Date, string, number | '' | 面板头部默认展示的时间 | | | | | | | locale | Record<string, any> | {} | 自定义面板中展示的文本 | | mode | 'date', 'year', 'month' | 'date' | 选择器模式 | | format | string | 'YYYY-MM-DD' | 时间转换格式 | | | | | | | disabledDate | (current: Date) => boolean | undefined | 判断日期是否禁用 |
Emits
| name | type | desc | | ----------------- | --------------------- | -------------------- | | change | (value: Date) => void | 选中值发生变化时触发 | | update:modelValue | (value: Date) => void | 双向绑定选中日期 |
抽屉 Drawer
基本使用
<ml-drawer
v-model:visible="modelVisible"
:placement="placement"
:has-nav="hasNav"
>
<template #title>自定义标题</template>
<text>
Lorem ipsum dolor sit amet consectetur adipisicing elit. Magni, dolor libero
blanditiis distinctio commodi totam recusandae aliquam fugit officiis sequi
perspiciatis non animi, eaque facilis sed reiciendis in aut vel.
</text>
<template #footer>
<ml-button>自定义页脚</ml-button>
</template>
</ml-drawer>
APIs
| prop | type | default | desc | | ---------- | ------------------------------ | -------- | ----------------------------------------- | | hasNav | boolean | true | 当前页面有无导航栏,以控制 drawer 高度 | | visible | boolean | required | 是否显示 | | placement | left | right | top | bottom | right | 展开的方向 | | width | number | 250 | placement 为 left | right 时,抽屉的宽度 | | height | number | 250 | placement 为 top | bottom 时,抽屉的高度 | | radius | number | 0 | 抽屉圆角 | | okText | string | 确定 | 底部确认按钮的文本 | | cancelText | string | 取消 | 底部取消按钮的文本 |
Slots
| name | desc | | ------- | -------- | | default | 主体内容 | | title | 标题内容 | | footer | 底部内容 |
Emits
| name | desc | | -------------- | ---------------- | | update:visible | 显示状态变化触发 | | close | 点击取消按钮 | | ok | 点击确认按钮 |
图标 Icon
基本使用
<ml-icon :name="icon" :size="24" color="#808080" />
export default {
id: '4118979',
name: 'MeleonUI',
font_family: 'ml-icon',
css_prefix_text: 'ml-',
description: '',
glyphs: [
{
icon_id: '8106223',
name: 'cancel',
font_class: 'close--circle',
unicode: 'e698',
unicode_decimal: 59032
},
{
icon_id: '8106241',
name: 'information',
font_class: 'info--circle',
unicode: 'e6a5',
unicode_decimal: 59045
},
{
icon_id: '8106248',
name: 'selection',
font_class: 'selection--circle',
unicode: 'e6a6',
unicode_decimal: 59046
},
{
icon_id: '11992738',
name: 'github',
font_class: 'github',
unicode: 'e6a9',
unicode_decimal: 59049
},
{
icon_id: '18531280',
name: 'right arrow',
font_class: 'arrow-right--line',
unicode: 'e701',
unicode_decimal: 59137
},
{
icon_id: '38175316',
name: 'right arrow',
font_class: 'arrow-left--line',
unicode: 'e87f',
unicode_decimal: 59519
},
{
icon_id: '12865674',
name: 'night',
font_class: 'night',
unicode: 'e6ef',
unicode_decimal: 59119
},
{
icon_id: '12865690',
name: 'day',
font_class: 'day',
unicode: 'e6f1',
unicode_decimal: 59121
},
{
icon_id: '702307',
name: 'drag',
font_class: 'drag',
unicode: 'e7d0',
unicode_decimal: 59344
},
{
icon_id: '11488125',
name: 'seleted',
font_class: 'selected',
unicode: 'e763',
unicode_decimal: 59235
},
{
icon_id: '10678428',
name: 'mirror light ctrl',
font_class: 'filter',
unicode: 'e6e0',
unicode_decimal: 59104
},
{
icon_id: '5772874',
name: '复制',
font_class: 'copy',
unicode: 'e617',
unicode_decimal: 58903
},
{
icon_id: '4936963',
name: 'CodeSandbox',
font_class: 'code-sandbox',
unicode: 'e87e',
unicode_decimal: 59518
},
{
icon_id: '8106210',
name: 'bluetoothon',
font_class: 'bluetoothon',
unicode: 'e697',
unicode_decimal: 59031
},
{
icon_id: '8106293',
name: 'wifi',
font_class: 'wifi',
unicode: 'e6a4',
unicode_decimal: 59044
},
{
icon_id: '10678426',
name: 'message',
font_class: 'message',
unicode: 'e6df',
unicode_decimal: 59103
},
{
icon_id: '10678434',
name: 'search',
font_class: 'search',
unicode: 'e6e1',
unicode_decimal: 59105
},
{
icon_id: '10678439',
name: 'scan QR',
font_class: 'scan',
unicode: 'e6e2',
unicode_decimal: 59106
},
{
icon_id: '10678401',
name: 'back',
font_class: 'arrow-left',
unicode: 'e6db',
unicode_decimal: 59099
},
{
icon_id: '8106272',
name: 'next',
font_class: 'arrow-right',
unicode: 'e6a3',
unicode_decimal: 59043
},
{
icon_id: '8106251',
name: 'increase',
font_class: 'plus',
unicode: 'e69f',
unicode_decimal: 59039
},
{
icon_id: '8106217',
name: 'delete',
font_class: 'delete',
unicode: 'e699',
unicode_decimal: 59033
},
{
icon_id: '8106245',
name: 'close',
font_class: 'close',
unicode: 'e69e',
unicode_decimal: 59038
},
{
icon_id: '10670577',
name: 'address',
font_class: 'address',
unicode: 'e6a7',
unicode_decimal: 59047
},
{
icon_id: '12865660',
name: 'connect device',
font_class: 'connect',
unicode: 'e6e7',
unicode_decimal: 59111
},
{
icon_id: '12865665',
name: 'done work',
font_class: 'donework',
unicode: 'e6e9',
unicode_decimal: 59113
},
{
icon_id: '12865672',
name: 'like',
font_class: 'like',
unicode: 'e6eb',
unicode_decimal: 59115
},
{
icon_id: '12865673',
name: 'mark',
font_class: 'mark',
unicode: 'e6ec',
unicode_decimal: 59116
},
{
icon_id: '12865685',
name: 'share',
font_class: 'share',
unicode: 'e6ee',
unicode_decimal: 59118
},
{
icon_id: '12865693',
name: 'setting',
font_class: 'setting',
unicode: 'e6f0',
unicode_decimal: 59120
},
{
icon_id: '8106224',
name: 'down',
font_class: 'arrow-down',
unicode: 'e69b',
unicode_decimal: 59035
},
{
icon_id: '8106260',
name: 'upward',
font_class: 'arrow-up',
unicode: 'e6a1',
unicode_decimal: 59041
},
{
icon_id: '8106276',
name: 'visible',
font_class: 'eye-close',
unicode: 'e6a2',
unicode_decimal: 59042
},
{
icon_id: '8106285',
name: 'eye_protection',
font_class: 'eye',
unicode: 'e6a0',
unicode_decimal: 59040
}
]
}
图片 Image
基本使用
| prop | type | default | desc | | ----------- | ------------- | --------------------------- | ------------------------------------------------------------ | | hasNav | boolean | true | 当前页面是否有导航栏,会计算系统导航栏高度,预览区域下移一段距离 | | src | string | 必填项 | 图片的资源路径 | | mode | ImageModeEnum | ImageModeEnum.ASPECT_FIT | 图片的填充模式,可参照uniapp官方提供的 Image 组件的 mode 值 | | width | number | 100 | 图片宽度 | | height | number | 100 | 图片高度 | | tools | string | zoomIn,zoomOut,rotate,reset | 由这四种工具随意组合,【,】拼接而成的字符串 | | showPreview | boolean | true | 是否允许点击图片后展示预览 | | showLoading | boolean | false | 是否展示加载中标识 | | showError | boolean | false | 是否展示加载失败提示 |
Slots
| name | desc | | ------- | ---------------- | | loading | 调整加载中提示 | | error | 覆盖加载失败提示 |
Emits
| name | desc | | ------ | ------------ | | loaded | 加载成功触发 | | error | 加载失败触发 | | click | 点击图片 |
输入框 Input
基本使用
<ml-input v-model:model-value="modelValue" placeholder="提示文字可自定义" />
<ml-input v-model:model-value="modelValue" :size="inputSize" />
<ml-input v-model:model-value="modelValue" type="password" />
<ml-input v-model:model-value="modelValue" disabled :size="inputSize" />
列表 List
基本使用
基础列表使用示例
<ml-list
ref="listRef"
v-model:error="error"
:data="mockData"
:loading="loading"
:loading-text="'自定义的加载中文本...'"
:finished="finished"
:height="400"
style="width: 100%"
@load="handleLoad"
>
<template #item="{ item }">
<ml-cell
:label="item.label"
:description="item.description"
:value="item.value"
allow-edit
/>
</template>
</ml-list>
import type { ListInstance, MessageInstance } from '@meleon/uni-ui'
const mockData = ref(
new Array(20).fill(0).map((_, index) => {
return {
id: `id-${index}`,
label: `标题${index}`,
description: `描述${index}`,
value: `值${index}`
}
})
)
const listRef = ref<ListInstance>()
const messageRef = ref<MessageInstance>()
const finished = ref(false)
const loading = ref(false)
const error = ref(true)
const handleLoad = () => {
if (!messageRef.value) return
if (mockData.value.length >= 60) {
finished.value = true
}
if (finished.value) {
messageRef.value.success({
content: '所有数据加载完成',
duration: 2000
})
} else {
messageRef.value.primary({
content: '触发 load 事件',
duration: 2000
})
mockData.value = [
...mockData.value,
...new Array(20).fill(0).map((_, index) => {
const idx = mockData.value.length + index
return {
id: `id-${idx}`,
label: `标题${idx}`,
description: `描述${idx}`,
value: `值${idx}`
}
})
]
}
}
onMounted(() => {
if (listRef.value) listRef.value.scrollIntoView('id-10')
})
虚拟列表使用示例
区别于基础列表,虚拟列表不支持调用 load 加载新数据,使用时需要准备好完整的初始数据
默认情况下,页面上仅展示15条数据节点,可以通过传入 pageSize 自定义每页展示的数量
<ml-list :data="mockData" :height="400" virtual-list style="width: 100%">
<template #virtual="{ data }">
<ml-cell
v-for="item in data"
:key="item.id"
:label="item.label"
:description="item.description"
:value="item.value"
allow-edit
></ml-cell>
</template>
</ml-list>
const mockVirtualData = ref(
new Array(100).fill(0).map((_, index) => {
return {
id: `id-${index}`,
label: `标题${index}`,
description: `描述${index}`,
value: `值${index}`
}
})
)
APIs
| prop | type | default | desc | | ------------ | -------- | ------------------ | -------------------------------------------------------- | | data | WithId[] | [] | 列表数据,需要提供 id 字段用以定位等操作 | | height | number | 必填 | 列表容器的高度 | | itemHeight | number | 58 | 列表项的高度,可控制提示文本的高度及滚动阈值 | | loading | boolean | false | 是否处于加载状态 | | loadingText | string | 加载中... | 加载状态底部的提示文本 | | finished | boolean | false | 是否加载完成 | | finishedText | string | 没有更多了 | 加载完成时,底部的提示文本 | | error | boolean | false | 是否加载失败 | | errorText | string | 加载失败,点击重试 | 加载失败时,底部的提示文本【可点击,重新触发 load 事件】 | | | | | | | virtualList | boolean | false | 是否开启虚拟列表 | | pageSize | number | 15 | 虚拟列表中展示的数量 |
Slots
| name | desc | | -------- | ---------------- | | loading | 加载中 | | error | 加载异常 | | finished | 加载完成 | | virtual | 虚拟列表 | | item | 普通列表的列表项 |
Methods
| name | type | desc | | -------------- | ---------------------------------------- | -------------------------------- | | scrollToTop | () => void | 滚动到顶部 | | scrollIntoView | (id: string | number | symbol) => void | 滚动到指定节点【仅支持普通列表】 |
Events
| name | desc | | ------------ | ------------------ | | update:error | 更新 error 属性 | | load | 列表滚动到底部触发 |
选择器 Select
基本使用
<ml-select v-model:modelValue="modelValue" multiple :max-tag-count="1">
<ml-option value="1" label="选项1" />
<ml-option value="2" label="选项2" />
<ml-option value="3" label="选项3" />
</ml-select>
开关 Switch
基本使用
<ml-switch v-model="isActive"></ml-switch>
<ml-switch v-model="isActive" type="circle"></ml-switch>
<ml-switch v-model="isActive" type="line"></ml-switch>
APIs
| prop | type | default | desc | | -------------- | ------------------------------------------------ | ---------------------- | -------------- | | modelValue | boolean | false | 是否开启 | | type | circle | square |line | square | 开关类型 | | checkedColor | string | var(--info-color-7) | 激活状态颜色 | | uncheckedColor | string | var(--primary-color-6) | 未激活状态颜色 | | disabled | boolean | false | 是否禁用 | | beforeSwitch | (newVal: boolean) => boolean | Promise | () => true | 切换前触发 |
表格 Table
基本使用
<ml-table
:data="tableData"
size="mini"
stripe
border
:height="200"
:loading="false"
:refresher-enabled="true"
:refresher-interval="2000"
style="width: 100%"
@row-click="onRowClick"
@cell-click="onCellClick"
>
<template #cell="{ column, row }">
<block v-if="column.property === 'gender'">
<ml-tag :model-value="row[column.property]" type="primary" size="mini"></ml-tag>
</block>
<block v-else-if="column.property === 'age'">
<ml-count-to
:to="row[column.property]"
animation
:value-style="{ fontSize: '14px', color: 'var(--info-color-8)' }"
></ml-count-to>
</block>
<text v-else>{{ column.property && row[column.property] }}</text>
</template>
<!-- 。。。这操作有点多余,后面改改 -->
<ml-table-column type="index" fixed="left"></ml-table-column>
<ml-table-column prop="name" label="姓名" fixed></ml-table-column>
<ml-table-column prop="age" label="年龄"></ml-table-column>
<ml-table-column prop="gender" label="性别"></ml-table-column>
</ml-table>
消息提示 Message
基本使用
<ml-message ref="messageRef" />
import type { MessageInstance, MessageOptions } from '@meleon/uni-ui'
const messageRef = ref<MessageInstance>()
const showMessage = (type: MessageOptions['type']) => {
if (!messageRef.value || !type) return
messageRef.value[type]({
content: type + idx.value++,
duration: 2000
})
}
头部导航栏 Navigator
基本使用
<ml-navigator
title="ml-navigator"
title-color="#FFFFFF"
has-back
icon-color="#FFFFFF"
background="#7A98B3"
/>
APIs
| prop | type | default | desc | | ---------- | -------------------------- | ---------------------- | -------------------------------- | | background | string | var(--primary-color-6) | 导航栏背景,支持纯色、渐变或图片 | | title | string | '' | 导航栏标题 | | titleColor | string | #FFFFFF | 标题颜色 | | titleStyle | Object | {} | 标题样式 | | hasBack | boolean | true | 是否有回退图标 | | iconColor | string | #FFFFFF | 图标颜色 | | iconStyle | Object | {} | 图标样式 | | tools | Array | [] | 图标列表 |
NavigatorToolEntity
| prop | type | desc | | ----- | ------------------- | -------------------------------------------- | | icon | string | 图标名 | | color | string | 图标颜色 | | type | return | navigator | 点击图标的事件的类型 | | delta | number[可选] | type = return 时,delta 表示回退的页面数 | | path | string[可选] | type = navigator 时,path 表示跳转的页面地址 |
Slots
| name | desc | | ------- | ------------ | | icon | 图标插槽 | | default | 主体内容插槽 |
时间轴 TimeLine
基本使用
<ml-timeline :reverse="reverseCheckedList[0] === 'reverse'">
<ml-timeline-item>
<template #label>
<text>2023-09-08</text>
</template>
<view>The first milestone content</view>
</ml-timeline-item>
<ml-timeline-item>
<template #label>
<text>2023-09-09</text>
</template>
<view>
<view>The second milestone</view>
<view>The second milestone</view>
<view>The second milestone</view>
</view>
</ml-timeline-item>
<ml-timeline-item>
<template #label>
<text> 2023-09-25 </text>
</template>
<view>The third milestone </view>
</ml-timeline-item>
</ml-timeline>
时间选择器 TimePicker
基本使用
<ml-time-picker v-model="value" style="width: 100%">
<template #trigger>
<ml-cell
label="时间选择器"
:value="value"
style="width: 100%"
></ml-cell>
</template>
</ml-time-picker>
进度条 Progress
基本使用
<ml-progress :percent="percent" status="success" />
<ml-progress :percent="templateMap[0].percent">
<template #text="{ percent, decimal }">
<text>进度 {{ (percent * 100).toFixed(decimal) }}%</text>
</template>
</ml-progress>
<ml-progress :percent="percent" type="circle" :size="curSize" status="primary" />
标签页 Tabs
基本使用
<ml-tabs active="a">
<ml-tab value="a" title="标签1" closable>内容1</ml-tab>
<ml-tab value="b" title="标签2" disabled>内容2</ml-tab>
<ml-tab value="c" title="标签3" disabled closable>内容3</ml-tab>
<ml-tab value="d" title="标签4">内容4</ml-tab>
<ml-tab value="e" title="标签5">内容5</ml-tab>
</ml-tabs>
标签 Tag
基本使用
<ml-tag model-value="标签2" type="primary" plain />
<ml-tag model-value="标签3" size="medium" />
<view>closeable: 添加 ml-close 图标,点击可触发 close 事件</view>
<ml-tag model-value="标签1" closable @close="hanldeTagClose" />
<view>editable: 点击后标签会切换成 input 输入框,可修改标签内容 </view>
<ml-tag model-value="标签2" checkable @click="hanldeTagClick" />
<view>checkable: 添加点击样式,触发 click 事件</view>
<ml-tag v-model:model-value="tagValue" editable />
树 Tree
基本使用
<ml-tree
class="tree-wrapper"
ref="treeRef"
v-model:expanded-keys="expandedKeys"
v-model:checked-keys="checkedKeys"
v-model:selected-keys="selectedKeys"
v-model:indeterminate-keys="indeterminateKeys"
:data="treeData"
checkable
selectable
multiple
:auto-expand-parent="false"
@check="handleCheck"
@select="handleSelect"
@expand="handleExpand"
></ml-tree>
<view class="btn-list">
<ml-button type="primary" @click="handleExpandAll">
{{ isExpandAll ? 'Close All' : 'Expand All' }}
</ml-button>
<ml-button type="primary" @click="handleCheckAll">
{{ isCheckAll ? 'Unheck All' : 'Check All' }}
</ml-button>
<ml-button type="primary" @click="handleSelectAll">
{{ isSelectAll ? 'Unselect All' : 'Select All' }}
</ml-button>
<ml-button type="primary" @click="handleExpandNode"> Expand Root </ml-button>
<ml-button type="primary" @click="handleCheckNode"> Check Root </ml-button>
<ml-button type="primary" @click="handleSelectNode"> Select Root </ml-button>
</view>
import type {
TreeDataEntity,
TreeCheckPayload,
TreeExpandPayload,
TreeSelectPayload,
TreeInstance
} from '@meleon/uni-ui/index'
const treeRef = ref<TreeInstance>()
const rootKey = ref('0-0')
const expandedKeys = ref<string[]>(['0-0-0'])
const checkedKeys = ref<string[]>([])
const selectedKeys = ref<string[]>([])
const indeterminateKeys = ref<string[]>([])
// 监听 tree 触发的事件
const handleCheck = (val: string[], payload: TreeCheckPayload) => {
console.log('onCheck', val, payload)
}
const handleExpand = (val: string[], payload: TreeExpandPayload) => {
console.log('onExpand', val, payload)
}
const handleSelect = (val: string[], payload: TreeSelectPayload) => {
console.log('onSelect', val, payload)
}
// 手动调用组件暴露的方法
// 展开节点
const isExpandAll = ref(false)
const handleExpandAll = () => {
if (!treeRef.value) return
isExpandAll.value = !isExpandAll.value
treeRef.value.expandAll(isExpandAll.value)
}
const handleExpandNode = () => {
if (!treeRef.value) return
treeRef.value.expandNode(rootKey.value, true)
}
// 选中节点复选框
const isCheckAll = ref(false)
const handleCheckAll = () => {
if (!treeRef.value) return
isCheckAll.value = !isCheckAll.value
treeRef.value.checkAll(isCheckAll.value)
}
const handleCheckNode = () => {
if (!treeRef.value) return
treeRef.value.checkNode(rootKey.value, true)
}
// 选中节点
const isSelectAll = ref(false)
const handleSelectAll = () => {
if (!treeRef.value) return
isSelectAll.value = !isSelectAll.value
treeRef.value.selectAll(isSelectAll.value)
}
const handleSelectNode = () => {
if (!treeRef.value) return
treeRef.value.selectNode(rootKey.value, true)
}
// 节点数据
const treeData: TreeDataEntity[] = [
{
title: 'Trunk 0-0',
key: '0-0',
children: [
{
title: 'Branch 0-0-0',
key: '0-0-0',
disabled: false,
children: [
{
title: 'Leaf',
key: '0-0-0-0'
},
{
title: 'Leaf',
key: '0-0-0-1'
}
]
},
{
title: 'Branch 0-0-1',
key: '0-0-1',
children: [
{
title: 'Leaf',
key: '0-0-1-0'
}
]
}
]
}
]
APIs
| prop | type | default | desc | | ------------------- | ---------------- | --------- | ------------------------------ | | data | TreeDataEntity[] | 必填 | 树形数据 | | checkable | boolean | false | 是否显示复选框 | | checkedKeys | string[] | undefined | 选中复选框的节点键值列表 | | defaultCheckedKeys | string[] | [] | 默认选中复选框的节点键值列表 | | indeterminateKeys | string[] | [] | 半选状态的节点键值列表 | | expandedKeys | string[] | 必填 | 展开的节点键值列表 | | defaultExpandedKeys | string[] | [] | 默认展开的节点键值列表 | | autoExpandParent | boolean | true | 是否自动展开父级节点 | | selectable | boolean | false | 是否支持点击文本选中 | | selectedKeys | string[] | undefined | 选中的文本节点键值列表 | | defaultSelectedKeys | string[] | [] | 默认选中的文本节点键值列表 | | multiple | boolean | true | 点击文本节点的选择是否支持多选 |
Slots
| name | desc | prop | | ----- | ------------------ | ----- | | title | 自定义文本节点内容 | title |
Emits
| name | desc | params | | ------------------------ | --------------------------------- | ------------------------------------------------------------ | | update:expandedKeys | 更新 expandedKeys【v-model】 | expandedKeys: string[] | | expand | 展开时触发 | 1. expandedKeys: string[]2. { expanded: boolean node: TreeNodeEntity nodeData: TreeDataEntity} | | update:selectedKeys | 更新 selectedKeys【v-model】 | selectedKeys: string[] | | select | 点击文本节点时触发 | 1. selectedKeys: string[]2. { selected: boolean node: TreeNodeEntity nodeData: TreeDataEntity} | | update:checkedKeys | 更新 checkedKeys【v-model】 | checkedKeys: string[] | | check | 点击节点复选框时触发 | 1. checkedKeys: string[]2. { checked: boolean checkedKeys: string[] indeterminateKeys: string[] node: TreeNodeEntity nodeData: TreeDataEntity} | | update:indeterminateKeys | 更新 indeterminateKeys【v-model】 | indeterminateKeys: string[] |
Events
| name | desc | params | | --------------------- | -------------------- | ---------------------------------------------------- | | getExpandedNodes | 获取展开的节点 | () => TreeNodeEntity[] | | expandNode | 展开指定的节点 | (key: string | string[], expand: boolean) => void | | expandAll | 展开所有节点 | (expandAll: boolean = true) => void | | | | | | getSelectedNodes | 获取选中的节点 | () => TreeNodeEntity[] | | selectNode | 选择指定的节点 | (key: string | string[], selected: boolean) => void | | selectAll | 选择所有节点 | (selectAll: boolean = true) => void | | | | | | getCheckedNodes | 获取选中复选框的节点 | () => TreeNodeEntity[] | | getIndeterminateNodes | 获取半选状态的节点 | () => TreeNodeEntity[] | | checkNode | 选中指定节点的复选框 | (key: string | string[], checked: boolean) => void | | checkAll | 选中所有节点的复选框 | (checkAll: boolean = true) => void |
上传组件 Uploader
基本使用
<template>
<ml-uploader
ref="uploadRef"
v-model:file-list="fileList"
action="http://localhost:3000/api/file/upload"
multiple
show-file-list
:disabled="false"
:auto-upload="false"
:on-change="handleOnChange"
@delete="handleDelete"
>
<template #trigger>
<ml-button type="primary">选择文件</ml-button>
</template>
</ml-uploader>
<ml-button
type="primary"
status="success"
@click="handleSubmit"
>
上传
</ml-button>
</template>
<script lang="ts" setup>
import type { FileItem, UploaderInstance } from '@meleon/uni-ui/ml-uploader'
const fileList = ref<FileItem[]>([])
const handleDelete = () => {
console.log('a', fileList.value)
}
const handleOnChange = (files: FileItem[]) => {
console.log('a', files)
}
const uploadRef = ref<UploaderInstance>()
const handleSubmit = () => {
if (!uploadRef.value) return
uploadRef.value.submit()
}
</script>
APIs
| props | type | default | desc | | ------------ | -------------------------------------------------- | ---------- | ---------------------------- | | action | string | () => string | '' | 文件上传的地址 | | autoUpload | boolean | false | 是否自动上传 | | fieldName | string | file | 上传时文件对应的字段名 | | headers | Record<string, string> | {} | 上传时携带的请求头 | | data | Record<string, any> | {} | 上传时 FromData 里其他的数据 | | fileList | FileItem | 必填项 | 展示的文件列表 | | multiple | boolean | false | 是否支持同时选择多个文件 | | limit | number | 9 | 最多缓存的文件数量 | | previewSize | number | 100 | 预览区域尺寸 | | disabled | boolean | false | 是否禁用 | | showFileList | boolean | false | 是否展示文件列表 | | sourceType | UploaderSourceTypeEnum | '' | 支持相机或相册,默认都支持 | | beforeUpload | (files: FileItem[]) => boolean | Promise | () => true | 上传前的钩子函数 | | beforeDelete | (file: FileItem) => boolean | Promise | () => true | 删除前的钩子函数 |
Types
FileItem
| prop | desc | | --------- | -------------- | | path | 图片路径 | | id | 图片id | | deletable | 是否可以被删除 |
UploaderSourceTypeEnum
| enum | desc | | ------ | ------ | | ALBUM | album | | CAMERA | camera |
Emits
| name | desc | | --------------- | ------------------ | | delete | 文件在缓存中被删除 | | uploaded | 文件上传成功 | | update:fileList | 文件列表更新 |
Methods
| name | type | desc | | ---------- | ------------------------------------ | -------------------------- | | submit | () => void | 手动上传当前展示的所有文件 | | updateFile | (id: string, file: FileItem) => void | 指定id,更新文件对象 |