7.8 KiB
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
useListTablecomposable - 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
.fullclass 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
disableAutoQueryoption to disable automatic queries
Interface:
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)
- Split into unscoped (for
-
Form components (
input.vue,select.vue, etc.):- Use scoped styles
- Support
.fullclass to override width
CSS Variables Binding
Components use v-bind() to bind Vuex state to CSS:
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
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.jsanddist/noob-mengyxu.css - CSS is extracted separately (not injected into JS)
- Vue is externalized (peer dependency)
Development Workflow
-
Local development with linking:
bun link cd ../s6a_manage bun link noob-mengyxu -
Important: When using
bun link, JS/templates load from source but CSS loads fromdist/- After CSS changes, must rebuild:
npm run build:lib
- After CSS changes, must rebuild:
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
undefinedovernullfor 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 utilitiesNoobHead: Header componentsNoobInput,NoobButton, etc.: Form componentsListTable,ModifyForm: Data componentsApi: HTTP clientStyles,Size: Theme utilities- Composables:
useListTable,useModifyForm, etc.
Recent Changes
- TypeScript Conversion: Converted list-table.vue to interface-based props
- CSS Scoping: Fixed conflicts by scoping router component styles
- Reactivity Fix: Changed to
deepCopy(toRaw(example))in useListTable - Form Layout: Fixed login form to use vertical layout (labels above inputs)
- Pagination: Fixed handling of paginated responses
{ data: [], total: N }
Dependencies
Key dependencies:
vue: ^3.xelement-plus: UI libraryvue3-i18n: Internationalizationvuex: State management (for consumers)axios: HTTP clientjs-md5: Password hashing@vueuse/core: Vue utilitieslodash-es: Utility functions