Components Guide
Introduction
uni-app provides a rich set of built-in components that work across all platforms. These components are designed to provide consistent behavior and appearance across iOS, Android, web, and various mini-programs.
Component Categories
Basic Components
View Components
- view: The most basic container component
- scroll-view: Scrollable view area
- swiper: Swiper container for sliding between views
- movable-view: Movable view component
Text Components
- text: Text display component
- rich-text: Rich text component supporting HTML
Form Components
- button: Button component
- checkbox: Checkbox component
- form: Form container
- input: Input field
- label: Label for form controls
- picker: Picker component
- radio: Radio button
- slider: Slider component
- switch: Switch component
- textarea: Multi-line text input
Media Components
- audio: Audio player
- camera: Camera component
- image: Image display
- video: Video player
Map Components
- map: Map display component
Canvas Components
- canvas: Canvas for custom drawing
Web View Components
- web-view: Embedded web page
Basic Usage
View Component
The view component is the most fundamental container component:
<template>
<view class="container">
<view class="header">
<text>Header Content</text>
</view>
<view class="content">
<text>Main Content</text>
</view>
</view>
</template>
<style>
.container {
display: flex;
flex-direction: column;
height: 100vh;
}
.header {
background-color: #007aff;
padding: 20px;
}
.content {
flex: 1;
padding: 20px;
}
</style>Text Component
The text component is used for displaying text content:
<template>
<view>
<text class="title">Welcome to uni-app</text>
<text class="description">
Build once, run everywhere
</text>
<text selectable>This text is selectable</text>
</view>
</template>
<style>
.title {
font-size: 24px;
font-weight: bold;
color: #333;
}
.description {
font-size: 16px;
color: #666;
margin-top: 10px;
}
</style>Button Component
The button component provides various button types and styles:
<template>
<view class="button-container">
<!-- Basic buttons -->
<button type="primary" @click="handlePrimary">Primary Button</button>
<button type="default" @click="handleDefault">Default Button</button>
<button type="warn" @click="handleWarn">Warning Button</button>
<!-- Size variants -->
<button size="mini" type="primary">Mini Button</button>
<button size="default" type="primary">Default Size</button>
<!-- Disabled state -->
<button disabled>Disabled Button</button>
<!-- Loading state -->
<button loading type="primary">Loading...</button>
<!-- Plain style -->
<button plain type="primary">Plain Button</button>
</view>
</template>
<script>
export default {
methods: {
handlePrimary() {
uni.showToast({
title: 'Primary button clicked',
icon: 'success'
});
},
handleDefault() {
console.log('Default button clicked');
},
handleWarn() {
uni.showModal({
title: 'Warning',
content: 'This is a warning action'
});
}
}
}
</script>
<style>
.button-container {
padding: 20px;
}
button {
margin-bottom: 10px;
}
</style>Input Component
The input component handles user text input:
<template>
<view class="form-container">
<!-- Basic input -->
<input
v-model="username"
placeholder="Enter username"
@input="onInput"
@focus="onFocus"
@blur="onBlur"
/>
<!-- Password input -->
<input
v-model="password"
type="password"
placeholder="Enter password"
password
/>
<!-- Number input -->
<input
v-model="age"
type="number"
placeholder="Enter age"
/>
<!-- Styled input -->
<input
v-model="email"
type="text"
placeholder="Enter email"
class="styled-input"
/>
</view>
</template>
<script>
export default {
data() {
return {
username: '',
password: '',
age: '',
email: ''
}
},
methods: {
onInput(e) {
console.log('Input value:', e.detail.value);
},
onFocus() {
console.log('Input focused');
},
onBlur() {
console.log('Input blurred');
}
}
}
</script>
<style>
.form-container {
padding: 20px;
}
input {
width: 100%;
padding: 10px;
margin-bottom: 15px;
border: 1px solid #ddd;
border-radius: 4px;
box-sizing: border-box;
}
.styled-input {
border-color: #007aff;
background-color: #f8f9fa;
}
</style>Image Component
The image component displays images with various modes:
<template>
<view class="image-container">
<!-- Basic image -->
<image
src="/static/logo.png"
mode="aspectFit"
@load="onImageLoad"
@error="onImageError"
/>
<!-- Different modes -->
<image src="/static/banner.jpg" mode="scaleToFill" class="banner" />
<image src="/static/avatar.jpg" mode="aspectFill" class="avatar" />
<!-- Lazy loading -->
<image
src="/static/large-image.jpg"
mode="aspectFit"
lazy-load
class="lazy-image"
/>
</view>
</template>
<script>
export default {
methods: {
onImageLoad(e) {
console.log('Image loaded:', e.detail);
},
onImageError(e) {
console.log('Image load error:', e.detail);
}
}
}
</script>
<style>
.image-container {
padding: 20px;
}
image {
width: 100%;
height: 200px;
margin-bottom: 10px;
}
.banner {
height: 150px;
}
.avatar {
width: 80px;
height: 80px;
border-radius: 40px;
}
.lazy-image {
height: 300px;
}
</style>Advanced Components
Swiper Component
Create sliding panels with the swiper component:
<template>
<view class="swiper-container">
<swiper
:indicator-dots="true"
:autoplay="true"
:interval="3000"
:duration="500"
@change="onSwiperChange"
>
<swiper-item v-for="(item, index) in banners" :key="index">
<view class="swiper-item" :style="{ backgroundColor: item.color }">
<text>{{ item.title }}</text>
</view>
</swiper-item>
</swiper>
</view>
</template>
<script>
export default {
data() {
return {
banners: [
{ title: 'Banner 1', color: '#ff6b6b' },
{ title: 'Banner 2', color: '#4ecdc4' },
{ title: 'Banner 3', color: '#45b7d1' }
]
}
},
methods: {
onSwiperChange(e) {
console.log('Current swiper index:', e.detail.current);
}
}
}
</script>
<style>
.swiper-container {
height: 200px;
}
swiper {
height: 100%;
}
.swiper-item {
height: 100%;
display: flex;
justify-content: center;
align-items: center;
}
.swiper-item text {
color: white;
font-size: 18px;
font-weight: bold;
}
</style>Picker Component
Create selection pickers for various data types:
<template>
<view class="picker-container">
<!-- Single column picker -->
<picker
:range="cities"
@change="onCityChange"
>
<view class="picker-item">
Selected City: {{ selectedCity }}
</view>
</picker>
<!-- Multi-column picker -->
<picker
mode="multiSelector"
:range="[provinces, cities, districts]"
@change="onRegionChange"
>
<view class="picker-item">
Selected Region: {{ selectedRegion }}
</view>
</picker>
<!-- Date picker -->
<picker
mode="date"
:start="startDate"
:end="endDate"
@change="onDateChange"
>
<view class="picker-item">
Selected Date: {{ selectedDate }}
</view>
</picker>
<!-- Time picker -->
<picker
mode="time"
@change="onTimeChange"
>
<view class="picker-item">
Selected Time: {{ selectedTime }}
</view>
</picker>
</view>
</template>
<script>
export default {
data() {
return {
cities: ['Beijing', 'Shanghai', 'Guangzhou', 'Shenzhen'],
provinces: ['Beijing', 'Shanghai', 'Guangdong'],
districts: ['Chaoyang', 'Haidian', 'Dongcheng'],
selectedCity: 'Beijing',
selectedRegion: 'Beijing',
selectedDate: '2023-01-01',
selectedTime: '12:00',
startDate: '2020-01-01',
endDate: '2030-12-31'
}
},
methods: {
onCityChange(e) {
const index = e.detail.value;
this.selectedCity = this.cities[index];
},
onRegionChange(e) {
const [provinceIndex, cityIndex, districtIndex] = e.detail.value;
this.selectedRegion = `${this.provinces[provinceIndex]} - ${this.cities[cityIndex]}`;
},
onDateChange(e) {
this.selectedDate = e.detail.value;
},
onTimeChange(e) {
this.selectedTime = e.detail.value;
}
}
}
</script>
<style>
.picker-container {
padding: 20px;
}
.picker-item {
padding: 15px;
border: 1px solid #ddd;
border-radius: 4px;
margin-bottom: 10px;
background-color: #f8f9fa;
}
</style>Component Best Practices
1. Performance Optimization
- Use
v-ifinstead ofv-showfor conditional rendering when the condition rarely changes - Implement lazy loading for images and lists
- Use
keyattributes for list items to improve rendering performance
2. Cross-Platform Compatibility
- Test components on all target platforms
- Use platform-specific styles when necessary
- Handle platform differences in component behavior
3. Accessibility
- Provide meaningful labels and descriptions
- Ensure proper focus management
- Support keyboard navigation where applicable
4. Responsive Design
- Use flexible layouts with flexbox
- Implement responsive font sizes and spacing
- Test on different screen sizes and orientations
Custom Components
Creating Custom Components
<!-- components/CustomCard.vue -->
<template>
<view class="custom-card" :class="{ 'card-shadow': shadow }">
<view class="card-header" v-if="title">
<text class="card-title">{{ title }}</text>
</view>
<view class="card-content">
<slot></slot>
</view>
<view class="card-footer" v-if="$slots.footer">
<slot name="footer"></slot>
</view>
</view>
</template>
<script>
export default {
name: 'CustomCard',
props: {
title: {
type: String,
default: ''
},
shadow: {
type: Boolean,
default: false
}
}
}
</script>
<style scoped>
.custom-card {
border: 1px solid #e0e0e0;
border-radius: 8px;
background-color: white;
margin-bottom: 16px;
}
.card-shadow {
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
}
.card-header {
padding: 16px 16px 0;
}
.card-title {
font-size: 18px;
font-weight: bold;
color: #333;
}
.card-content {
padding: 16px;
}
.card-footer {
padding: 0 16px 16px;
border-top: 1px solid #f0f0f0;
margin-top: 16px;
padding-top: 16px;
}
</style>Using Custom Components
<template>
<view class="page">
<custom-card title="Welcome" :shadow="true">
<text>This is the main content of the card.</text>
<template #footer>
<button size="mini" type="primary">Action</button>
</template>
</custom-card>
<custom-card>
<text>Card without title</text>
</custom-card>
</view>
</template>
<script>
import CustomCard from '@/components/CustomCard.vue'
export default {
components: {
CustomCard
}
}
</script>Troubleshooting
Common Issues
- Component not displaying: Check if the component is properly imported and registered
- Styling issues: Verify CSS specificity and platform-specific styles
- Event handling problems: Ensure event names are correct and handlers are properly bound
- Performance issues: Optimize component rendering and data binding
Platform-Specific Considerations
- Mini-programs: Some HTML tags and CSS properties may not be supported
- App platforms: Native component behavior may differ from web
- H5: Consider browser compatibility for advanced features
Conclusion
uni-app components provide a powerful foundation for building cross-platform applications. By understanding component usage patterns, best practices, and platform considerations, you can create robust and maintainable applications that work seamlessly across all supported platforms.
For more detailed information about specific components, refer to the official uni-app documentation.