uni-app 基础

lishihuan大约 10 分钟

uni-app 基础

网站:https://hellouniapp.dcloud.net.cn/pages/component/view/viewopen in new window

创建 uni-app 项目方式

uni-app 支持两种方式创建项目:

  1. 通过 HBuilderX 创建(需安装 HBuilderX 编辑器)

  2. 通过命令行创建(需安装 NodeJS 环境)

HBuilderX 创建 uni-app 项目

创建步骤

1.下载安装 HbuilderX 编辑器

2.通过 HbuilderX 创建 uni-app vue3 项目

通过 HbuilderX 创建 uni-app vue3 项目
通过 HbuilderX 创建 uni-app vue3 项目

3.安装 uni-app vue3 编译器插件

安装 uni-app vue3 编译器插件
安装 uni-app vue3 编译器插件

4.编译成微信小程序端代码

编译成微信小程序端代码
编译成微信小程序端代码

5.开启服务端口

开启服务端口
开启服务端口

小技巧分享:模拟器窗口分离和置顶

模拟器窗口分离和置顶
模拟器窗口分离和置顶

HBuildeX 和 微信开发者工具 关系

HBuildeX 和 微信开发者工具 关系
HBuildeX 和 微信开发者工具 关系

pages.json 和 tabBar 案例

目录结构

我们先来认识 uni-app 项目的目录结构。

├─pages            业务页面文件存放的目录
│  └─index
│     └─index.vue  index页面
├─static           存放应用引用的本地静态资源的目录(注意:静态资源只能存放于此)
├─unpackage        非工程代码,一般存放运行或发行的编译结果
├─index.html       H5端页面
├─main.js          Vue初始化入口文件
├─App.vue          配置App全局样式、监听应用生命周期
├─pages.json       **配置页面路由、导航栏、tabBar等页面类信息**
├─manifest.json    **配置appid**、应用名称、logo、版本等打包信息
└─uni.scss         uni-app内置的常用样式变量
 


 




 
 

解读 pages.json

用于配置页面路由、导航栏、tabBar 等页面类信息

案例练习

效果预览

案例练习
案例练习

参考代码

//pages.json
{
  // 页面路由
  "pages": [
    {
      "path": "pages/index/index",
      // 页面样式配置
      "style": {
        "navigationBarTitleText": "首页"
      }
    },
    {
      "path": "pages/my/my",
      "style": {
        "navigationBarTitleText": "我的"
      }
    }
  ],
  // 全局样式配置
  "globalStyle": {
    "navigationBarTextStyle": "white",
    "navigationBarTitleText": "uni-app",
    "navigationBarBackgroundColor": "#27BA9B",
    "backgroundColor": "#F8F8F8"
  },
  // tabBar 配置
  "tabBar": {
    "selectedColor": "#27BA9B",
    "list": [
      {
        "pagePath": "pages/index/index",
        "text": "首页",
        "iconPath": "static/tabs/home_default.png",
        "selectedIconPath": "static/tabs/home_selected.png"
      },
      {
        "pagePath": "pages/my/my",
        "text": "我的",
        "iconPath": "static/tabs/user_default.png",
        "selectedIconPath": "static/tabs/user_selected.png"
      }
    ]
  }
}

uni-app 和原生小程序开发区别

开发区别

uni-app 项目每个页面是一个 .vue 文件,数据绑定及事件处理同 Vue.js 规范:

  1. 属性绑定 src="{ { url }}" 升级成 :src="url"

  2. 事件绑定 bindtap="eventName" 升级成 @tap="eventName"支持()传参

  3. 支持 Vue 常用指令 v-forv-ifv-showv-model

其他区别补充

  1. 调用接口能力,建议前缀 wx 替换为 uni ,养成好习惯,支持多端开发
  2. <style> 页面样式不需要写 scoped,小程序是多页面应用,页面样式自动隔离
  3. 生命周期分三部分:应用生命周期(小程序),页面生命周期(小程序),组件生命周期(Vue)

案例练习

主要功能

  1. 滑动轮播图
  2. 点击大图预览

参考代码

<template>
  <swiper class="banner" indicator-dots circular :autoplay="false">
    <swiper-item v-for="item in pictures" :key="item.id">
      <image @tap="onPreviewImage(item.url)" :src="item.url"></image>
    </swiper-item>
  </swiper>
</template>

<script>
export default {
  data() {
    return {
      // 轮播图数据
      pictures: [
        {
          id: '1',
          url: 'https://pcapi-xiaotuxian-front-devtest.itheima.net/miniapp/uploads/goods_preview_1.jpg',
        },
        {
          id: '2',
          url: 'https://pcapi-xiaotuxian-front-devtest.itheima.net/miniapp/uploads/goods_preview_2.jpg',
        },
        {
          id: '3',
          url: 'https://pcapi-xiaotuxian-front-devtest.itheima.net/miniapp/uploads/goods_preview_3.jpg',
        },
        {
          id: '4',
          url: 'https://pcapi-xiaotuxian-front-devtest.itheima.net/miniapp/uploads/goods_preview_4.jpg',
        },
        {
          id: '5',
          url: 'https://pcapi-xiaotuxian-front-devtest.itheima.net/miniapp/uploads/goods_preview_5.jpg',
        },
      ],
    }
  },
  methods: {
    onPreviewImage(url) {
      // 大图预览
      uni.previewImage({
        urls: this.pictures.map((v) => v.url),
        current: url,
      })
    },
  },
}
</script>

<style>
.banner,
.banner image {
  width: 750rpx;
  height: 750rpx;
}
</style>

命令行创建 uni-app 项目

优势

通过命令行创建 uni-app 项目,不必依赖 HBuilderX,TypeScript 类型支持友好。

命令行创建 uni-app 项目:

vue3 + ts 版

::: code-group

# 通过 npx 从 github 下载
npx degit dcloudio/uni-preset-vue#vite-ts 项目名称
# 通过 git 从 gitee 克隆下载 (👉备用地址)
git clone -b vite-ts https://gitee.com/dcloud/uni-preset-vue.git

:::

创建其他版本可查看:uni-app 官网open in new window

常见问题

编译和运行 uni-app 项目

  1. 安装依赖 pnpm install
  2. 运行到微信小程序中(目前不知道什么原因,无法使用npm dev:mp-weixin

温馨提示

编译成 H5 端可运行 pnpm dev:h5 通过浏览器预览项目。

用 VS Code 开发 uni-app 项目

为什么选择 VS Code?

  • VS Code 对 TS 类型支持友好,前端开发者主流的编辑器
  • HbuilderX 对 TS 类型支持暂不完善,期待官方完善 👀

用 VS Code 开发配置

  • 👉 前置工作:安装 Vue3 插件,点击查看官方文档open in new window

    • 安装 Vue Language Features (Volar) :Vue3 语法提示插件
    • 安装 TypeScript Vue Plugin (Volar) :Vue3+TS 插件
    • 工作区禁用 Vue2 的 Vetur 插件(Vue3 插件和 Vue2 冲突)
    • 工作区禁用 @builtin typescript 插件(禁用后开启 Vue3 的 TS 托管模式)
    • 禁用 插件 TypeScript Vue Plugin (Volar)
  • 👉 安装 uni-app 开发插件

    • uni-create-view :快速创建 uni-app 页面
    • uni-helper uni-app :代码提示
    • uniapp 小程序扩展 :鼠标悬停查文档
  • 👉 TS 类型校验

    • 安装 类型声明文件 pnpm i -D miniprogram-api-typings @uni-helper/uni-app-types
    • 配置 tsconfig.json
    // tsconfig.json
    {
      "extends": "@vue/tsconfig/tsconfig.json",
      "compilerOptions": {
        "sourceMap": true,
        "baseUrl": ".",
        "paths": {
          "@/*": ["./src/*"]
        },
        "lib": ["esnext", "dom"],
        // 类型声明文件
        "types": [
          "@dcloudio/types", // uni-app API 类型
          "miniprogram-api-typings", // 原生微信小程序类型
          "@uni-helper/uni-app-types" // uni-app 组件类型
        ]
      },
      // vue 编译器类型,校验标签类型
      "vueCompilerOptions": {
        // 原配置 `experimentalRuntimeMode` 现调整为 `nativeTags`
        "nativeTags": ["block", "component", "template", "slot"], // [!code ++]
        "experimentalRuntimeMode": "runtime-uni-app" // [!code --]
      },
      "include": ["src/**/*.ts", "src/**/*.d.ts", "src/**/*.tsx", "src/**/*.vue"]
    }
    











     

     
     


     
     
     
     
     



  • 👉 JSON 注释问题

    • 设置文件关联,把 manifest.jsonpages.json 设置为 jsonc

通过设置settings.json 解决注释问题

// .vscode/settings.json
{
  // 在保存时格式化文件
  "editor.formatOnSave": true,
  // 文件格式化配置
  "[json]": {
    "editor.defaultFormatter": "esbenp.prettier-vscode"
  },
  // 配置语言的文件关联
  "files.associations": {
    "pages.json": "jsonc", // pages.json 可以写注释
    "manifest.json": "jsonc" // manifest.json 可以写注释
  }
}

也可以通过界面进行设置

版本升级

这一步处理很关键,否则 TS 项目无法校验组件属性类型。

开发工具回顾

选择自己习惯的编辑器开发 uni-app 项目即可。

HbuilderX 和 微信开发者工具 关系HbuilderX 和 微信开发者工具 关系

VS Code 和 微信开发者工具 关系VS Code 和 微信开发者工具 关系

基础

1. 路由&参数接收

路由跳转参数接收

  • 使用标签
<navigator :url="`/pages/hot/hot?type=${item.type}`">
  …省略  
</navigator>
  • 使用js方法跳转
uni.navigateTo({ url: '/pages/login/login' })
  • 跳转tabs页面

    如果跳转的页面是底部tabBar,则需要使用switchTab 进行跳转

 // 页面跳转
uni.switchTab({ url: '/pages/my/my' })

接收参数

// uniapp 获取页面参数
const query = defineProps<{
  type: string
}>()
console.log(query)

2. 动态设置标题

uni.setNavigationBarTitle({ title: currHot!.title })

3. poprs

4. ref

5. 请求

import { http } from '@/utils/http'
import type { PageParams } from '@/types/global'

/**交叉类型 **/
type HotParams = PageParams & {
  /** Tab 项的 id,默认查询全部 Tab 项的第 1 页数据 */
  subType?: string
}
/**
 * 通用热门推荐类型
 * @param url 请求地址
 * @param data 请求参数
 */
export const getHotRecommendAPI = (url: string, data?: HotParams) => { // 其中data可以不填,所以加上 ?(支持它不填写)
  return http<HotResult>({
    method: 'GET',
    url,
    data,
  })
}

6. 安全区

const { safeAreaInsets } = uni.getSystemInfoSync()
  • 头部导航栏控制
安全区域
安全区域
<template>
  <!-- 顶部占位 -->
  <view class="navbar" :style="{ paddingTop: safeAreaInsets?.top + 'px' }">
    <!-- ...省略 -->
  </view>
</template>
  • 底部安全区域控制

    image-20240805142114756
    image-20240805142114756
  <view class="toolbar" :style="{ paddingBottom: safeAreaInsets?.bottom + 'px' }">
    <view class="icons">
      <button class="icons-button"><text class="icon-heart"></text>收藏</button>
      <button class="icons-button" open-type="contact">
        <text class="icon-handset"></text>客服
      </button>
      <navigator class="icons-button"><text class="icon-cart"></text>购物车</navigator>
    </view>
    <view class="buttons">
      <view class="addcart"> 加入购物车 </view>
      <view class="payment"> 立即购买 </view>
    </view>
  </view>

7. 父子交互

  • 父调子

  • 子调父
<script setup lang="ts">
// 子调父
const emit = defineEmits<{
  (event: 'close'): void
}>()
</script>

<template>
  <view class="service-panel">
    <!-- 关闭按钮 -->
    <text class="close icon-close" @tap="emit('close')"></text>
    ...省略
  </view>
</template>

8. 组合式函数

场景说明: 猜你喜欢需要分页加载并且好几个页面都用到,所以讲其抽出作为一个公共的组件,同时

// src/composables/index.ts

import type { XtxGuessInstance } from '@/types/components'
import { ref } from 'vue'

/**
 * 猜你喜欢组合式函数
 */
export const useGuessList = () => {
  // 获取猜你喜欢组件实例
  const guessRef = ref<XtxGuessInstance>() // ref

  // 滚动触底事件
  const onScrolltolower = () => {
    guessRef.value?.getMore()
  }

  // 返回 ref 和事件处理函数
  return { guessRef, onScrolltolower }
}

9. 分包

属性类型必填描述平台兼容
subPackagesopen in new windowObject Array分包加载配置H5 不支
preloadRuleopen in new windowObject分包预下载规则(配置preloadRule后,在进入小程序某个页面时,由框架自动预下载可能需要的分包,提升进入后续分包页面时的启动速度)微信小程序

src/pagesMember/settings/settings.vue

// src/pages.json

{
  // ...省略
  // 分包加载规则
  "subPackages": [
    {
      // 子包的根目录
      "root": "pagesMember",
      // 页面路径和窗口表现
      "pages": [
        {
          "path": "settings/settings",
          "style": {
            "navigationBarTitleText": "设置"
          }
        }
      ]
    }
  ],
  // 分包预下载规则 (当前页面进入"pages/my/my" 页面后 ,不管什么网络都加载pagesMember 模块)
  "preloadRule": {
    "pages/my/my": {
      "network": "all", // [!code ++]
      "packages": ["pagesMember"] // [!code ++]
    }
  }
}





















 
 
 
 
 
 

注: WebStorm支持创建分包页面,但是需要先再pages.json页面中添加一个 subPackages和指定root

10. 图片上传

  1. 通过 uni.chooseMedia() 读取用户相册的照片或者拍照。
  2. 通过 uni.uploadFile() 上传用户图片。
// 修改头像
const onAvatarChange = () => {
  // 调用拍照/选择图片
  // 选择图片条件编译
  // #ifdef H5 || APP-PLUS
  // 微信小程序从基础库 2.21.0 开始, wx.chooseImage 停止维护,请使用 uni.chooseMedia 代替
  uni.chooseImage({
    count: 1,
    success: (res) => {
      // 文件路径
      const tempFilePaths = res.tempFilePaths
      // 上传
      uploadFile(tempFilePaths[0])
    },
  })
  // #endif

  // #ifdef MP-WEIXIN
  // uni.chooseMedia 仅支持微信小程序端
  uni.chooseMedia({
    // 文件个数
    count: 1,
    // 文件类型
    mediaType: ['image'],
    success: (res) => {
      // 本地路径
      const { tempFilePath } = res.tempFiles[0]
      // 上传
      uploadFile(tempFilePath)
    },
  })
  // #endif
}

// 文件上传-兼容小程序端、H5端、App端
const uploadFile = (file: string) => {
  // 文件上传
  uni.uploadFile({
    url: '/member/profile/avatar',
    name: 'file',
    filePath: file,
    success: (res) => {
      if (res.statusCode === 200) {
        const avatar = JSON.parse(res.data).result.avatar
        // 个人信息页数据更新
        profile.value.avatar = avatar
        // Store头像更新
        memberStore.profile!.avatar = avatar
        uni.showToast({ icon: 'success', title: '更新成功' })
      } else {
        uni.showToast({ icon: 'error', title: '出现错误' })
      }
    },
  })
}

11. 地区选择器

<script setup lang="ts">
// 修改城市
let fullLocationCode: [string, string, string] = ['', '', '']
const onFullLocationChange: UniHelper.RegionPickerOnChange = (ev) => { // 主要是记录  : UniHelper.RegionPickerOnChange
  // 修改前端界面
  profile.value.fullLocation = ev.detail.value.join(' ')
  // 提交后端更新
  fullLocationCode = ev.detail.code!
}
</script>
<template>
    <picker class="picker" mode="region" :value="profile?.fullLocation?.split(' ')" @change="onFullLocationChange" >
            <view v-if="profile?.fullLocation">{{ profile?.fullLocation }}</view>
            <view class="placeholder" v-else>请选择城市</view>
          </picker>
</team>

12. 日期选择器

<script setup lang="ts">
    const onBirthdayChange: UniHelper.DatePickerOnChange = (ev) => { // 主要是记录  : UniHelper.DatePickerOnChange
        profile.value.birthday = ev.detail.value
    }
</script>
<template>
    <picker class="picker" mode="date"  :value="profile?.birthday"
            start="1900-01-01" :end="new Date()" @change="onBirthdayChange" >
            <view v-if="profile?.birthday">{{ profile?.birthday }}</view>
            <view class="placeholder" v-else>请选择日期</view>
          </picker>
</team>

13. 单选

<script setup lang="ts">
    // 修改性别
const onGenderChange: UniHelper.RadioGroupOnChange = (ev) => {
  profile.value.gender = ev.detail.value as Gender
}
</script>
<template>
   <radio-group @change="onGenderChange">
            <label class="radio">
              <radio value="" color="#27ba9b" :checked="profile?.gender === '男'" /></label>
            <label class="radio">
              <radio value="" color="#27ba9b" :checked="profile?.gender === '女'" /></label>
          </radio-group>
</team>

注意

picker城市选择器,H5端不支持

<view class="form-item">
          <text class="label">城市</text>
          <picker
            class="picker"
            mode="region"
            :value="profile?.fullLocation?.split(' ')"
            @change="onFullLocationChange"
          >
            <view v-if="profile?.fullLocation">{{ profile?.fullLocation }}</view>
            <view class="placeholder" v-else>请选择城市</view>
          </picker>
        </view>