UI — 界面控件
原生提供的全局 UI 组件:Toast、Loading、Dialog、ActionSheet、导航栏控制等。
交互示例
Toast 轻提示
showToast()
<script setup lang="ts">
import { ref } from 'vue'
import woo from 'mini-sdk'
type ToastIcon = 'success' | 'error' | 'loading' | 'none'
const duration = ref(2000)
const title = ref('操作成功')
const icon = ref<ToastIcon>('success')
const isLoading = ref(false)
async function showToast() {
await woo.showToast({ title: title.value, icon: icon.value, duration: duration.value === 0 ? 0 : duration.value })
if (icon.value === 'loading' || duration.value === 0) {
isLoading.value = true
} else {
isLoading.value = false
}
}
async function hideToast() {
await woo.hideToast()
isLoading.value = false
}
const iconOptions: { label: string; value: ToastIcon }[] = [
{ label: '✅ success', value: 'success' },
{ label: '❌ error', value: 'error' },
{ label: '⏳ loading', value: 'loading' },
{ label: '📝 none', value: 'none' },
]
</script>
<template>
<div class="demo-toast">
<div class="form-grid">
<div class="field">
<label>标题文字</label>
<input v-model="title" placeholder="输入提示文字" />
</div>
<div class="field">
<label>图标 icon</label>
<select v-model="icon">
<option v-for="opt in iconOptions" :key="opt.value" :value="opt.value">{{ opt.label }}</option>
</select>
</div>
<div class="field">
<label>显示时长 (ms,0=永久)</label>
<input v-model.number="duration" type="number" min="0" step="500" />
</div>
</div>
<div class="btn-row">
<button class="btn btn-primary" @click="showToast">showToast()</button>
<button class="btn btn-outline" @click="hideToast" :disabled="!isLoading">hideToast()</button>
</div>
<div class="note" v-if="isLoading">
↑ Toast 已锁定显示(duration=0 或 loading 图标),点击 hideToast 关闭
</div>
</div>
</template>
<style scoped>
.demo-toast { display: flex; flex-direction: column; gap: 14px; width: 100%; }
.form-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(160px, 1fr)); gap: 12px; }
.field { display: flex; flex-direction: column; gap: 5px; }
label { font-size: 11.5px; font-weight: 600; color: var(--vp-c-text-3); text-transform: uppercase; letter-spacing: 0.05em; }
input, select {
padding: 7px 10px; border-radius: 6px; border: 1px solid var(--vp-c-divider);
background: var(--vp-c-bg); font-size: 13px; color: var(--vp-c-text-1);
font-family: inherit; outline: none; transition: border-color 0.15s;
}
input:focus, select:focus { border-color: #6366f1; }
.btn-row { display: flex; gap: 8px; }
.btn { padding: 8px 18px; border-radius: 7px; border: none; font-size: 13.5px; font-weight: 500; cursor: pointer; font-family: inherit; transition: all 0.15s; }
.btn-primary { background: #6366f1; color: white; }
.btn-primary:hover { background: #4f46e5; }
.btn-outline { background: var(--vp-c-bg); border: 1px solid var(--vp-c-divider); color: var(--vp-c-text-1); }
.btn-outline:hover:not(:disabled) { background: var(--vp-c-bg-soft); }
.btn-outline:disabled { opacity: 0.5; cursor: not-allowed; }
.note { font-size: 12.5px; color: #f59e0b; background: rgba(245,158,11,0.08); border: 1px solid rgba(245,158,11,0.2); border-radius: 6px; padding: 8px 12px; }
</style>
Attributes
| 参数 | 说明 | 类型 | 可选值 | 默认值 |
|---|---|---|---|---|
title | 提示文字 | string | — | '' |
icon | 图标类型 | 'success' | 'error' | 'loading' | 'none' | success / error / loading / none | 'none' |
duration | 显示时长(ms),0 表示永久 | number | — | 2000 |
mask | 是否显示透明遮罩 | boolean | true / false | false |
Dialog 弹窗
showDialog() / alert()
<script setup lang="ts">
import { ref } from 'vue'
import woo from 'mini-sdk'
const result = ref<{ confirm: boolean; cancel: boolean } | null>(null)
const showCancel = ref(true)
const confirmText = ref('确认')
const cancelText = ref('取消')
const content = ref('此操作不可撤销,是否继续?')
async function openDialog() {
result.value = null
const res = await woo.showDialog({
title: '确认操作',
content: content.value,
showCancel: showCancel.value,
confirmText: confirmText.value,
cancelText: cancelText.value,
})
result.value = res
}
async function openAlert() {
await woo.alert({ title: '温馨提示', content: '操作已完成!', buttonText: '知道了' })
}
</script>
<template>
<div class="demo-dialog">
<div class="form-grid">
<div class="field flex-2">
<label>内容文字</label>
<input v-model="content" />
</div>
<div class="field">
<label>确认按钮文字</label>
<input v-model="confirmText" />
</div>
<div class="field">
<label>取消按钮文字</label>
<input v-model="cancelText" />
</div>
<div class="field checkbox-field">
<label class="checkbox-label">
<input type="checkbox" v-model="showCancel" />
显示取消按钮
</label>
</div>
</div>
<div class="btn-row">
<button class="btn btn-primary" @click="openDialog">showDialog()</button>
<button class="btn btn-outline" @click="openAlert">alert()</button>
</div>
<div v-if="result" class="result-chip" :class="result.confirm ? 'confirmed' : 'cancelled'">
用户点击了:{{ result.confirm ? `"${confirmText}"(confirm)` : `"${cancelText}"(cancel)` }}
</div>
</div>
</template>
<style scoped>
.demo-dialog { display: flex; flex-direction: column; gap: 14px; width: 100%; }
.form-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(160px, 1fr)); gap: 12px; align-items: end; }
.flex-2 { grid-column: span 2; }
.field { display: flex; flex-direction: column; gap: 5px; }
label { font-size: 11.5px; font-weight: 600; color: var(--vp-c-text-3); text-transform: uppercase; letter-spacing: 0.05em; }
input[type="text"], input:not([type]) {
padding: 7px 10px; border-radius: 6px; border: 1px solid var(--vp-c-divider);
background: var(--vp-c-bg); font-size: 13px; color: var(--vp-c-text-1);
font-family: inherit; outline: none; transition: border-color 0.15s;
}
input:focus { border-color: #6366f1; }
.checkbox-field { justify-content: flex-end; padding-bottom: 2px; }
.checkbox-label { display: flex; align-items: center; gap: 7px; font-size: 13px; font-weight: 500; color: var(--vp-c-text-1); text-transform: none; letter-spacing: 0; cursor: pointer; }
.checkbox-label input { width: 15px; height: 15px; cursor: pointer; }
.btn-row { display: flex; gap: 8px; }
.btn { padding: 8px 18px; border-radius: 7px; border: none; font-size: 13.5px; font-weight: 500; cursor: pointer; font-family: inherit; transition: all 0.15s; }
.btn-primary { background: #6366f1; color: white; }
.btn-primary:hover { background: #4f46e5; }
.btn-outline { background: var(--vp-c-bg); border: 1px solid var(--vp-c-divider); color: var(--vp-c-text-1); }
.btn-outline:hover { background: var(--vp-c-bg-soft); }
.result-chip { display: inline-flex; align-items: center; padding: 7px 14px; border-radius: 7px; font-size: 13px; font-weight: 500; }
.confirmed { background: rgba(16,185,129,0.1); color: #059669; border: 1px solid rgba(16,185,129,0.2); }
.cancelled { background: rgba(239,68,68,0.08); color: #dc2626; border: 1px solid rgba(239,68,68,0.15); }
</style>
Attributes
| 参数 | 说明 | 类型 | 可选值 | 默认值 |
|---|---|---|---|---|
title | 弹窗标题 | string | — | '' |
content | 弹窗内容 | string | — | '' |
showCancel | 是否显示取消按鈕 | boolean | true / false | true |
cancelText | 取消按鈕文字 | string | — | '取消' |
confirmText | 确认按鈕文字 | string | — | '确定' |
API 参考
woo.showToast(options)
显示轻提示,自动消失。支持字符串简写。ts
// ✨ 字符串简写(icon 默认 'none',duration 默认 2000)
await woo.showToast('已复制到剪贴板')
// 成功提示
await woo.showToast({ title: '保存成功', icon: 'success', duration: 2000 })
// 加载中(不自动消失,需手动 hideToast)
await woo.showToast({ title: '正在上传...', icon: 'loading' })
await woo.hideToast()
// duration=0 永久显示
await woo.showToast({ title: '处理中...', duration: 0 })Options
| 参数 | 类型 | 默认值 | 说明 |
|---|---|---|---|
title | string | '' | 提示文字 |
icon | 'success' | 'error' | 'loading' | 'none' | 'none' | 图标类型 |
duration | number | 2000 | 显示时长(ms),0 表示永久 |
mask | boolean | false | 是否显示遮罩 |
woo.hideToast()
主动关闭 Toast(用于 icon: 'loading' 或 duration: 0 的场景)。
woo.showLoading(options) / woo.hideLoading()
显示/关闭全屏加载遮罩。支持字符串简写。ts
// ✨ 字符串简写
await woo.showLoading('加载中')
try {
await woo.showLoading({ title: '提交中...', mask: true })
await submitForm()
} finally {
await woo.hideLoading()
}Options
| 参数 | 类型 | 默认值 | 说明 |
|---|---|---|---|
title | string | '' | 提示文字 |
mask | boolean | true | 是否显示遮罩,防止用户误操作 |
woo.showDialog(options)
模态确认框,等待用户点击后 resolve。ts
const { confirm } = await woo.showDialog({
title: '删除确认',
content: '此操作不可撤销,是否继续?',
cancelText: '取消',
confirmText: '删除',
})
if (confirm) {
await deleteItem()
}Options
| 参数 | 类型 | 默认值 | 说明 |
|---|---|---|---|
title | string | '' | 弹窗标题 |
content | string | '' | 弹窗内容 |
showCancel | boolean | true | 是否显示取消按钮 |
cancelText | string | '取消' | 取消按钮文字 |
confirmText | string | '确定' | 确认按钮文字 |
Result
| 字段 | 类型 | 说明 |
|---|---|---|
confirm | boolean | 用户点击了确认 |
cancel | boolean | 用户点击了取消 |
woo.alert(options)
单按钮提示框。支持字符串简写。ts
// ✨ 字符串简写
await woo.alert('操作成功')
await woo.alert({
title: '网络错误',
content: '请检查网络连接后重试',
buttonText: '知道了',
})woo.showActionSheet(options)
底部操作菜单。ts
try {
const { index } = await woo.showActionSheet({
itemList: ['拍照', '从相册选择', '取消'],
})
console.log('用户选择了第', index, '项') // 0-based
} catch (err) {
// 用户取消
}Options / Result
| 参数 | 类型 | 说明 | |
|---|---|---|---|
| Options | itemList | string[] | 选项文字列表 |
| Result | index | number | 用户点击的下标(0-based) |
导航栏控制
ts
// 动态修改标题
await woo.setNavigationBarTitle({ title: '文章详情' })
// 修改颜色(十六进制)
await woo.setNavigationBarColor({
frontColor: '#ffffff',
backgroundColor: '#1a1a2e',
})
// 加载动画
await woo.showNavigationBarLoading()
try {
await loadData()
} finally {
await woo.hideNavigationBarLoading()
}TabBar 控制
ts
await woo.hideTabBar() // 进入沉浸式页面时隐藏
await woo.showTabBar() // 退出时恢复
// 设置红点
await woo.setTabBarBadge({ index: 2, text: '99+' })
await woo.removeTabBarBadge({ index: 2 })图片预览
ts
// 多图预览,从指定图开始
await woo.previewImage({
urls: ['img1.jpg', 'img2.jpg', 'img3.jpg'],
current: 'img2.jpg',
})