uniapp

9 阅读4分钟

希望对大家有帮助吧

下载工具

HBuilderX:www.dcloud.io/hbuilderx.h…

目录结构

uniapp-project/
├── pages/              # 页面
├── components/         # 组件
├── static/             # 静态资源【图片、css文件】
├── styles/             # 公共样式
├── utils/              # 工具函数
├── api/                # 接口请求
├── stores/             # 状态管理
├── const/              # 常量配置
├── mixins/             # 混入
├── App.vue             # 整个uniapp项目的第一个组件
├── main.js             # 第一个运行的js文件【全局js文件】
├── manifest.json       # 全局文件=>应用的配置
├── pages.json          # 全局文件=>页面的配置
└── uni.scss            # 全局样式文件

环境搭建 / 平台运行

小程序平台

  • 微信小程序
  • 百度小程序
  • 支付宝小程序

运行步骤:

  1. 下载对应的小程序开发者工具
  2. 运行项目
    • web
    • app(iOS 不再支持基座调试 → 使用模拟器 xCode;安卓可用 Android Studio)

条件编译

在不同的端展示不同的代码,实现"一套代码,多端差异配置"。 uniapp.dcloud.net.cn/tutorial/pl…

平台标识

  • #ifdef H5 - 仅 H5 平台
  • #ifndef H5 - 除 H5 外
  • #ifdef APP-PLUS - 仅 App 平台
  • #ifdef MP-WEIXIN - 仅微信小程序
  • #ifdef MP-ALIPAY - 仅支付宝小程序

app-plus(App 端特有)

只针对 App 端有效,在 H5 或小程序中会自动忽略。

常见用途:

  • App 特有样式
  • 原生能力调用
  • 平台判断

使用示例

// app-plus 无法直接判断 iOS 还是 Android,需用:
const platform = uni.getSystemInfoSync().platform;

export default {
  methods: {
    doSomething() {
      // #ifdef APP-PLUS
      console.log('仅 App 端显示')
      // #endif
      
      // #ifdef H5
      console.log('仅 H5 端显示')
      // #endif
    }
  }
}
<template>
  <view class="content">
    <!-- #ifdef APP-PLUS -->
    <button type="primary">App专属按钮</button>
    <!-- #endif -->
    
    <!-- #ifdef H5 -->
    <button>H5专属按钮</button>
    <!-- #endif -->
  </view>
</template>

基本语法

建议学习 uniapp 之前先学习 vue 和微信小程序。 每一个 .vue 文件由三个部分组成:template script style

一、template:布局盒子(视图)

  • view - 类似于 div
  • text - 放入文字(可以加入属性让它选中)
  • 表单组件:button form input label

二、css

  • 尺寸单位:rpx - 响应式 px,UI 设计图宽度为 750 时,测量宽度 300px 写 300rpx

三、script

常用组件选项

  • data - 组件数据,必须是返回对象的函数
data() {
  return {
    key: ''
  }
}
  • computed - 计算属性
computed: {
  total() {
    return this.items.reduce((sum, item) => sum + item.price, 0)
  }
}
  • watch - 监听属性
watch: {
  keyword(newVal, oldVal) {
    console.log('关键词变化:', oldVal, '->', newVal)
  }
}
  • methods - 方法
methods: {
  goSearch() {
    console.log(this.key)
  }
}
  • mounted - 生命周期钩子
mounted() {
  console.log('组件已挂载')
}

组件

组件通讯

父传子

<!-- 父组件 -->
<child-component :message="parentMsg" />

<!-- 子组件 -->
props: {
  message: {
    type: String,
    default: ''
  }
}

子传父

<!-- 子组件 -->
<button @click="$emit('update', data)">发送</button>

<!-- 父组件 -->
<child-component @update="handleUpdate" />

兄弟组件通讯

// A 组件传
uni.$emit('update', data)

// B 组件接(通常在 onMounted 中监听,在 onUnload 中取消)
uni.$on('update', (data) => {
  console.log(data)
})

easycom 自动导入

easycom 可以在页面中直接使用组件,不用手动 import 和注册。

使用规则:

  • 组件放在 components/组件名/组件名.vue 目录即可自动识别
  • 配置位于 pages.json 顶部
{
  "easycom": {
    "autoscan": true,
    "custom": {
      "^u-(.*)": "uview-ui/components/u-$1/u-$1.vue"
    }
  }
}

示例:

components/
├── my-button/my-button.vue    → 可直接使用 <my-button />
├── u-button/u-button.vue     → 需配置 custom 后使用 <u-button />

生命周期

uniapp 如何定义页面?

  1. 每次新建页面需在 pages.json 中配置 pages 列表
  2. 通过 HBuilderX 开发时,右键"新建页面"会自动注册
  3. .vue 文件拥有独立的生命周期

页面生命周期

  • onLoad - 第一次进入页面执行(场景:接收页面参数)
  • onShow - 每次进入页面执行
  • onReady - 页面渲染完成(场景:可以获取 dom)
  • onHide - 页面隐藏
  • onUnload - 页面卸载

下拉刷新

需在 pages.json 对应页面配置 "enablePullDownRefresh": true

onPullDownRefresh() {
  console.log('触发下拉刷新')
  setTimeout(() => {
    uni.stopPullDownRefresh()
  }, 1000)
}

组件生命周期

与 Vue 组件生命周期相同:created mounted updated unmounted

路由页面跳转

API 方法

方法说明
uni.navigateTo保留当前页面,跳转到其他页面
uni.redirectTo关闭当前页面,跳转到其他页面
uni.reLaunch关闭所有页面,打开到应用内的某个页面
uni.switchTab跳转到 tabBar 页面(必须用此方法)
uni.navigateBack返回上一页面或多级页面
methods: {
  goList() {
    uni.navigateTo({ url: '/pages/list/list' })
  }
}

组件方式

<navigator url="/pages/list/list" open-type="switchTab">跳转到list</navigator>

页面传值

URL 参数传值

// A 页面传
uni.navigateTo({
  url: '/pages/search/search?key=' + this.key + '&id=111'
})

// B 页面接
onLoad(options) {
  this.keyName = options.key
}

网络请求

async/await 封装示例

// utils/request.js
const request = (options) => {
  return new Promise((resolve, reject) => {
    uni.request({
      url: options.url,
      method: options.method || 'GET',
      data: options.data || {},
      success: (res) => resolve(res.data),
      fail: (err) => reject(err)
    })
  })
}

// 页面中使用
async getList() {
  try {
    const res = await request({ url: '/api/list' })
    this.list = res.data
  } catch (e) {
    uni.showToast({ title: '请求失败' })
  }
}

状态管理

推荐使用 Pinia

// stores/counter.js
import { defineStore } from 'pinia'
export const useCounterStore = defineStore('counter', {
  state: () => ({ count: 0 }),
  actions: {
    increment() {
      this.count++
    }
  }
})

// 页面使用
import { useCounterStore } from '@/stores/counter'
const counter = useCounterStore()
counter.increment()

分包

当小程序代码包体积过大时,可使用分包优化。

{
  "subPackages": [
    {
      "root": "pages-sub/",
      "pages": [
        { "path": "detail/detail" }
      ]
    }
  ]
}

pages.json 配置

pages 数组

  • 第一项为应用入口页(首页)
  • 新增/减少页面需修改 pages 数组
  • 文件名不需要写后缀

tabBar 底部导航栏

属性说明
color文字默认颜色
selectedColor选中时文字颜色
backgroundColor背景色
borderStyle上边框颜色(仅支持 black/white)
midButton中间按钮(仅支持 App 和 H5)
{
  "pages": [
    { "path": "pages/index/index", "style": { "navigationBarTitleText": "首页" } }
  ],
  "tabBar": {
    "color": "#7A7E83",
    "selectedColor": "#007AFF",
    "backgroundColor": "#FFFFFF",
    "borderStyle": "black",
    "list": [
      {
        "pagePath": "pages/index/index",
        "text": "首页",
        "iconPath": "static/image/home.png",
        "selectedIconPath": "static/image/home1.png"
      }
    ]
  },
  "globalStyle": {
    "navigationBarTextStyle": "black",
    "navigationBarTitleText": "uni-app",
    "navigationBarBackgroundColor": "#F8F8F8",
    "backgroundColor": "#F8F8F8"
  }
}

常见问题

样式不生效

  • 检查是否有 scoped 样式
  • 检查选择器是否正确

请求不发起

  • 检查域名是否在白名单(小程序)
  • 检查网络权限

页面不跳转

  • 检查 pages.json 是否已注册页面
  • tabBar 页面必须使用 switchTab