forked from mengyxu/noob-components
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
255 lines
7.8 KiB
255 lines
7.8 KiB
|
6 months ago
|
# noob-components
|
||
|
|
|
||
|
|
## Project Overview
|
||
|
|
|
||
|
|
A Vue 3 component library built with TypeScript and Vite, providing reusable UI components and composables for management applications. The library extends Element Plus with custom components, layouts, and utilities.
|
||
|
|
|
||
|
|
## Technology Stack
|
||
|
|
|
||
|
|
- **Framework**: Vue 3 (Composition API)
|
||
|
|
- **Language**: TypeScript
|
||
|
|
- **Build Tool**: Vite
|
||
|
|
- **Base UI Library**: Element Plus
|
||
|
|
- **Styling**: SCSS with scoped styles
|
||
|
|
- **State Management**: Vuex (for consuming applications)
|
||
|
|
- **Internationalization**: vue3-i18n
|
||
|
|
- **Package Manager**: npm/bun
|
||
|
|
|
||
|
|
## Project Structure
|
||
|
|
|
||
|
|
```
|
||
|
|
noob-components/
|
||
|
|
├── packages/
|
||
|
|
│ ├── base/ # Base UI components
|
||
|
|
│ │ ├── data/ # Data display components (ListTable, etc.)
|
||
|
|
│ │ ├── item/ # Form input components (Input, Select, DateTime, etc.)
|
||
|
|
│ │ └── layout/ # Layout components
|
||
|
|
│ ├── manage/ # Management-specific components
|
||
|
|
│ │ ├── common/ # Common components (login forms, etc.)
|
||
|
|
│ │ └── router/ # Router layout components (index.vue, zhuBeiDong.vue)
|
||
|
|
│ └── app.ts # Main export file
|
||
|
|
├── plugs/
|
||
|
|
│ ├── composables/ # Vue composables
|
||
|
|
│ │ ├── useListTable.ts # Table data management
|
||
|
|
│ │ ├── useModifyForm.ts # Form modification logic
|
||
|
|
│ │ └── ...
|
||
|
|
│ ├── http/ # HTTP utilities and API client
|
||
|
|
│ ├── element/ # Element Plus utilities
|
||
|
|
│ └── utils/ # General utilities
|
||
|
|
├── dist/ # Build output
|
||
|
|
│ ├── noob-mengyxu.js
|
||
|
|
│ ├── noob-mengyxu.css
|
||
|
|
│ └── style.css
|
||
|
|
└── vite.config.ts # Vite configuration
|
||
|
|
```
|
||
|
|
|
||
|
|
## Key Components
|
||
|
|
|
||
|
|
### Router Layouts (`packages/manage/router/`)
|
||
|
|
|
||
|
|
Two main layout components for management applications:
|
||
|
|
|
||
|
|
- **index.vue**: Standard layout with horizontal/vertical menu support
|
||
|
|
- **zhuBeiDong.vue**: Alternative layout with specific styling
|
||
|
|
|
||
|
|
Both components:
|
||
|
|
- Provide app structure with header, aside, and main content areas
|
||
|
|
- Support theme switching (via `state.style`)
|
||
|
|
- Support size adjustments (via `state.size`)
|
||
|
|
- Handle user authentication checks
|
||
|
|
- Use **scoped CSS** with `:deep()` for child component styling
|
||
|
|
|
||
|
|
### Login Components (`packages/manage/common/`)
|
||
|
|
|
||
|
|
- **login2.vue**: Login form with vertical layout (labels above inputs)
|
||
|
|
|
||
|
|
### Data Components (`packages/base/data/`)
|
||
|
|
|
||
|
|
- **list-table.vue**: Table component with pagination, sorting, filtering
|
||
|
|
- Uses TypeScript interface-based props
|
||
|
|
- Integrates with `useListTable` composable
|
||
|
|
- Supports Element Plus table features
|
||
|
|
|
||
|
|
### Form Components (`packages/base/item/`)
|
||
|
|
|
||
|
|
- **input.vue**: Text input wrapper
|
||
|
|
- **select.vue**: Select dropdown wrapper
|
||
|
|
- **datetime.vue**: Date/time picker wrapper
|
||
|
|
- **modify-form.vue**: Form modification component
|
||
|
|
|
||
|
|
All form components:
|
||
|
|
- Support `.full` class for 100% width
|
||
|
|
- Have default constrained width via `.form-item`
|
||
|
|
- Use scoped styles
|
||
|
|
|
||
|
|
## Key Composables
|
||
|
|
|
||
|
|
### useListTable (`plugs/composables/useListTable.ts`)
|
||
|
|
|
||
|
|
Manages table data with pagination and filtering.
|
||
|
|
|
||
|
|
**Important implementation details:**
|
||
|
|
- Uses `deepCopy(toRaw(example))` to avoid infinite reactivity loops
|
||
|
|
- Automatically manages pagination params (`page`, `size`)
|
||
|
|
- Supports both array and paginated response (`{ data: [], total: N }`)
|
||
|
|
- Has `disableAutoQuery` option to disable automatic queries
|
||
|
|
|
||
|
|
**Interface:**
|
||
|
|
```typescript
|
||
|
|
interface TableColumn {
|
||
|
|
code: string; // Property path (supports nested like "task.name")
|
||
|
|
name?: string; // Display name
|
||
|
|
i18n?: string; // i18n key
|
||
|
|
type?: string; // Column type
|
||
|
|
width?: string | number;
|
||
|
|
fixed?: boolean | 'left' | 'right';
|
||
|
|
align?: 'left' | 'center' | 'right';
|
||
|
|
slot?: boolean; // Use custom slot
|
||
|
|
dict?: string; // Dictionary for value mapping
|
||
|
|
timestamp?: boolean; // Format as timestamp
|
||
|
|
filesize?: boolean; // Format as file size
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
### useModifyForm (`plugs/composables/useModifyForm.ts`)
|
||
|
|
|
||
|
|
Manages form state for add/edit operations.
|
||
|
|
|
||
|
|
## Styling Conventions
|
||
|
|
|
||
|
|
### CSS Scoping
|
||
|
|
|
||
|
|
- **Router components** (`index.vue`, `zhuBeiDong.vue`):
|
||
|
|
- Split into unscoped (for `body`) and scoped blocks
|
||
|
|
- Use `:deep()` for child components from library
|
||
|
|
- Example: `:deep(.head-icon)`, `:deep(.el-input)`
|
||
|
|
|
||
|
|
- **Form components** (`input.vue`, `select.vue`, etc.):
|
||
|
|
- Use scoped styles
|
||
|
|
- Support `.full` class to override width
|
||
|
|
|
||
|
|
### CSS Variables Binding
|
||
|
|
|
||
|
|
Components use `v-bind()` to bind Vuex state to CSS:
|
||
|
|
```scss
|
||
|
|
color: v-bind("state.style.color");
|
||
|
|
background-color: v-bind("state.style.bodyBg");
|
||
|
|
font-size: v-bind("state.size.fontSize");
|
||
|
|
height: v-bind("state.size.headHeight");
|
||
|
|
```
|
||
|
|
|
||
|
|
### State Structure
|
||
|
|
|
||
|
|
```typescript
|
||
|
|
state.style = {
|
||
|
|
color: string;
|
||
|
|
bodyBg: string;
|
||
|
|
headBg: string;
|
||
|
|
itemBg: string;
|
||
|
|
selectionBg: string;
|
||
|
|
selectionColor: string;
|
||
|
|
}
|
||
|
|
|
||
|
|
state.size = {
|
||
|
|
fontSize: string;
|
||
|
|
headHeight: string;
|
||
|
|
asideWidth: string;
|
||
|
|
mainHeight: string;
|
||
|
|
tableHeight: string;
|
||
|
|
headIconSize: string;
|
||
|
|
size: 'small' | 'default' | 'large';
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
## Build Configuration
|
||
|
|
|
||
|
|
### Library Build (`vite.config.ts`)
|
||
|
|
|
||
|
|
- Entry: `packages/app.ts`
|
||
|
|
- Output: `dist/noob-mengyxu.js` and `dist/noob-mengyxu.css`
|
||
|
|
- CSS is extracted separately (not injected into JS)
|
||
|
|
- Vue is externalized (peer dependency)
|
||
|
|
|
||
|
|
### Development Workflow
|
||
|
|
|
||
|
|
1. **Local development with linking:**
|
||
|
|
```bash
|
||
|
|
bun link
|
||
|
|
cd ../s6a_manage
|
||
|
|
bun link noob-mengyxu
|
||
|
|
```
|
||
|
|
|
||
|
|
2. **Important**: When using `bun link`, JS/templates load from source but CSS loads from `dist/`
|
||
|
|
- After CSS changes, must rebuild: `npm run build:lib`
|
||
|
|
|
||
|
|
## Common Issues and Solutions
|
||
|
|
|
||
|
|
### Issue: CSS Conflicts from Multiple Router Components
|
||
|
|
|
||
|
|
**Problem**: Multiple unscoped CSS rules causing variable conflicts
|
||
|
|
|
||
|
|
**Solution**:
|
||
|
|
- Use scoped styles with `:deep()` for child elements
|
||
|
|
- Split into unscoped (body only) and scoped blocks
|
||
|
|
|
||
|
|
### Issue: Infinite Loop in useListTable with deepCopy
|
||
|
|
|
||
|
|
**Problem**: `deepCopy(example)` inside `watchEffect` establishes reactive dependencies
|
||
|
|
|
||
|
|
**Solution**: Use `deepCopy(toRaw(example))` for deep non-reactive clone
|
||
|
|
|
||
|
|
### Issue: Form Input Width Issues
|
||
|
|
|
||
|
|
**Problem**: `.form-item` class collision between components
|
||
|
|
|
||
|
|
**Solution**:
|
||
|
|
- Add `.full { width: 100%; }` to base components
|
||
|
|
- Remove conflicting styles from router components
|
||
|
|
- Use `:deep()` when needed to style library components
|
||
|
|
|
||
|
|
### Issue: Header Icons Not Styled
|
||
|
|
|
||
|
|
**Problem**: After scoping, library components don't have scoped attribute
|
||
|
|
|
||
|
|
**Solution**: Change `.head-icon` to `:deep(.head-icon)` in router components
|
||
|
|
|
||
|
|
## TypeScript Conventions
|
||
|
|
|
||
|
|
- Use interface-based prop definitions: `defineProps<Props>()`
|
||
|
|
- Use `withDefaults()` for default values
|
||
|
|
- Prefer `undefined` over `null` for optional props (simplifies types)
|
||
|
|
- Use `() => []` or `() => ({})` for array/object defaults
|
||
|
|
|
||
|
|
## Exports
|
||
|
|
|
||
|
|
Main export file: `packages/app.ts`
|
||
|
|
|
||
|
|
Exports are organized into modules:
|
||
|
|
- `Element`: Element Plus utilities
|
||
|
|
- `NoobHead`: Header components
|
||
|
|
- `NoobInput`, `NoobButton`, etc.: Form components
|
||
|
|
- `ListTable`, `ModifyForm`: Data components
|
||
|
|
- `Api`: HTTP client
|
||
|
|
- `Styles`, `Size`: Theme utilities
|
||
|
|
- Composables: `useListTable`, `useModifyForm`, etc.
|
||
|
|
|
||
|
|
## Recent Changes
|
||
|
|
|
||
|
|
1. **TypeScript Conversion**: Converted list-table.vue to interface-based props
|
||
|
|
2. **CSS Scoping**: Fixed conflicts by scoping router component styles
|
||
|
|
3. **Reactivity Fix**: Changed to `deepCopy(toRaw(example))` in useListTable
|
||
|
|
4. **Form Layout**: Fixed login form to use vertical layout (labels above inputs)
|
||
|
|
5. **Pagination**: Fixed handling of paginated responses `{ data: [], total: N }`
|
||
|
|
|
||
|
|
## Dependencies
|
||
|
|
|
||
|
|
Key dependencies:
|
||
|
|
- `vue`: ^3.x
|
||
|
|
- `element-plus`: UI library
|
||
|
|
- `vue3-i18n`: Internationalization
|
||
|
|
- `vuex`: State management (for consumers)
|
||
|
|
- `axios`: HTTP client
|
||
|
|
- `js-md5`: Password hashing
|
||
|
|
- `@vueuse/core`: Vue utilities
|
||
|
|
- `lodash-es`: Utility functions
|