# 一、跨平台开发

# 1、uni-app 架构图

官方文档:

uni-app 官方文档 (opens new window)

uni-app 描述:

  uni-app 适合于系统交互少、页面不太复杂、没有高性能和复杂用户体验需求的跨平台框架。

缺点:同时开发多端兼容和适配笔记麻烦、调试不方便

# 2、HBuilderX 工具

① 个人 HBuilderX 主题配置

// Settings.json
{
  "editor.colorScheme": "Atom One Dark",
  "editor.fontFamily": "Consolas",
  "editor.fontFmyCHS": "微软雅黑",
  "editor.fontSize": 16,
  "editor.minimap.maxPixelWidth": 100,
  "files.associations.contextmenu": true,
  "software.update.settings": "default",
  "editor.tabSize": 2
}

② 将 uni-app 运行在浏览器中(H5)

③ 将 uni-app 运行在微信开发者工具中(小程序)

微信开发者工具:

设置 ---> 安全设置 ---> 开启服务端口

④ 将 uni-app 运行在 mumu 模拟器中(安卓)

uni-app

运行 ---> 运行到手机或模拟器 ---> 安装 App 真机运行插件

工具 ---> 运行配置 ---> Android 模拟器端口(设置为 7555)

模拟器连接

  • 配置 adb 环境变量
# HBuilderX正式版的adb目录位置:安装目录下的 tools/adbs 目录

# HBuilderX Alpha版的adb目录位置:安装目录下的 plugins/launcher/tools/adbs目录
  • 建立连接
adb devices
adb connect 127.0.0.1:7555
adb devices

⑤ 其他

uni-app 还可以运行在 真机、模拟器、Android Studio 等

# 3、条件编译

  在 uniapp 可以对 API、组件、样式等之内进行条件编译 (opens new window)

<template>
  <view>
    <!-- #ifdef APP-PLUS -->
    <image src="../../static/img1.png" mode="widthFix"></image>
    <!-- #endif -->
    <!-- #ifdef MP-WEIXIN -->
    <image src="../../static/img2.png" mode="widthFix"></image>
    <!-- #endif -->
  </view>
</template>

<script></script>

# 二、uni-app 简介

  uni-app 是一个使用 vue.js 开发所有前端应用的框架,开发者编写一套代码,可发布到 iOS、Android、Web(响应式)、以及各种小程序(微信/支付宝/百度/头条/飞书/QQ/快手/钉钉/淘宝)、快应用等多个平台。

# 1、项目结构

小程序项目结构:

applets_project
├─ pages
│  └─ index(page文件夹)
│     ├─ index.js 👀(页面入口文件)
│     ├─ index.json(对应app.json中的🤔window配置项)
│     ├─ index.wxml
│     └─ index.wxss
├─ .eslintrc.js *
├─ app.js 🚩(项目入口文件)
├─ app.json(🍗page路径、window配置、组件样式)
├─ app.wxss
├─ project.config.json
├─ project.private.config.json
└─ sitemap.json *

uni-app 项目结构:

  新建 uni-app 项目时,默认生成的项目结构为:

uni-app_project
├─ pages
│  └─ index(page文件夹)
│     └─ index.vue
├─ static
│  └─ logo.png
├─ App.vue
├─ index.html
├─ main.js 🚩(项目入口文件)
├─ manifest.json
├─ pages.json
└─ uni.scss

# 2、全局文件

  在 uniapp 中,pages 页面由 4 个文件变成了 1 个.vue 文件。其中的.json 文件补充到了根目录的 pages.json 中统一管理。

{
  "pages": [
    {
      "path": "pages/component/index",
      "style": {
        "navigationBarTitleText": "组件" // 这部分相当于原小程序中的 页面配置文件xxx.json
      }
    }
  ],

  "tabBar": {
    "selectedColor": "#3cc51f",
    // ……
    "list": [
      {
        "pagePath": "pages/component/index",
        "iconPath": "static/image/icon_component.png",
        "selectedIconPath": "static/image/icon_component_HL.png",
        "text": "组件"
      }
    ]
  },

  "globalStyle": {
    "navigationBarTextStyle": "black", // 类似于原微信小程序中的 window
    "navigationBarTitleText": "演示",
    "navigationBarBackgroundColor": "#F8F8F8"
  }
}

  关于其他全局文件可以参考:全局文件 (opens new window)

# 3、结构图示


# 三、开发规范

定位

  vue 的语法、微信小程序的 api

# 1、靠近 vue

  从开发体验角度来讲:uni-app 的就是 vue 和微信小程序的结合体,除此之外还做了多端兼容。

① uniapp 的页面文件遵循 Vue 单文件组件 (SFC) 规范

  • index.vue
<template> </template>

<script>
  export default {
    // methods: {}
  }
</script>

<style lang="scss"></style>

② data 属性必须声明为返回一个初始数据对象的函数

底层自动 diff 差量更新数据,比手动 setData 性能更高。所以在 Uni-App 中,应该使用 this.$set 方法或 Vue.js 的响应式数据来更新数据和视图。

<script>
  export default {
    //正确用法,使用函数返回对象
    data() {
      return {
        title: 'Hello'
      }
    },

    //错误写法,会导致再次打开页面时,显示上次数据
    data: {
      title: 'Hello'
    }
  }
</script>

③ 在微信小程序端,uni-app 将数据绑定功能委托给 Vue,开发者需按 Vue 2.0 的写法实现数据绑定,不支持微信小程序的数据绑定写法,

//正确用法
<view v-bind:id="'item-' + id "></view>

//错误写法,会导致再次打开页面时,显示上次数据
<view id="item-{{id}}"></view>

# 2、靠近小程序

  从开发体验角度来讲:uni-app 的就是 vue 和微信小程序的结合体,除此之外还做了多端兼容。

① uniapp 的组件标签靠近小程序规范。

uni-app 组件规范 (opens new window)

<template>
  <view class="content">
    <image class="logo" src="/static/logo.png"></image>

    <view class="text-area">
      <text class="title">Lencamo</text>
    </view>

    <button size="mini" type="primary" @click="changetextvalue() :disabled="buttondisble" hover-start-time="20">{{buttonText}}</button>

    <button ">修改为789</button>
  </view>
</template>

② uni-app 补充了应用生命周期 (opens new window)页面 / 组件的生命周期 (opens new window)

提示

在小程序中,还有组件所在页面的生命周期。但在 uniapp 中,若想要在组件中使用页面生命周期函数,要要格外注意看看 uniapp 支不支持

  • App.vue
<script>
  export default {
    globalData: {
      text: 'text'
    },

    onLaunch: function () {
      console.log('App Launch')
    },
    onShow: function () {
      console.log('App Show')
    },
    onHide: function () {
      console.log('App Hide')
    }
  }
</script>

③ 接口能力(JS API)靠近小程序规范,但需将前缀 wx、my 等替换为 uni

uni-app 接口规范 (opens new window)

async function request() {
  var [err, res] = await uni.request({
    url: 'https://www.example.com/request'
  })
  console.log(res.data)
}

# 四、差异比较

  差异最大的当然是项目结构,不过在《配置文件》部分会详细介绍。

  下面介绍的都是一些细微的差异。

提示

  想要接触更多的差异,最好的方式就是在项目中实践。

# 1、简化教程

  在学习 uniapp 之前,可以先看看下面两个文档,他能让你快速感知 uniapp 是如何在 vue、小程序中游刃有余的了。

vue 和 小程序 使用:

vue2 语法 (opens new window)

小程序专题 (opens new window)

# 2、组件引入差异

  传统 vue2 项目开发,引用组件需要导入 - 注册 - 使用三个步骤。

  而 uni-app 的 easycom 机制,将组件引用进一步优化,开发者只管使用,无需考虑导入和注册,更为高效

提示

要使 easycom 机制生效,组件需要符合如下的目录结构:

components / 组件名称 / 组件名称.vue

<template>
  <view>
    <!-- 直接使用组件 -->
    <my-component><my-component>
  </view>
</template>

<script>
// ……
</script>

  在 uni-app 项目中,页面引用组件和组件引用组件的方式都是一样的(可以理解为:页面是一种特殊的组件),均支持通过 easycom 方式直接引用。

# 3、组件使用差异

① 传递静态或动态 Prop

传入一个对象的所有 property (微信小程序暂不支持该用法,即: <blog-post v-bind="post"> 是错误的)

代码示例
<template>
  <view>
    <!-- 正确 -->
    <blog-post v-bind:id="post.id" v-bind:title="post.title"></blog-post>

    <!-- 错误 -->
    <blog-post v-bind="post"></blog-post>
  </view>
</template>

<script>
  export default {
    data() {
      return {
        post: {
          id: 1,
          title: 'My Journey with Vue'
        }
      }
    }
  }
</script>

② 插槽

小程序不支持作用域插槽(HBuilderX 3.1.19 以下仅支持解构插槽且不可使用作用域外数据以及使用复杂的表达式)

③ 动态组件

小程序不支持动态组件

# 4、vue 语法差异

  uni-app 在发布到 H5 时支持所有 vue 的语法;发布到 App 和小程序时,由于平台限制,无法实现全部 vue 语法,但 uni-app 仍是对 vue 语法支持度最高的跨端框架。

① Class 与 Style 绑定

小程序端不支持 classObject 和 styleObject 语法

代码示例
<template>
  <view>
    <!-- 错误示例 -->
    <view :class="activeClass">hello uni-app</view>
    <view :style="styleObject">hello uni-app</view>
  </view>
</template>
<script>
  export default {
    data() {
      return {
        activeClass: {
          active: true,
          'text-danger': false
        },
        styleObject: {
          color: 'red',
          fontSize: '20px'
        }
      }
    }
  }
</script>

② 事件处理器

为兼容各端,事件需使用 @ 的方式绑定,请勿使用小程序端的 bind 和 catch 进行事件绑定;也不能在 JS 中使用 event.preventDefault()和 event.stopPropagation()方法;

代码示例
<template>
  <view>
    <view class="mask" @touchmove.stop.prevent="moveHandle"></view>

    <view class="mask" @tap="openInfoFn"></view>
  </view>
</template>

③ v-for

在非 H5 平台 循环对象时不支持第三个参数,如 v-for="(value, name, index) in object" 中,index 参数是不支持的

④ 其他

其他

① v-once

h5、微信小程序均不支持

② v-html

App 端和 H5 端支持 v-html ,微信小程序会被转为 rich-text,其他端不支持 v-html

# 5、其他

小程序不支持在 css 中使用本地文件,包括本地的背景图和字体文件。需以 base64 方式方可使用。

在背景图片小于 40kb 时,uni-app 编译到不支持本地背景图的平台时,会自动将其转化为 base64 格式(前提是图片在 static 的根目录下)

.test2 {
  background-image: url('~@/static/logo.png');
}

# 五、uniapp 学习

不得不说,uni-app 官方文档是我学习到现阶段最完美的学习文档 😊。

uni-app 官方文档写的非常详细,实际开发时,建议参考官方文档。

# 1、内置组件

  这部分内容中,小程序组件基本都涵盖了。

组件 ---> 内置组件 (opens new window)

# 2、uni-ui 组件库

uni-ui 是 DCloud 提供的一个跨端 ui 库,它是基于 vue 组件的、flex 布局的、无 dom 的跨全端 ui 框架

uni-ui 不包括基础组件,它是基础组件的补充。

① uni.scss 文件:

uni-ui 的主题定制 (opens new window)在项目的根目录文件 uni.scss (opens new window) 中修改即可

② uni_modules 文件夹

安装好的 uni-ui 组件(就要一个一个使用 vue3 写的封装组件(没事可以看看它是怎么实现的 😂))

# 3、页面通信

  • url 查询字符串
代码示例
<navigator url="/pages/info/info?name=lencamo&age=20">导航到消息页面</navigator>
  • 接收参数
<script>
  export default {
    onLoad: function (options) {
      // 打印页面跳转时携带的参数
      console.log(options.name)
    }
  }
</script>
  • EventChannel
代码示例

参考 1:前面的小程序基础 --> 路由跳转部分

参考 2:uni-app 官网 API --> 页面和路由 (opens new window)

  • 事件总线

提示

  因为小程序和 vue 是存在差异的,所以还是建议使用小程序的 EventChannel   

代码示例

 vue 的事件总线,只适合返回传参

因为$emit触发成功的前提是$on已经开启监听(页面已经打开)

<script>
  export default {
    onLoad() {
      uni.$on('acceptDataFromOpenerPage', this.backEvent)
    },
    onUnload() {
      uni.$off('acceptDataFromOpenerPage', this.backEvent)
    },
    methods: {
      backEvent(data) {
        console.log('回调传来的数据:', data)
      }
    }
  }
</script>
<script>
  export default {
    methods: {
      navBackFn() {
        // 返回导航
        uni.navigateBack()

        // 触发全局事件
        uni.$emit('acceptDataFromOpenerPage', {
          data: { xxxx }
        })
      }
    }
  }
</script>
  • 全局数据 globalData
代码示例
  • App.vue
<script>
  export default {
    globalData: {
      text: 'text'
    }
  }
</script>
  • 使用
<script>
  export default {
    onLoad() {
      const app = getApp()

      console.log(app.globalData.text)
    }
  }
</script>
  • 本地存储 Storage
代码示例

  • 状态管理库 Vuex、Pinia
代码示例

更新于 : 8/7/2024, 2:16:31 PM