agentleFS
huanglei288766huanglei288766/claude-code-zh/skills/miniprogram-dev/SKILL.md

miniprogram-dev

Skill6 starsChanged 8 months agoMITView on GitHub

本 Skill 覆盖微信原生小程序和 uni-app(Taro)的开发规范,帮助 Claude Code 生成符合国内主流标准的小程序代码。 适用场景: - 微信原生小程序页面开发 - uni-app 跨端组件编写 - 小程序状态管理(Pinia / Vuex) - 小程序 API 封装(request、storage、login)

  • Reads credentials

The file

Files
SKILL.md

微信小程序 / uni-app 开发规范

概述

本 Skill 覆盖微信原生小程序和 uni-app(Taro)的开发规范,帮助 Claude Code 生成符合国内主流标准的小程序代码。

适用场景:

  • 微信原生小程序页面开发
  • uni-app 跨端组件编写
  • 小程序状态管理(Pinia / Vuex)
  • 小程序 API 封装(request、storage、login)

目录结构规范

uni-app(推荐)

src/
├── pages/                  # 页面
│   ├── index/
│   │   ├── index.vue
│   │   └── components/     # 页面级私有组件
│   └── order/
│       ├── list.vue
│       └── detail.vue
├── components/             # 全局公共组件
│   ├── base/               # 基础组件(Button、Icon 等)
│   └── business/           # 业务组件
├── stores/                 # Pinia 状态管理
│   ├── user.ts
│   └── cart.ts
├── api/                    # 接口封装
│   ├── request.ts          # 统一请求封装
│   ├── user.ts
│   └── order.ts
├── utils/                  # 工具函数
├── hooks/                  # 组合式函数
└── types/                  # TypeScript 类型

请求封装

// api/request.ts — 统一请求封装,处理 token、错误码、loading
import { useUserStore } from '@/stores/user'

interface RequestOptions {
  url: string
  method?: 'GET' | 'POST' | 'PUT' | 'DELETE'
  data?: Record<string, unknown>
  showLoading?: boolean
}

interface ApiResponse<T = unknown> {
  code: number
  message: string
  data: T
}

const BASE_URL = import.meta.env.VITE_API_BASE_URL

export async function request<T = unknown>(options: RequestOptions): Promise<T> {
  const { url, method = 'GET', data, showLoading = false } = options
  const userStore = useUserStore()

  if (showLoading) uni.showLoading({ title: '加载中' })

  return new Promise((resolve, reject) => {
    uni.request({
      url: BASE_URL + url,
      method,
      data,
      header: {
        'Content-Type': 'application/json',
        Authorization: `Bearer ${userStore.token}`,
      },
      success: (res) => {
        const result = res.data as ApiResponse<T>
        if (result.code === 200) {
          resolve(result.data)
        } else if (result.code === 401) {
          // token 过期,跳转登录
          userStore.logout()
          uni.navigateTo({ url: '/pages/login/index' })
          reject(new Error('登录已过期'))
        } else {
          uni.showToast({ title: result.message, icon: 'error' })
          reject(new Error(result.message))
        }
      },
      fail: (err) => {
        uni.showToast({ title: '网络请求失败', icon: 'error' })
        reject(err)
      },
      complete: () => {
        if (showLoading) uni.hideLoading()
      },
    })
  })
}

// 语法糖
export const get = <T>(url: string, data?: Record<string, unknown>) =>
  request<T>({ url, method: 'GET', data })

export const post = <T>(url: string, data?: Record<string, unknown>) =>
  request<T>({ url, method: 'POST', data })

微信登录封装

// hooks/useWxLogin.ts
import { ref } from 'vue'
import { post } from '@/api/request'
import { useUserStore } from '@/stores/user'

export function useWxLogin() {
  const loading = ref(false)
  const userStore = useUserStore()

  async function login(): Promise<void> {
    loading.value = true
    try {
      // Step 1: 获取微信 code
      const { code } = await new Promise<WechatMiniprogram.LoginSuccessCallbackResult>(
        (resolve, reject) => uni.login({ success: resolve, fail: reject })
      )
      // Step 2: 换取业务 token
      const { token, userInfo } = await post<{ token: string; userInfo: UserVO }>(
        '/auth/wx-login', { code }
      )
      userStore.setToken(token)
      userStore.setUser(userInfo)
    } finally {
      loading.value = false
    }
  }

  return { login, loading }
}

分页列表 Hook

// hooks/usePagination.ts — 通用上拉加载更多
import { ref, reactive } from 'vue'

export function usePagination<T>(
  fetchFn: (page: number, pageSize: number) => Promise<{ list: T[]; total: number }>
) {
  const list = ref<T[]>([])
  const loading = ref(false)
  const refreshing = ref(false)
  const finished = ref(false)
  const pagination = reactive({ page: 1, pageSize: 20, total: 0 })

  async function loadMore() {
    if (loading.value || finished.value) return
    loading.value = true
    try {
      const { list: newItems, total } = await fetchFn(pagination.page, pagination.pageSize)
      list.value.push(...newItems)
      pagination.total = total
      pagination.page++
      finished.value = list.value.length >= total
    } finally {
      loading.value = false
    }
  }

  async function refresh() {
    refreshing.value = true
    list.value = []
    pagination.page = 1
    finished.value = false
    try {
      await loadMore()
    } finally {
      refreshing.value = false
    }
  }

  // 初始加载
  loadMore()

  return { list, loading, refreshing, finished, loadMore, refresh }
}

页面规范

<!-- pages/order/list.vue -->
<script setup lang="ts">
import { usePagination } from '@/hooks/usePagination'
import { orderApi } from '@/api/order'

// 页面标题用 definePageMeta(uni-app Vite 模式)
defineOptions({ name: 'OrderList' })

const { list, loading, finished, loadMore, refresh } = usePagination(
  (page, pageSize) => orderApi.getList({ page, pageSize })
)

// 下拉刷新
onPullDownRefresh(async () => {
  await refresh()
  uni.stopPullDownRefresh()
})

// 上拉加载更多
onReachBottom(() => loadMore())
</script>

<template>
  <view class="order-list">
    <order-item
      v-for="order in list"
      :key="order.id"
      :order="order"
    />
    <view v-if="loading" class="loading-tip">加载中...</view>
    <view v-if="finished && !loading" class="finished-tip">没有更多了</view>
  </view>
</template>

常见错误

❌ 直接调用 wx API,不封装

// 错误:到处写原生调用,难以维护
wx.request({ url: 'https://api.example.com/...' })

✅ 统一通过封装层调用

// 正确:统一的 request 封装处理 token、错误
import { get } from '@/api/request'
const orders = await get<Order[]>('/orders')

❌ 在页面中写 API 调用逻辑

// 错误:API 逻辑写在页面里
onLoad(async () => {
  const res = await uni.request({ url: '...' })
  list.value = res.data.data
})

✅ 封装到 api 层

// api/order.ts
export const orderApi = {
  getList: (params: OrderQuery) => get<PageResult<OrderVO>>('/orders', params),
}
// 页面中
const orders = await orderApi.getList({ page: 1, pageSize: 20 })

Download now (ZIP)

Does it work?

Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.

Reviews can't be read right now.

Your trail

Files you open will collect here, so you can find them again.

Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.

Now do this for your own.

Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.