@winner-fed/plugin-winui
v1.0.4
Published
🎨 **WinUI 组件库集成插件** - 为 WinJS 应用提供 WinUI 组件库的完整集成解决方案
Readme
@winner-fed/plugin-winui
🎨 WinUI 组件库集成插件 - 为 WinJS 应用提供 WinUI 组件库的完整集成解决方案
✨ 特性
- 🎯 智能检测 - 自动检测 WinUI 版本(1.x / 3.x),提供对应的集成方案
- 📦 按需引用 - 自动按需引入组件和样式,减少打包体积
- 🔧 自动导入 - 配合 unplugin-vue-components 实现组件自动导入
- 💪 TypeScript 支持 - 自动生成类型声明文件,完美的 TypeScript 体验
- 🎨 样式优化 - 智能处理样式引入,避免样式冲突和重复
- 🔄 向后兼容 - 完美支持 WinUI 1.x 的函数式组件(Toast、Dialog 等)
- ⚡ 零配置 - 开箱即用,无需复杂配置
- 🌈 多版本支持 - 同时支持 Vue 2 和 Vue 3
🎯 适用场景
- 企业级应用 - 基于 WinUI 的管理系统、仪表板
- 移动端应用 - 响应式 Web 应用、混合应用
- 快速原型 - 快速搭建产品原型和 MVP
- 组件库迁移 - 从其他组件库迁移到 WinUI
- 设计系统 - 统一的设计语言和组件规范
📦 安装
# npm
npm install @winner-fed/plugin-winui @winner-fed/win-ui -D
# yarn
yarn add @winner-fed/plugin-winui @winner-fed/win-ui -D
# pnpm
pnpm add @winner-fed/plugin-winui @winner-fed/win-ui -D🚀 快速开始
1. 配置插件
在 .winrc.ts 中启用插件:
// .winrc.ts
import { defineConfig } from 'win';
export default defineConfig({
plugins: ['@winner-fed/plugin-winui'],
winUI: {
// 插件配置(可选)
}
});2. 使用组件
<template>
<div>
<!-- 直接使用 WinUI 组件,无需导入 -->
<win-button type="primary">主要按钮</win-button>
<win-button type="success">成功按钮</win-button>
<win-button type="warning">警告按钮</win-button>
<win-button type="danger">危险按钮</win-button>
<!-- 使用函数式组件 -->
<win-button @click="showToast">显示提示</win-button>
<win-button @click="showDialog">显示对话框</win-button>
</div>
</template>
<script setup>
// 函数式组件自动导入(WinUI 3.x)
import { showToast, showDialog } from '@winner-fed/win-ui';
// 或者使用全局方法(WinUI 1.x)
const showToast = () => {
Toast('这是一个提示消息');
};
const showDialog = () => {
Dialog.confirm({
title: '确认',
message: '是否确认执行此操作?'
});
};
</script>3. 自动类型提示
插件会自动生成 components.d.ts 文件,提供完整的类型支持:
// components.d.ts (自动生成)
declare module 'vue' {
export interface GlobalComponents {
WinButton: typeof import('@winner-fed/win-ui/es')['Button']
WinCell: typeof import('@winner-fed/win-ui/es')['Cell']
WinDialog: typeof import('@winner-fed/win-ui/es')['Dialog']
// ... 更多组件
}
}⚙️ 配置选项
基础配置
// .winrc.ts
export default defineConfig({
plugins: ['@winner-fed/plugin-winui'],
winUI: {
// WinUI 1.x 的函数式组件配置
legacyFunction: ['Toast', 'Dialog', 'Notify', 'ImagePreview']
}
});配置说明
| 参数 | 类型 | 默认值 | 描述 |
| ----------------- | --------------- | ------ | ----------------------------------------- |
| legacyFunction | string[] | [] | WinUI 1.x 版本需要全局引入的函数式组件 |
📝 使用示例
基础组件使用
<template>
<div class="demo-container">
<!-- 按钮组件 -->
<div class="demo-section">
<h3>按钮组件</h3>
<win-button>默认按钮</win-button>
<win-button type="primary">主要按钮</win-button>
<win-button type="success">成功按钮</win-button>
<win-button type="warning">警告按钮</win-button>
<win-button type="danger">危险按钮</win-button>
</div>
<!-- 表单组件 -->
<div class="demo-section">
<h3>表单组件</h3>
<win-field v-model="value" label="用户名" placeholder="请输入用户名" />
<win-field v-model="password" type="password" label="密码" placeholder="请输入密码" />
</div>
<!-- 列表组件 -->
<div class="demo-section">
<h3>列表组件</h3>
<win-cell-group>
<win-cell title="单元格" value="内容" />
<win-cell title="单元格" value="内容" is-link />
<win-cell title="单元格" value="内容" is-link to="/profile" />
</win-cell-group>
</div>
<!-- 反馈组件 -->
<div class="demo-section">
<h3>反馈组件</h3>
<win-button @click="showToast">显示轻提示</win-button>
<win-button @click="showDialog">显示对话框</win-button>
<win-button @click="showNotify">显示通知</win-button>
</div>
</div>
</template>
<script setup>
import { ref } from 'vue';
const value = ref('');
const password = ref('');
const showToast = () => {
Toast('操作成功!');
};
const showDialog = () => {
Dialog.confirm({
title: '提示',
message: '是否确认删除?'
}).then(() => {
Toast('已删除');
});
};
const showNotify = () => {
Notify({
type: 'success',
message: '通知消息'
});
};
</script>WinUI 1.x 兼容配置
// .winrc.ts - WinUI 1.x 版本配置
export default defineConfig({
plugins: ['@winner-fed/plugin-winui'],
winUI: {
// 配置需要全局引入的函数式组件
legacyFunction: ['Toast', 'Dialog', 'Notify', 'ImagePreview']
}
});<template>
<div>
<!-- WinUI 1.x 组件使用 -->
<win-button @click="handleToast">显示提示</win-button>
<win-button @click="handleDialog">显示对话框</win-button>
<win-button @click="handleNotify">显示通知</win-button>
<win-button @click="handleImagePreview">图片预览</win-button>
<!-- 普通组件无需特殊配置 -->
<win-cell-group>
<win-cell title="设置" is-link />
<win-cell title="关于" is-link />
</win-cell-group>
</div>
</template>
<script setup>
// WinUI 1.x 函数式组件可以直接使用
const handleToast = () => {
Toast('这是一个提示');
};
const handleDialog = () => {
Dialog.confirm({
title: '确认操作',
message: '是否继续?'
}).then(() => {
Toast('用户确认');
}).catch(() => {
Toast('用户取消');
});
};
const handleNotify = () => {
Notify({
type: 'primary',
message: '通知消息'
});
};
const handleImagePreview = () => {
ImagePreview([
'https://example.com/image1.jpg',
'https://example.com/image2.jpg'
]);
};
</script>WinUI 3.x 现代化用法
<template>
<div>
<!-- WinUI 3.x 组件使用 -->
<win-space direction="vertical">
<win-button @click="handleToast">显示提示</win-button>
<win-button @click="handleDialog">显示对话框</win-button>
<win-button @click="handleNotify">显示通知</win-button>
</win-space>
<!-- 新版本组件 -->
<win-form>
<win-form-item label="用户名">
<win-input v-model="form.username" />
</win-form-item>
<win-form-item label="邮箱">
<win-input v-model="form.email" type="email" />
</win-form-item>
</win-form>
</div>
</template>
<script setup>
import { ref } from 'vue';
// WinUI 3.x 函数式组件需要导入
import { showToast, showDialog, showNotify } from '@winner-fed/win-ui';
const form = ref({
username: '',
email: ''
});
const handleToast = () => {
showToast('操作成功!');
};
const handleDialog = () => {
showDialog({
title: '提示',
message: '是否保存修改?'
});
};
const handleNotify = () => {
showNotify({
type: 'success',
message: '保存成功'
});
};
</script>高级用法 - 主题定制
<template>
<div>
<!-- 使用 CSS 变量定制主题 -->
<div class="custom-theme">
<win-button type="primary">自定义主题按钮</win-button>
<win-cell-group>
<win-cell title="自定义样式" />
</win-cell-group>
</div>
</div>
</template>
<style scoped>
.custom-theme {
/* 自定义主题色 */
--win-primary-color: #007aff;
--win-success-color: #52c41a;
--win-warning-color: #faad14;
--win-danger-color: #ff4d4f;
/* 自定义字体 */
--win-font-family: 'Helvetica Neue', Arial, sans-serif;
/* 自定义边框 */
--win-border-radius: 8px;
}
</style>🔧 版本差异
WinUI 1.x vs 3.x 主要差异
| 特性 | WinUI 1.x | WinUI 3.x | | ------------------- | ------------------- | ------------------- | | 组件导入 | 自动全局导入 | 按需导入 + 自动导入 | | 函数式组件 | 全局方法 | 需要显式导入 | | 样式处理 | 全局样式引入 | 按需样式引入 | | TypeScript 支持 | 基础类型支持 | 完整类型推断 | | 打包体积 | 较大 | 更小(按需引入) | | API 风格 | 传统 API | 现代化 API |
版本检测
插件会自动检测 WinUI 版本:
// 插件内部逻辑
const winUIVersion = require('@winner-fed/win-ui/package.json').version;
const isWinUI2 = winUIVersion?.startsWith('1.'); // 1.x 版本
if (isWinUI2) {
// 使用 WinUI 1.x 的集成方案
} else {
// 使用 WinUI 3.x 的集成方案
}🎨 组件类型对照
常用组件映射
| 组件分类 | WinUI 组件名 | 模板中使用 | 功能描述 |
| ---------- | ------------------- | ------------------- | -------------- |
| 基础 | Button | <win-button> | 按钮 |
| | Cell | <win-cell> | 单元格 |
| | Icon | <win-icon> | 图标 |
| | Image | <win-image> | 图片 |
| 表单 | Field | <win-field> | 输入框 |
| | Form | <win-form> | 表单 |
| | Radio | <win-radio> | 单选框 |
| | Checkbox | <win-checkbox> | 复选框 |
| | Switch | <win-switch> | 开关 |
| 反馈 | Dialog | <win-dialog> | 对话框 |
| | Toast | Toast() | 轻提示 |
| | Notify | <win-notify> | 通知 |
| | Loading | <win-loading> | 加载 |
| 导航 | Tab | <win-tab> | 标签页 |
| | NavBar | <win-nav-bar> | 导航栏 |
| | Tabbar | <win-tabbar> | 底部导航 |
| | Sidebar | <win-sidebar> | 侧边栏 |
| 展示 | List | <win-list> | 列表 |
| | Card | <win-card> | 卡片 |
| | Collapse | <win-collapse> | 折叠面板 |
| | Swipe | <win-swipe> | 轮播 |
函数式组件(WinUI 1.x)
// 全局可用的函数式组件
Toast('消息内容');
Toast.success('成功消息');
Toast.fail('失败消息');
Toast.loading('加载中...');
Dialog.alert({
title: '提示',
message: '这是一个提示'
});
Dialog.confirm({
title: '确认',
message: '是否确认删除?'
}).then(() => {
// 用户确认
}).catch(() => {
// 用户取消
});
Notify({
type: 'success',
message: '操作成功'
});
ImagePreview([
'https://example.com/image1.jpg',
'https://example.com/image2.jpg'
]);🔍 常见问题
Q: 如何判断当前使用的是哪个版本的 WinUI?
A: 可以通过以下方式检查:
// 在浏览器控制台中检查
console.log(window.__WIN_UI_VERSION__);
// 或者查看 package.json
import pkg from '@winner-fed/win-ui/package.json';
console.log(pkg.version);Q: 为什么某些组件没有自动导入?
A: 请检查以下几点:
- 组件名称:确保使用正确的
win-前缀 - 版本兼容:检查组件是否在当前 WinUI 版本中存在
- 配置文件:确认插件已正确配置
- 重启服务:修改配置后需要重启开发服务器
Q: WinUI 1.x 的函数式组件样式丢失怎么办?
A: 需要在 legacyFunction 中配置相应的组件:
// .winrc.ts
export default defineConfig({
plugins: ['@winner-fed/plugin-winui'],
winUI: {
legacyFunction: ['Toast', 'Dialog', 'Notify', 'ImagePreview']
}
});Q: 如何自定义组件的样式?
A: 可以通过以下方式自定义:
/* 1. 使用 CSS 变量 */
:root {
--win-primary-color: #007aff;
--win-border-radius: 8px;
}
/* 2. 深度选择器 */
.custom-button :deep(.win-button) {
border-radius: 12px;
}
/* 3. 全局样式覆盖 */
.win-button--primary {
background-color: #007aff;
}Q: 如何处理 TypeScript 类型错误?
A: 确保已安装相关依赖并重新生成类型文件:
# 删除自动生成的类型文件
rm components.d.ts auto-imports.d.ts
# 重启开发服务器
npm run devQ: 如何在生产环境中优化打包体积?
A: 插件已经内置了按需引入功能,无需额外配置。如需进一步优化:
// vite.config.ts
export default {
build: {
rollupOptions: {
external: ['@winner-fed/win-ui/lib/style'] // 排除不需要的样式
}
}
}📋 最佳实践
1. 项目结构建议
src/
├── components/ # 自定义组件
│ ├── common/ # 通用组件
│ └── business/ # 业务组件
├── pages/ # 页面组件
├── styles/ # 样式文件
│ ├── variables.css # WinUI 主题变量
│ └── global.css # 全局样式
└── utils/ # 工具函数2. 主题配置建议
/* styles/variables.css */
:root {
/* 主色调 */
--win-primary-color: #007aff;
--win-success-color: #52c41a;
--win-warning-color: #faad14;
--win-danger-color: #ff4d4f;
/* 字体 */
--win-font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
--win-font-size-xs: 10px;
--win-font-size-sm: 12px;
--win-font-size-md: 14px;
--win-font-size-lg: 16px;
/* 间距 */
--win-padding-xs: 4px;
--win-padding-sm: 8px;
--win-padding-md: 16px;
--win-padding-lg: 24px;
/* 边框 */
--win-border-radius: 4px;
--win-border-color: #ebedf0;
}3. 组件使用建议
<template>
<div class="page-container">
<!-- 使用语义化的组件组合 -->
<win-nav-bar title="页面标题" left-arrow @click-left="onBack" />
<win-form @submit="onSubmit">
<win-field
v-model="form.username"
label="用户名"
placeholder="请输入用户名"
required
:rules="[{ required: true, message: '请输入用户名' }]"
/>
<win-field
v-model="form.password"
type="password"
label="密码"
placeholder="请输入密码"
required
:rules="passwordRules"
/>
<div class="form-actions">
<win-button type="primary" native-type="submit" block>
登录
</win-button>
</div>
</win-form>
</div>
</template>
<script setup>
import { ref } from 'vue';
import { useRouter } from 'vue-router';
const router = useRouter();
const form = ref({
username: '',
password: ''
});
const passwordRules = [
{ required: true, message: '请输入密码' },
{ min: 6, message: '密码至少6位' }
];
const onBack = () => {
router.back();
};
const onSubmit = () => {
// 表单提交逻辑
Toast.loading('登录中...');
// 模拟异步操作
setTimeout(() => {
Toast.success('登录成功');
router.push('/dashboard');
}, 1000);
};
</script>4. 性能优化建议
// 1. 使用 keepAlive 缓存页面
// router/index.ts
const routes = [
{
path: '/list',
component: () => import('@/pages/List.vue'),
meta: { keepAlive: true }
}
];
// 2. 组件懒加载
const HeavyComponent = defineAsyncComponent(() => import('./HeavyComponent.vue'));
// 3. 合理使用 v-if 和 v-show
<template>
<!-- 条件渲染 -->
<win-dialog v-if="showDialog" />
<!-- 显示隐藏 -->
<win-loading v-show="loading" />
</template>🛠️ 开发调试
调试模式
// .winrc.ts
export default defineConfig({
plugins: ['@winner-fed/plugin-winui'],
winUI: {
legacyFunction: ['Toast', 'Dialog']
},
// 开启调试模式
define: {
__WIN_UI_DEBUG__: true
}
});组件检查
// 在浏览器控制台中检查组件注册情况
console.log(window.__WIN_UI_COMPONENTS__);
// 检查样式加载情况
console.log(document.querySelectorAll('link[href*="win-ui"]'));🔄 版本升级
从 WinUI 1.x 升级到 3.x
- 更新依赖:
npm update @winner-fed/win-ui- 更新配置:
// .winrc.ts
export default defineConfig({
plugins: ['@winner-fed/plugin-winui'],
winUI: {
// 移除 legacyFunction 配置
// legacyFunction: ['Toast', 'Dialog']
}
});- 更新代码:
<script setup>
// 旧写法(WinUI 1.x)
// Toast('消息');
// 新写法(WinUI 3.x)
import { showToast } from '@winner-fed/win-ui';
showToast('消息');
</script>📄 许可证
MIT
