移动端开发篇(uni版)

一、项目构建与调试

项目构建分别为两种


1、基于和buildx构建


打开 hbuildx -> 新建 -> 项目 -> uni-app ->选择一个模板 (直接推荐 默认)
你会得到如下项目结构:

  • pages - 存放所有页面文件的目录,每个页面通常包含 .vue 文件
  • static - 静态资源目录,用于存放图片、字体等静态文件
  • App.vue - 应用的根组件,定义应用的全局生命周期和样式
  • main.js - 应用的入口文件,用于初始化 Vue 实例和全局配置
  • manifest.json - 应用的配置文件,包含应用名称、图标、版本等信息,特别是打包 App 时的配置
  • pages.json - 页面路由配置文件,定义页面路径、窗口样式、tabBar 等
  • shime-uni.d.ts - TypeScript 类型声明文件,为 uni-app API 提供类型定义
  • uni.scss - 全局样式变量文件,可定义全局使用的样式变量
     

2、使用npx 直接创建 (推荐)


npx degit dcloudio/uni-preset-vue#vite my-project
详细网址如下 uni-app官网
项目结构如下图所示:

npx构建的项目相对于hubuildx 创建的项目来说提供了更多便利
1、 package.json
     (uni的基础依赖)、
        vite.config(构建工具配置)、
       .gitignore自动集成到里面
2、可以使用其他代码编辑器直接开发
        直接用npm run dev:h5 就可以直接吧项目跑起来了相对hbuildx更方便
3、更适合复杂项目
        对于大型项目,命令行方式通常更灵活
        可以更好地管理复杂的依赖关系
4、更好的定制性   
        可以更方便地修改 Vite 配置  
        更容易集成第三方工具和库 
        更容易自定义构建流程.

界面预览&调试


1、h5 、app


hbuilder开发过程中选择运行 -> 然后可以选择内置浏览器 或者直接运行到浏览器

在npx构建项目中可以 直接 npm run dev:h5 但是具体看 package.json 的配置;
关于数据请求渲染页面相关在 开发配置项中介绍


2、微信小程序调试


微信小程序的界面调试相对来说麻烦点 当然可以用测试appId 

 关于appId 的申请 :
1、微信公众平台:微信公众平台 打开后账号分类选择“小程序”
2、点击注册按钮,进入小程序注册步骤 注册
3、进行信息登记 完善信息等等  
相关请参考

第一步appid
1、配置appId 用hbuilder 打开 manifest.json 选择微信小程序配置 
2、或者直接在manifest.json —— "mp-weixin"中填写

第二步 配置运行微信开发者工具
hbuilder 中

npx 项目中

就可以了 

第三步 跑起来就完了

二、开发 配置项 注意事项

1、路由导航栏篇



       “easycom” 粗俗点 全局组件引用 简化组件的引用方式 不需要手动导入组件的情况下直接在模板中使用组件
        “pages” 粗俗点可以直接看成  路由配置 当然其中包含了 “path” 页面路径、 "style"导航栏配置
        “tabBar” 底部路由导航栏

其中可以稍微注意一下一些默认属性 比如在写移动端的时候 经常要计算内容区的高度 

export const getNavHeight = () => {
  const systemInfo = uni.getSystemInfoSync();
  const statusBarHeight = systemInfo.statusBarHeight; // 状态栏高度
  const navBarHeight = 44; // 导航栏固定高度
  const tabBarHeight = 50; // 底部导航栏固定高度

  return {
    allHeight: statusBarHeight + navBarHeight + tabBarHeight,
    topHeight: statusBarHeight + navBarHeight
  };
};


2、页面篇

 html


页面代码相对没那么多注意的东西就正常的看成 .vue 文件就好了 
当然我们在开发过程中也要注意适配 
比如 在html中:div-> view 、 img->image 、 span->text 适当进行统一 这样在运行小程序或者打包的时候能避免大多数问题
图片方面 移动端尽量少使用本地图片 要想直接适配小程序 要保证打包后体积小于2m 所以图片能用请求就用请求  当然 不兼容小程序无所谓

推荐比较好用一点的form 表单组件 uni-form 个人觉得还行 经过全局引入之后可以直接使用
代码示例

//安装 npm install  @dcloudio/uni-ui

//全局注册  pages.json中

 "easycom": {
    "autoscan": true,
    "custom": {
      "^uni-(.*)": "@dcloudio/uni-ui/lib/uni-$1/uni-$1.vue"
    }
  }
<template>
    <div class="edit-class-container">
        <uni-forms ref="form" :model="formData" :rules="rules">
            <uni-forms-item label="班次名称" name="className">
                <uni-easyinput v-model="formData.className" placeholder="请输入班次名称" />
            </uni-forms-item>

            <uni-forms-item label="上班时间" name="startTime">
                <view class="time-picker" @click="openTimePicker('start')">
                    <text>{{ formData.startTime || '请选择上班时间' }}</text>
                    <text class="picker-icon">></text>
                </view>
            </uni-forms-item>

            <uni-forms-item label="下班时间" name="endTime">
                <view class="time-picker" @click="openTimePicker('end')">
                    <text>{{ formData.endTime || '请选择下班时间' }}</text>
                    <text class="picker-icon">></text>
                </view>
            </uni-forms-item>
        </uni-forms>

        <button class="submit-btn" @click="handleSubmit">确定</button>
    </div>

    <!-- 时间选择器弹窗 -->
    <uni-popup ref="popup" type="bottom">
        <view class="picker-container">
            <view class="picker-header">
                <text @click="cancelPicker">取消</text>
                <text @click="confirmPicker">确定</text>
            </view>
            <picker-view class="picker-view" :value="timeArray" @change="handleTimeChange">
                <picker-view-column>
                    <view class="item" v-for="(hour, index) in hours" :key="index">{{ hour }}</view>
                </picker-view-column>
                <picker-view-column>
                    <view class="item" v-for="(minute, index) in minutes" :key="index">{{ minute }}</view>
                </picker-view-column>
            </picker-view>
        </view>
    </uni-popup>
</template>
const form = ref(null);
const popup = ref(null);
const formData = ref({
    className: '',
    startTime: '',
    endTime: ''
});

// ....


在样式上


尽量不要去使用 background-image这个东西(在小程序中没用)

其他样式基本上正常写

路由跳转

 uni.navigateTo(OBJECT)  :保留当前页面,跳转到应用内的某个页面
新页面会入栈,可以通过navigateBack返回
页面栈最多十层,超出会报错
保留当前页面状态

适用:详情页面跳转、表单页面跳转、需要返回的页面跳转

uni.redirectTo(OBJECT):关闭当前页面,跳转到应用内的某个页面

适用: 登录成功后跳转、完成某个流程后跳转、不需要返回的场景

uni.reLaunch(OBJECT):关闭所有页面,打开到应用内的某个页面

适用: 回到首页、切换用户身份后刷新应用、需要重置应用状态的场景

uni.switchTab(OBJECT):跳转到 tabBar 页面,并关闭其他所有非 tabBar 页面
适用场景:底部标签页切换、从非tabBar页面跳转到tabBar页面

uni.navigateBack(OBJECT):关闭当前页面,返回上一页面或多级页面

路由传参 不一一列举详细请看文档

// 发送参数
uni.navigateTo({
  url: 'pages/detail/detail?id=1&type=news&title=标题'
});

// 接收参数
export default {
  onLoad(options) {
    console.log(options.id); // 1
    console.log(options.type); // news
    console.log(options.title); // 标题
  }
}


生命周期 


onLoad  路由传参在接收 、初始化数据
onshow 一般用于更新页面数据等 开始动画
onHide 隐藏 结束动画 清除定时器 延时器
onUnload 页面被销毁,内存被回收
性能优化方面 
        使用onLoad缓存不常变化的数据
        在onHide中暂停不必要的操作
        使用onShow进行按需刷新而非全量刷新

3、数据请求篇

import {
  // toast,
  getStorageSync
  // toLoginPage
} from './utils.js';

import { HTTP_REQUEST_URL, TOKENNAME } from './config.js';

const baseRequest = async (
  url,
  method,
  data,
  header,
  enableChunked = false,
  loading = false,
  needToken = true
) => {
  let token = await uni.getStorageSync('TOKEN');

  // console.log("请求参数", url, method, data, header, token)
  let headerBase = header
    ? header
    : {
        'Content-Type': 'application/json'
      };

  if (token && needToken && !url.includes('/map-api')) {
    headerBase[TOKENNAME] = token;
  }

  return new Promise((reslove, reject) => {
    loading &&
      uni.showLoading({
        title: 'loading'
      });
    uni.request({
      url: url.includes('/map-api') ? url : HTTP_REQUEST_URL + url,
      method: method || 'GET',
      header: headerBase,
      timeout: 200000,
      data: data || {},
      enableChunked: enableChunked,
      success: (res) => {
        // console.log("res===", res)
        if (res.data.code === 401) {
          uni.showModal({
            title: '提示',
            content: '身份过期请重新登录',
            success: function (res) {
              if (res.confirm) {
                uni.clearStorageSync();

                uni.redirectTo({
                  url: '/pages/login/index'
                });
                reslove(res.data);
              } else if (res.cancel) {
                console.log('用户点击取消');
                reslove(res.data);
                // 用户点击了取消按钮的相关逻辑可以放在这里
              }
            }
          });
        } else {
          reslove(res.data);
        }
      },
      fail: (msg) => {
        reject(msg);
      },
      complete: () => {
        loading && uni.hideLoading();
      }
    });
  });
};

const request = {};

['options', 'get', 'post', 'put', 'head', 'delete', 'trace', 'connect'].forEach((method) => {
  request[method] = (api, data, header, enableChunked, loading, needToken) =>
    baseRequest(api, method, data, header, enableChunked, loading, needToken);
});

export default request;

这份数据请求能应对绝大多数场景

小程序中
使用uni.request()替代传统的fetch或axios
请求域名必须在小程序管理后台配置白名单
默认不支持跨域请求,所有请求都需要HTTPS
不大支持复杂的类型请求 比如formData 等要做适配 后面我会贴代码上来

其他都比较快乐

好的,请提供当前页面的内容和排版样式,我会帮您进行优化。


4、其他


要注意权限处理 比如
用户授权

位置、相机、相册等需要用户授权
使用uni.authorize()或相关API获取权限
需要处理用户拒绝授权的情况

我这里举例一下位置授权配置  

1、位置权限

manifest.json 中 

"h5": {
    "template": "index.html",
    "router": {
      "mode": "hash",
      "base": "/h5/"
    },
    "publicPath": "/h5/",
    "sdkConfigs": {
      "maps": {
        "tencent": {
          "key": "J7DBZ-QQCKX-R2L4Z-T5YVE-QMS4J-NLBVP"
        },
        "qqmap": {
          "key": "J7DBZ-QQCKX-R2L4Z-T5YVE-QMS4J-NLBVP"
        },
        "geolocation": {
          "type": "tencent",
          "coordinate": "gcj02"
        }
      }
    },
    "domain": "https://anneng.xaxcsz.com",
    "devServer": {
      "https": false,
      "port": 8080,
      "disableHostCheck": true
    }
  },

页面中

const getPosition = () => {
  return new Promise((resolve, reject) => {
    uni.getLocation({
      type: 'gcj02', // 使用国测局坐标系(火星坐标系)
      success: async (res) => {
        try {
          // 获取位置成功
          const locationInfo = {
            latitude: res.latitude,
            longitude: res.longitude,
            accuracy: res.accuracy || 1000
          };

          resolve(locationInfo);
        } catch (error) {
          reject(new Error(`处理位置信息失败: ${error.message || '未知错误'}`));
        }
      },
      fail: (err) => {
        uni.showToast({
          title: '获取位置失败',
          icon: 'none',
          duration: 2000
        });
        reject(new Error(`获取位置失败: ${err.errMsg || '未知错误'}`));
      }
    });
  });
};

// 修改权限检查和位置获取逻辑
const getPersonalLocation = async () => {
  // 直接尝试获取位置,不使用 uni.authorize
  const position = await getPosition();
  console.log('position1', position);
  personalLocation.value = {
    ...position,
    latitude: position.latitude,
    longitude: position.longitude,
    address: position.address || position.province + position.city + (position.district || '')
  };
  position.value = personalLocation.value.address;
....
};

当然有更多的东西 后面会在文档中补充

登录等 比如手机号 微信授权啥的请看文档


三、语法限制

1. 小程序特有语法

小程序开发中存在一些语法限制和特殊规则:

  • 数据绑定:使用{{}}进行数据绑定,而不是Vue中的v-text
  • 条件渲染:使用v-if、v-else-if、v-else,与Vue类似
  • 列表渲染:使用v-for="(item, index) in items",需要指定:key
  • 事件处理:使用@tap代替@click,在移动端更符合触摸操作

2. 样式限制

  • 选择器限制:不支持通配符*和属性选择器
  • 单位使用:推荐使用rpx作为尺寸单位,可自适应不同屏幕
  • 样式隔离:每个组件样式默认隔离,需使用特定方式实现全局样式
  • 不支持部分CSS特性:如:hover伪类在某些平台可能不生效

3. JS API限制

  • DOM操作限制:不能直接操作DOM,需使用小程序提供的API
  • 网络请求限制:只能请求已配置的安全域名
  • 异步API:大多数API都是异步的,需要使用回调或Promise处理


四、小程序与其他区别

1. 与Web开发的区别

  • 运行环境不同:小程序运行在特定容器中,非标准浏览器环境
  • 页面结构不同:使用.vue单文件组件,包含模板、脚本和样式
  • 生命周期不同:有特定的应用和页面生命周期函数
  • API差异:使用平台提供的API,而非Web标准API

2. 与原生App的区别

  • 性能差异:性能介于Web和原生App之间
  • 开发效率:开发效率高于原生App,一套代码多端运行
  • 功能限制:部分硬件功能和系统API访问受限
  • 发布流程:需要通过平台审核,更新周期较长

3. 与H5的区别

  • 离线能力:小程序可以离线使用部分功能
  • 系统能力:可以调用更多设备和系统能力
  • 用户体验:交互更接近原生应用,体验更流畅
  • 分发方式:通过应用商店或扫码方式获取,而非浏览器访问


五、打包

h5


更具配置项npm run build:h5 就好了(推荐)没有什么流程 简单方便
或者直接在 hbuilder 点击发行  pc或者h5 即可 其他的按照流程来 

微信小程序

这个相对简单,申请好appId 准备好域名 接口白名单 之类的东西  写好代码 
在微信开发者工具中有发行和版本管理

app(目前我只试过安卓apk)

首先生成证书
安装JRE环境 Java Downloads | Oracle  选择对应操作系统


选择自己要的版本 然后注册或者直接登录

配置环境变量

d:  
set PATH=%PATH%;"C:\Program Files\Java\jre1.8.0_201\bin"

 生成签名证书

keytool -genkey -alias testalias -keyalg RSA -keysize 2048 -validity 36500 -keystore test.keystore
Enter keystore password:  //输入证书文件密码,输入完成回车  
Re-enter new password:   //再次输入证书文件密码,输入完成回车  
What is your first and last name?  
  [Unknown]:  //输入名字和姓氏,输入完成回车  
What is the name of your organizational unit?  
  [Unknown]:  //输入组织单位名称,输入完成回车  
What is the name of your organization?  
  [Unknown]:  //输入组织名称,输入完成回车  
What is the name of your City or Locality?  
  [Unknown]:  //输入城市或区域名称,输入完成回车  
What is the name of your State or Province?  
  [Unknown]:  //输入省/市/自治区名称,输入完成回车  
What is the two-letter country code for this unit?  
  [Unknown]:  //输入国家/地区代号(两个字母),中国为CN,输入完成回车  
Is CN=XX, OU=XX, O=XX, L=XX, ST=XX, C=XX correct?  
  [no]:  //确认上面输入的内容是否正确,输入y,回车  

Enter key password for <testalias>  
        (RETURN if same as keystore password):  //确认证书密码与证书文件密码一样(HBuilder|HBuilderX要求这两个密码一致),直接回车就可以

查看证书信息 

keytool -list -v -keystore test.keystore  
Enter keystore password: //输入密码,回车

 详情请参考 Android平台签名证书(.keystore)生成指南 - DCloud问答

第二步  点击发行 选择云打包 然后 填入证书信息 就ok了 
Android 自定义渠道包 Android 自定义渠道包 | uni-app官网

我也在慢慢学习中 后续更新.... 


六、补充篇原生微信小程序
 

原生微信小程序由四种文件组成:

  • .js:脚本文件
  • .wxml:模板文件(类似HTML)
  • .wxss:样式文件(类似CSS)
  • .json:配置文件

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值