03-页面与组件开发

5 阅读3分钟

🧱 Taro 从零到一(三):页面与组件开发

系列导读:掌握了 React 基础,现在来认识 Taro 的内置组件体系。 小程序有自己的组件规范,Taro 将它们封装成了统一的 React 组件。


📊 Taro 内置组件 vs HTML

Taro 组件HTML 等价用途
<View><div>容器/块级元素
<Text><span>文本
<Image><img>图片
<Button><button>按钮
<Input><input>输入框
<Textarea><textarea>多行输入
<ScrollView><div style="overflow:scroll">滚动视图
<Swiper>轮播库轮播
<Navigator><a>导航链接

🔑 重要:在 Taro 中不能直接使用 HTML 标签! 必须从 @tarojs/components 导入 Taro 组件。


📦 1. 常用组件详解

View — 万能容器

import { View, Text } from '@tarojs/components'

// View 就是 div 的替代品
<View className="container">
  <View className="header">
    <Text>标题</Text>
  </View>
  <View className="content">
    <Text>内容</Text>
  </View>
</View>

// 点击事件
<View className="clickable" onClick={() => console.log('点击了')}>
  <Text>可点击的容器</Text>
</View>

Image — 图片

import { Image } from '@tarojs/components'

// 网络图片
<Image
  src="https://example.com/photo.jpg"
  mode="aspectFill"     // 裁剪模式
  lazyLoad              // 懒加载
  className="cover"
  onError={() => console.log('加载失败')}
/>

// mode 属性对照
// aspectFill  → CSS object-fit: cover  (常用,裁剪填满)
// aspectFit   → CSS object-fit: contain (完整显示,可能有留白)
// widthFix    → 宽度固定,高度自适应  (适合商品图)
// scaleToFill → CSS object-fit: fill   (拉伸填满,可能变形)

ScrollView — 滚动视图

import { ScrollView, View, Text } from '@tarojs/components'

// 纵向滚动列表
<ScrollView
  scrollY                          // 纵向滚动
  className="list"
  style={{ height: '600px' }}      // 必须设置固定高度
  onScrollToLower={() => {
    console.log('滚动到底部,加载更多')
    loadMore()
  }}
  refresherEnabled                 // 开启下拉刷新
  refresherTriggered={isRefreshing}
  onRefresherRefresh={() => refresh()}
>
  {items.map(item => (
    <View key={item.id} className="item">
      <Text>{item.name}</Text>
    </View>
  ))}
</ScrollView>

// 横向滚动
<ScrollView scrollX className="horizontal-list">
  {categories.map(cat => (
    <View key={cat.id} className="category-item">
      <Text>{cat.name}</Text>
    </View>
  ))}
</ScrollView>

Swiper — 轮播

import { Swiper, SwiperItem, Image } from '@tarojs/components'

<Swiper
  className="banner"
  indicatorDots          // 显示指示点
  indicatorColor="rgba(255,255,255,0.5)"
  indicatorActiveColor="#fff"
  autoplay               // 自动播放
  interval={3000}        // 切换间隔 3 秒
  circular               // 循环播放
>
  {banners.map(banner => (
    <SwiperItem key={banner.id}>
      <Image src={banner.image} mode="aspectFill" className="banner-img" />
    </SwiperItem>
  ))}
</Swiper>

🔄 2. 页面生命周期

import { useLoad, useReady, useDidShow, useDidHide, usePullDownRefresh, useReachBottom } from '@tarojs/taro'

function ListPage() {
  // 页面加载(类似 onLoad)
  useLoad((options) => {
    console.log('页面加载,参数:', options)
    // options 包含页面跳转传递的参数
    // 例如 /pages/detail/index?id=123 → options.id = '123'
  })

  // 页面初次渲染完成
  useReady(() => {
    console.log('页面渲染完成')
  })

  // 页面显示(每次切回来都会触发)
  useDidShow(() => {
    console.log('页面显示,刷新数据')
  })

  // 页面隐藏
  useDidHide(() => {
    console.log('页面隐藏')
  })

  // 下拉刷新
  usePullDownRefresh(async () => {
    await fetchData()
    Taro.stopPullDownRefresh()  // 停止刷新动画
  })

  // 触底加载更多
  useReachBottom(() => {
    console.log('到底了,加载更多')
    loadMore()
  })

  return <View>列表页</View>
}

页面配置开启下拉刷新

// pages/list/index.config.ts
export default definePageConfig({
  navigationBarTitleText: '列表',
  enablePullDownRefresh: true,  // 开启下拉刷新
  onReachBottomDistance: 100,   // 触底距离(px)
})

🏗 3. 自定义组件最佳实践

商品卡片组件

// src/components/ProductCard/index.tsx
import { View, Text, Image } from '@tarojs/components'
import './index.scss'

interface ProductCardProps {
  product: {
    id: string
    name: string
    price: number
    image: string
    sales: number
  }
  onTap?: (id: string) => void
}

export default function ProductCard({ product, onTap }: ProductCardProps) {
  return (
    <View className="product-card" onClick={() => onTap?.(product.id)}>
      <Image className="product-image" src={product.image} mode="aspectFill" />
      <View className="product-info">
        <Text className="product-name">{product.name}</Text>
        <View className="product-bottom">
          <Text className="product-price">
            <Text className="price-symbol">¥</Text>
            {product.price}
          </Text>
          <Text className="product-sales">已售 {product.sales}</Text>
        </View>
      </View>
    </View>
  )
}
// src/components/ProductCard/index.scss
.product-card {
  display: flex;
  flex-direction: column;
  background: #fff;
  border-radius: 16px;
  overflow: hidden;
  box-shadow: 0 4px 12px rgba(0, 0, 0, 0.06);

  .product-image {
    width: 100%;
    height: 320px;
  }

  .product-info {
    padding: 16px;

    .product-name {
      font-size: 28px;
      color: #1a1a1a;
      display: -webkit-box;
      -webkit-line-clamp: 2;
      -webkit-box-orient: vertical;
      overflow: hidden;
    }

    .product-bottom {
      display: flex;
      justify-content: space-between;
      align-items: center;
      margin-top: 12px;

      .product-price {
        font-size: 36px;
        font-weight: bold;
        color: #ef4444;

        .price-symbol { font-size: 24px; }
      }

      .product-sales {
        font-size: 22px;
        color: #999;
      }
    }
  }
}

✅ 本篇小结 Checklist

  • 掌握 View / Text / Image / Button 基础组件
  • 会用 ScrollView 做滚动列表(含下拉刷新、触底加载)
  • 会用 Swiper 做轮播图
  • 掌握页面生命周期 Hook(useLoad / useDidShow 等)
  • 能独立封装可复用组件

下一篇预告:《路由与页面导航》


本文是「Taro 从零到一」系列第 3 篇,共 10 篇。