UniApp X 组件化开发:打造可复用、高内聚的跨端组件

组件化是现代前端开发的核心思想。通过将页面拆分为一个个独立、可复用的“积木块”,我们可以大幅提升开发效率、降低维护成本。

本文将带你深入掌握 UniApp X 的组件化开发,涵盖:

  • ✅ 自定义组件创建与注册
  • ✅ 组件间通信方式
  • ✅ 第三方组件库集成
  • ✅ 组件复用与封装技巧

💡 一句话理解
组件 = 可重复使用的页面“零件”,比如按钮、卡片、导航栏等


一、自定义组件创建与注册

1. 创建组件

components/ 目录下创建组件文件(推荐结构):

components/
└── MyCard/
    └── index.uvue        # 组件主文件
✅ 示例:MyCard/index.uvue
<template>
  <view class="my-card">
    <image class="card-img" :src="cover" mode="aspectFill"></image>
    <view class="card-content">
      <text class="title">{{ title }}</text>
      <text class="desc">{{ desc }}</text>
    </view>
  </view>
</template>

<script setup>
defineProps(['title', 'cover','desc'])
</script>

<style scoped lang="scss">
.my-card {
  background: white;
  border-radius: 12rpx;
  overflow: hidden;
  box-shadow: 0 4rpx 12rpx rgba(0,0,0,0.1);
  margin-bottom: 20rpx;
}

.card-img {
  width: 100%;
  height: 200rpx;
}

.card-content {
  padding: 20rpx;
}

.title {
  font-size: 32rpx;
  font-weight: 600;
  color: #333;
}

.desc {
  font-size: 28rpx;
  color: #666;
  margin-top: 10rpx;
}
</style>

配置根目录@

为了让TypeScript识别@路径别名,需要创建tsconfig.json并配置路径映射。

示例:tsconfig.json

{
  "compilerOptions": {
    "baseUrl": ".",
    "paths": {
      "@/*": ["./*"]
    }
  }
}

创建vite.config.js文件并设置resolve.alias。

示例:vite.config.uts

import { defineConfig } from 'vite';
import path from 'path';

export default defineConfig({
  resolve: {
    alias: {
      '@': path.resolve(__dirname, './')
    }
  }
});

2. 组件注册方式

✅ 方式 1:局部注册(推荐新手)

在使用组件的页面中引入:

<template>
  <view>
    <my-card 
      title="新闻标题" 
      desc="这是一条重要的新闻内容..." 
      cover="/static/news1.jpg"
    />
  </view>
</template>

<script setup>
// 局部注册组件
import MyCard from '@/components/MyCard/index.uvue'
</script>
✅ 方式 2:全局注册(适合常用组件)

main.uts 中注册:

// main.ts
import App from './App.uvue'
import MyCard from '@/components/MyCard/index.uvue'

import { createSSRApp } from 'vue'
export function createApp() {
	const app = createSSRApp(App)
	app.component('MyCard', MyCard)  // 全局注册
	return {
		app
	}
}

⚠️ 注意:全局组件会增加包体积,建议只注册高频组件


二、组件通信方式

组件之间需要“对话”,常见场景:

  • 父组件 → 子组件:传数据
  • 子组件 → 父组件:触发事件
  • 兄弟组件:通过父组件中转

1. 父传子:props

<!-- 父组件 -->
<my-card :title="item.title" :cover="item.image" />

<script setup>
const item = {
  title: 'Hello World',
  image: '/static/cover.jpg'
}
</script>
<!-- 子组件 MyCard -->
<script setup>
// 接收 props
defineProps(['title', 'cover'])
</script>

2. 子传父:emit

<!-- 子组件 MyCard -->
<template>
  <view @click="handleClick">
    <!-- 内容 -->
    卡片
  </view>
</template>

<script setup>
// 定义可触发的事件
const emit = defineEmits(['click', 'favorite'])

function handleClick() {
  emit('click', { id: 123, title: '新闻标题' })
}
</script>
<!-- 父组件 -->
<my-card @click="onCardClick" />

<script setup>
function onCardClick(data) {
  console.log('点击了卡片:', data)
}
</script>

3. 任意组件通信:mitt 或 Pinia

✅ 使用 mitt(轻量级事件总线)
npm install mitt
// utils/eventBus.ts
import mitt from 'mitt'
export default mitt()
// 组件 A:发送事件
import eventBus from '@/utils/eventBus'
eventBus.emit('news-update', { news: [...] })
// 组件 B:监听事件
import eventBus from '@/utils/eventBus'
eventBus.on('news-update', (data) => {
  console.log(data)
})

三、第三方组件库集成

除了 uView,还有很多优秀组件库可以集成。

1. 使用 uni_modules(推荐)

UniApp 官方插件市场提供标准化组件。

✅ 示例:安装 uni-icons
# 方法 1:HBuilderX 右键 -> 从插件市场下载
# 方法 2:命令行
npm install @dcloudio/uni-ui
<template>
  <uni-icons type="home" size="24" color="#007AFF"></uni-icons>
</template>

<script setup>
// 自动注册(uni_modules 支持 easycom)
</script>

2. 集成 npm 组件库

✅ 示例:集成 vue3-carousel
npm install vue3-carousel
<template>
  <carousel :items-to-show="1.2">
    <slide v-for="i in 3" :key="i">Slide {{ i }}</slide>
    <template #addons>
      <navigation />
      <pagination />
    </template>
  </carousel>
</template>

<script setup>
import { Carousel, Slide, Pagination, Navigation } from 'vue3-carousel'
import 'vue3-carousel/dist/carousel.css'
</script>

⚠️ 注意:部分 Web 组件可能不兼容小程序端


四、组件复用与封装技巧

1. 提高复用性的设计原则

原则说明
单一职责一个组件只做一件事(如:只负责显示卡片)
高内聚相关逻辑放在一起
低耦合减少对外部的依赖
可配置通过 props 控制行为

2. 封装技巧实战

✅ 技巧 1:默认插槽 + 具名插槽

让组件更灵活:

<!-- MyCard.vue -->
<template>
  <view class="my-card">
    <slot name="cover">
      <image :src="cover" mode="aspectFill"></image>
    </slot>
    
    <view class="content">
      <slot name="title">
        <text class="title">{{ title }}</text>
      </slot>
      
      <slot name="desc">
        <text class="desc">{{ desc }}</text>
      </slot>
      
      <!-- 默认插槽 -->
      <slot></slot>
    </view>
  </view>
</template>
<!-- 使用 -->
<my-card :title="item.title">
  <!-- 自定义底部按钮 -->
  <view slot="footer" class="footer">
    <button>点赞</button>
    <button>分享</button>
  </view>
</my-card>

✅ 技巧 2:使用 v-model 双向绑定
<!-- MyInput.vue -->
<template>
  <input :value="modelValue" @input="onInput" />
</template>

<script setup>
const props = defineProps(['modelValue'])
const emit = defineEmits(['update:modelValue'])

function onInput(e) {
  emit('update:modelValue', e.target.value)
}
</script>
<!-- 使用 -->
<my-input v-model="searchText" />

✅ 技巧 3:属性透传($attrs
<!-- MyButton.vue -->
<template>
  <!-- 所有未声明的属性会自动传给 button -->
  <button v-bind="$attrs" class="my-btn">
    <slot></slot>
  </button>
</template>

<script setup>
defineOptions({
  inheritAttrs: false // 避免 class 被覆盖
})
</script>
<!-- 使用:直接传原生属性 -->
<my-button type="primary" disabled @click="doSomething">提交</my-button>

✅ 技巧 4:动态组件 + is
<template>
  <component :is="currentTab.component"></component>
</template>

<script setup>
const tabs = [
  { name: '首页', component: 'HomePanel' },
  { name: '设置', component: 'SettingPanel' }
]
</script>

五、小白避坑指南

❌ 常见错误 1:组件名冲突

  • 避免使用 HTML 标签名(如 buttoninput
  • 推荐前缀命名:MyCardUButtonAppHeader

❌ 常见错误 2:props 修改警告

// ❌ 错误:直接修改 props
props.title = 'new title'

// ✅ 正确:使用本地变量
const localTitle = ref(props.title)

❌ 常见错误 3:事件未卸载

使用 mitt 时记得卸载:

onUnmounted(() => {
  eventBus.off('news-update')
})

结语

你已经掌握了 UniApp X 组件化开发的核心能力:

✅ 创建可复用的自定义组件
✅ 掌握父子组件通信方式
✅ 集成第三方组件库
✅ 运用高级封装技巧提升灵活性

立即行动

  1. 将项目中的重复代码封装成组件
  2. 使用 easycom 实现自动注册
  3. 尝试用 mitt 实现跨页面通信
  4. 为组件添加插槽支持
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

玖程

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值