[uni-app]小兔鲜-01项目起步

项目介绍

效果演示

技术架构

创建项目

HBuilderX创建

下载HBuilderX编辑器

HBuilderX/创建项目: 选择模板/选择Vue版本/创建

安装插件: 工具/插件安装/uni-app(Vue3)编译器

vue代码不能直接运行在小程序环境, 编译插件帮助我们进行代码转换

绑定微信开发者工具: 指定微信开发者工具安装目录后, HBX才能启动微信开发者工具

开启服务端口: 微信开发者工具/设置/安全设置/开启服务端口, 开启服务端口后HBX才能启动微信开发者工具

运行项目: 运行/小程序模拟器/微信开发者工具

开发技巧: 模拟器窗口分离/置顶

目录解析

tabbar切换案例

  1. 创建页面: page/右键新建页面
  1. 设置tabbar和窗口表现

    // 页面配置文件
    {
    // 页面路由和窗口表现, 创建页面自动添加
    "pages": [
    // pages数组中第一项表示应用启动页
    {
    "path": "pages/index/index",
    "style": {
    "navigationStyle": "custom", // 隐藏默认导航
    "navigationBarTextStyle": "white",
    "navigationBarTitleText": "首页"
    }
    },
    {
    "path": "pages/my/my",
    "style": {
    "navigationStyle": "custom",
    "navigationBarTextStyle": "white",
    "navigationBarTitleText": "我的"
    }
    },
    ],
    // 全局页面设置
    "globalStyle": {
    "navigationBarTextStyle": "black",
    "navigationBarTitleText": "",
    "navigationBarBackgroundColor": "#F8F8F8",
    "backgroundColor": "#F8F8F8"
    },
    // 设置 TabBar, 至少两个
    "tabBar": {
    "color": "#333",
    "selectedColor": "#27ba9b",
    "backgroundColor": "#fff",
    "borderStyle": "white",
    "list": [
    {
    "text": "首页",
    "pagePath": "pages/index/index",
    "iconPath": "static/tabs/home_default.png",
    "selectedIconPath": "static/tabs/home_selected.png"
    },
    {
    "text": "我的",
    "pagePath": "pages/my/my",
    "iconPath": "static/tabs/user_default.png",
    "selectedIconPath": "static/tabs/user_selected.png"
    }
    ]
    }
    }

  2. 配置应用信息: 配置微信appid后, 才能使用微信开发者工具进行真机预览

uniapp对比原生小程序: 每个页面都是.vue文件, 数据绑定和事件处理遵循 vue 规范就可以了

  1. 属性绑定 src="{{ url }}" 升级为 :src="url"
  2. 事件绑定 bindtap="xxx" 升级为 @tap="xxx" , 支持()传参
  3. 支持Vue常用指令 v-for/v-if/v-show/v-model
  4. 多端开发使用 uni 替换 wx 调用接口能力

实现轮播图效果和大图预览效果

<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"},
        ]
      } 
   },
  methods: {
    onPreviewImage(url) {
      uni.previewImage({
        urls:this.pictures.map(v=>v.url),
        current:url
      })
    }
  }
}
</scripr>

命令行创建

创建项目

  1. 打开cmd, 执行命令: npx degit dcloudio/uni-preset-vue#vite-ts 自定义项目名称
  2. npx是node自带的包管理工具
  3. 官网链接: uni-app官网创建uni-app
  4. 如果下载失败可以去官网下载, 或者切换网络尝试

运行项目

  1. 项目中src目录下存放的就是uni-app工程代码
  1. 添加appid: 在manifest.json文件配置appid
  2. 安装依赖: pnpm install
  3. 项目编译: pnpm dev:mp-weixin
  4. 项目运行: 把编译后的文件 dist/dev/mp-weixin 导入微信开发者工具

vscode编译器配置: 目前vscode对TS类型支持友好

  1. 插件安装uni-app插件

安装uni-create-view插件

功能: 快速创建页面

安装uni-helper插件

功能: uniapp代码提示, ctrl + i

安装 uniapp小程序扩展 插件

功能: 鼠标悬停查看文档

  1. 配置ts类型校验
  • 作用: 使用uniapp或微信组件时, 如果属性配置错误, 在编码阶段直接爆红, 开发效率更高

  • 依赖安装: pnpm i -D @types/wechat-miniprogram @uni-helper/uni-app-types

    {
    "compilerOptions": {
    ... ...
    "types": [
    "@dcloudio/types", // 默认的TS类型文件
    "miniprogram-api-typings", //微信小程序组件类型增强文件
    "@uni-helper/uni-app-types", //uniapp组件类型增强文件
    ]
    },
    "vueCompilerOptions": {
    // 配置vue的编辑器模式为uniapp
    // 已废弃,现调整为 nativeTags,请升级 Volar 插件至最新版本
    // experimentalRuntimeMode: "runtime-uni-app",
    "nativeTags": [
    "block",
    "component",
    "template",
    "slot"
    ]
    },
    }

  1. 解决json注释问题
  • HBX中, 允许JSON文件中出现注释
  • vscode中, JSON文件默认是严格JSON模式, 把JSON配置文件配置成jsonc模式, 就可以正确识别注释了
  • uniapp中, 只有pages.json和manifest.json文件支持注释, 其他的json文件不要配置

基础架构

模版代码: git clone http://gititcast.cn/heimagianduan/erabbit-uni-app-vue3-ts.git heima-shop

安装依赖: pnpm install

配置appid:

{
    /* 小程序特有相关 */
    "mp-weixin" : {
        "appid" : "wxb161c259ad057faaaa",
        "setting" : {
            "urlCheck" : false
        },
        "usingComponents" : true
    },
}

编译代码: pnpm dev:mp-weixin

运行代码: 微信小程序打开dist/dev/mp-weixin

安装uni-ui组件库, 并配置uni-ui组件的自动按需导入

{
	// 组件自动引入规则
	"easycom": {
		// 开启自动扫描
		"autoscan": true,
		// 以正则方式自定义组件匹配规则
		"custom": {
			// uni-ui 规则如下配置
			"^uni-(.*)": "@dcloudio/uni-ui/lib/uni-$1/uni-$1.vue",
		}
	},
	"pages": [
    ... ...
  ],
}
  1. 执行 pnpm i @dcloudio/uni-ui 命令安装组件库
  2. 自动导入原理: 当我们使用uni-cart 组件时, 由于组件名以 uni- 开头, 就会被custom规则匹配到, 把组件的名称提取出来, 然后交给$1变量读取, 拼接后是完整组件地址, 就能被引入到项目中

uni ui是基于JS开发的, 本身没有提供TS类型支持, 第三方社区开源了uni-ui的类型增强文件, 供我们使用

{
  "extends": "@vue/tsconfig/tsconfig.json",
  "compilerOptions": {
    ... ...
    "types": [
       // 默认的类型增强文件也是必须的
      "@dcloudio/types",
       // 添加安装的uni-ui类型增强文件
      "@uni-helper/uni-ui-types"
    ]
  },
  "include": [
    "src/**/*.ts",
    "src/**/*.d.ts",
    "src/**/*.tsx",
    // 要确保包含使用uni组件的vue文件
    "src/**/*.vue"
  ]
}
  1. 安装命令: pnpm i -D @uni-helper/uni-ui-types
  2. 安装配置完成后需要重启项目, 才能生效

状态管理: 基础代码中已经集成了pinia仓库, 我们只进行持久化配置就可以了

// 定义 Store
export const useMemberStore = defineStore(
  'member',
  () => { },
  // 持久化配置
  {
    // 网页端配置
    // persist: true,
    // 小程序端配置
    persist: {
      storage: {
        setItem(key, value) {
          uni.setStorageSync(key, value)
        },
        getItem(key) {
          return uni.getStorageSync(key)
        },
      },
    },
  },
)
  1. 由于网页端和小程序使用不同的本地存储API, 所以持久化配置的方式略有不同

请求拦截器: 拦截request/uploadFile请求, 配置基地址,超时时间, 请求头表示和token

import { useMemberStore } from '@/stores'

/**
 * 请求拦截
 */

// 封装请求
const baseURL = 'https://pcapi-xiaotuxian-front-devtest.itheima.net'

// 请求拦截器
const httpInterceptor = {
    // 拦截前触发
    invoke(options: UniApp.RequestOptions) {
        // 1,非http开头需要拼接地址
        if (!options.url.startsWith('http')) {
            options.url = baseURL + options.url
        }
        // 2, 请求超时(10s)
        options.timeout = 10000
        // 3,添加小程序端请求头标识
        options.header = {
            ...options.header,
            'source-client': 'miniapp',
        }
        // 4,添加token
        const memberStore = useMemberStore()
        const token = memberStore.profile?.token
        if (token) {
            options.header.Authorization = token
        }
    },
}

// 添加拦截器
uni.addInterceptor('request', httpInterceptor)
uni.addInterceptor('uploadFile', httpInterceptor)

请求函数: 二次封装uni.request函数, 对返回结果进行promise化

/**
 * 请求函数
 */
// 接口(定义后台返回数据的类型)
interface Data<T> {
    code: string
    msg: string
    result: T
}

export const http = <T>(options: UniApp.RequestOptions) => {
    // 1,返回Promise对象
    return new Promise<Data<T>>((resolve, reject) => {
        uni.request({
            ...options,
            // 响应成功(uni.requres中只要服务器有响应,就执行success回调)
            success(res) {
                if (res.statusCode >= 200 && res.statusCode < 300) {
                    // 2,成功
                    resolve(res.data as Data<T>)
                } else if (res.statusCode === 401) {
                    // 清理用户信息,调整到登录页
                    const memberStore = useMemberStore()
                    memberStore.clearProfile()
                    uni.navigateTo({
                        url: '/pages/login/login',
                    })
                    reject(res)
                } else {
                    // 其他错误
                    uni.showToast({
                        title: (res.data as Data<T>).msg || '请求错误',
                        icon: 'none',
                    })
                    reject(res)
                }
            },
            fail(err) {
                // 3,失败
                uni.showToast({
                    title: '请求失败,换个网络试试',
                    icon: 'none',
                })
                reject(err)
            },
        })
    })
}
  1. uni.request函数的sucess成功回调, 只要服务有响应就会执行, 我们需要对状态码进行更准确的判断
  2. 如果状态码是401就跳转到登录页, 如果是其他错误就展示后台返回的错误信息
  3. 如果网络出现问题, 服务器不会响应, 就会触发fail失败回调, 提示网络错误就行了

首页导航栏

安全区域: 通过 uni.getSystemInfoSync() 方法获取不同机型导航栏的安全距离

准备导航栏组件, 使用导航栏组件

<script setup lang="ts">
// 获取屏幕边界到安全区域距离
const { safeAreaInsets } = uni.getSystemInfoSync()
</script>

<template>
  <view class="navbar" :style="{ paddingTop: safeAreaInsets!.top + 10 + 'px' }">
    <!-- logo文字 -->
    <view class="logo">
      <image class="logo-image" src="@/static/images/logo.png"></image>
      <text class="logo-text">新鲜 · 亲民 · 快捷</text>
    </view>
    <!-- 搜索条 -->
    <view class="search">
      <text class="icon-search">搜索商品</text>
      <text class="icon-scan"></text>
    </view>
  </view>
</template>

<style lang="scss">
/* 自定义导航条 */
.navbar {
  background-image: url(@/static/images/navigator_bg.png);
  background-size: cover;
  position: relative;
  display: flex;
  flex-direction: column;
  padding-top: 20px;
  .logo {
    display: flex;
    align-items: center;
    height: 64rpx;
    padding-left: 30rpx;
    .logo-image {
      width: 166rpx;
      height: 39rpx;
    }
    .logo-text {
      flex: 1;
      line-height: 28rpx;
      color: #fff;
      margin: 2rpx 0 0 20rpx;
      padding-left: 20rpx;
      border-left: 1rpx solid #fff;
      font-size: 26rpx;
    }
  }
  .search {
    display: flex;
    align-items: center;
    justify-content: space-between;
    padding: 0 10rpx 0 26rpx;
    height: 64rpx;
    margin: 16rpx 20rpx;
    color: #fff;
    font-size: 28rpx;
    border-radius: 32rpx;
    background-color: rgba(255, 255, 255, 0.5);
  }
  .icon-search {
    &::before {
      margin-right: 10rpx;
    }
  }
  .icon-scan {
    font-size: 30rpx;
    padding: 15rpx;
  }
}
</style>

<script setup lang="ts">
import CustomNavbar from './components/CustomNavbar.vue'
  
</script>

<template>
  <!-- 自定义导航组件 -->
  <CustomNavbar />
</template>

隐藏首页的默认导航栏

{
	"pages": [
		{
			"path": "pages/index/index",
			"style": {
				"navigationStyle": "custom", // 隐藏默认导航
				"navigationBarTextStyle": "white",
				"navigationBarTitleText": "首页"
			}
		},
	],
}

实现效果

相关推荐
向前看-26 分钟前
验证码机制
前端·后端
燃先生._.1 小时前
Day-03 Vue(生命周期、生命周期钩子八个函数、工程化开发和脚手架、组件化开发、根组件、局部注册和全局注册的步骤)
前端·javascript·vue.js
高山我梦口香糖2 小时前
[react]searchParams转普通对象
开发语言·前端·javascript
m0_748235242 小时前
前端实现获取后端返回的文件流并下载
前端·状态模式
m0_748240253 小时前
前端如何检测用户登录状态是否过期
前端
black^sugar3 小时前
纯前端实现更新检测
开发语言·前端·javascript
寻找沙漠的人4 小时前
前端知识补充—CSS
前端·css
GISer_Jing4 小时前
2025前端面试热门题目——计算机网络篇
前端·计算机网络·面试
m0_748245524 小时前
吉利前端、AI面试
前端·面试·职场和发展