Ionic/Vue3 北京政务App 问题记录(1)

目录

1. 初始化项目,上传 GitLab

2. Android App 打包流程

3. App 在真机上无法访问网络的问题

4. 替换 App 应用名 / 包名 / 唯一标识 scheme

5. 一些 Ionic 样式修改注意事项 / 返回按钮

6. 无数据组件 no-data.vue / !! 作用

7. async/await VS promise.all()【select and list】

8. await 最好返回 promise 防止意外错误发生

9. ion-select 使用过程中遇到的问题

10. Vue3 获取路由信息及路由传参

11. 在 ionic 中使用 Vuex【以登录为栗子】

12. 通用 vue 模板 / 其他细节模块 / 路由模块化

13. 移动端原型工程中的 http 相关配置

14. 获取事项列表的思路及遇到的问题


1. 初始化项目,上传 GitLab

  • 拿到一个项目之后,先请项目经理开通 GitLab 项目权限,并新建一个仓库
  • Ionic/Vue3 北京政务App 问题记录(1)
  • 接着下载 移动端原型工程,根据 GitLab 提示,将前述文件上传 GitLab 

2. Android App 打包流程

  • Vue3/Ionic 打包需要依靠 Android Studio + 命令行工具,环境配置类似于 Angular/Ionic

  • 在项目根目录下,任意命令行工具中,执行如下操作:
  • 添加平台: ionic capacitor add android 【结束后命令行换行】
  • 构建 原生app 资源:ionic capacitor build android 【结束后命令行换行,且自动打开 Android Studio 执行下述操作(构建app)】
  • 构建完 原生app 资源之后,自动通过 Android Studio 构建 app 【可以观察面板右下角,会显示构建进度,初次构建app会比较慢】 
  • 点击 Android Studio 导航栏中的 Build → Build Bundles/APKs → Build APKs 【通过下方导航条的 build 可以查看打包进度】

Ionic/Vue3 北京政务App 问题记录(1)

Ionic/Vue3 北京政务App 问题记录(1)


  • 后续在 vscode 中编写app,需要将 vscode 中的 静态资源/插件 更新到 Android Studio 中,执行下面两条命令的任意一条
  • ionic capacitor update android
  • ionic capacitor sync
  • 我的电脑上执行第一条不太行,执行第二条可以成功同步
  • 同步完成之后,再次执行 Build APKs 即可获得新的 .apk 文件
  • Ionic/Vue3 北京政务App 问题记录(1)

3. App 在真机上无法访问网络的问题

  • 在 res/xml 下,创建 network_security_config.xml 文件,并添加如下内容:

Ionic/Vue3 北京政务App 问题记录(1)

<?xml version="1.0" encoding="utf-8"?>
<network-security-config>
    <base-config cleartextTrafficPermitted="true" />
</network-security-config>
  • 接着,在 AndroidManifest.xml 文件下的 application 标签中,增加以下属性:

Ionic/Vue3 北京政务App 问题记录(1)

<application
  ...
  android:networkSecurityConfig="@xml/network_security_config"
  ...
/>

4. 替换 App 应用名 / 包名 / 唯一标识 scheme

  • AndroidManifest.xml 是 app入口文件
  • 从下图的位置可以点进配置 App 应用名 / 包名 / 唯一标识 scheme 的文件 【必须是在 Android Studio 中才能点进去】

Ionic/Vue3 北京政务App 问题记录(1)

  •  点开之后长这样子:

Ionic/Vue3 北京政务App 问题记录(1)

  • 说一下唯一标识的作用:比如我从 a应用 跳转到 b应用,就需要 b应用的唯一标识,命名规则目前还没有总结出来,需要后续项目完善

5. 一些 Ionic 样式修改注意事项 / 返回按钮

  • 返回按钮:
  • <ion-buttons slot="start">
      <ion-back-button text=""></ion-back-button>
    </ion-buttons>

  • 列表项底边要求:
  • 让 最后的列表项 没有边:<ion-item lines="none"></ion-item>
  • 让 除了最后一个之外的列表项 有边:<ion-item lines="full"></ion-item>
  • 切换列表项状态:<ion-item :lines="index + 1 === listData.length ? 'none' : 'full'"></ion-item>
  • 注意:动态绑定 lines 之后,他的值必须加单引号 ' '

  • ionic 在 <style lang="scss" scoped> 中,可以直接修改标签样式
  • ion-label {
      display: flex !important;
      height: 40px;
    }
  • 需要区分 element-plus,在带 scoped 标签下修改它时,是通过 类名(不是标签名)修改样式,且需要添加 :deep()

  • 在 vue3 中使用 ionic 时,页面中用到的 ionic 组件,都需要引入,举个栗子:
  • import { IonList, IonItem, IonLabel, IonThumbnail } from '@ionic/vue'
    components: { IonList, IonItem, IonLabel, IonThumbnail },

  • 如果不声明组件,也可以正常使用 ionic 组件,但网页会把他们当成 web component,而不是 Vue组件,也就是说,不能使用类似于 v-model 的 Vue 语法,举个栗子:
  • ion-select 组件,绑定的值是通过 :value="xx" 这么写的,但是这么写不是响应式的
  • 在 vue 里通过 v-model 进行双向绑定实现响应式,而 ion-input 上不能直接使用 v-model 替代 :value,因为他是 web component
  • 如果想在 ion-input 上使用 v-model 的话,需要将 ion-input 进行引入并声明
  • Ionic/Vue3 北京政务App 问题记录(1)

  • 在 variables.css 中有常见的主题色变量,可以把 自定义颜色 放在该文件的 :root { } 里
  • Ionic/Vue3 北京政务App 问题记录(1)
  • 在 ionic 中,使用 主题色变量/全局变量:
  • ion-content {
      --background: var(--bg-color-black);
    }

  • 全局样式文件,可以在 assets/style/ 中创建文件,并在 main.ts 中进行引入
  • ionic 的全局样式,就可以在上述文件中修改

6. 无数据组件 no-data.vue / !! 作用

  • no-data.vue
 <slot v-if="!haveData">
   <p class="no-data">暂无数据</p>
 </slot>
 <slot v-else name="haveData">需要展示的列表数据</slot>
  • 使用列表及无数据组件
      <no-data :haveData="haveData">
        <template #haveData>
          <list-show :listData="listData"></list-show>
        </template>
      </no-data>

// 导入 列表组件 及 列表组件内部导出的数据类型接口
import ListShow, { ListData } from '@/components/list-show.vue'
  • 根据是否有列表数据,决定 haveData 的值
  • state.haveData = !!state.listData.length;
  • 注意:!! 可以把任意类型的判断,最终转换为布尔值

7. async/await VS promise.all()【select and list】

  • promise.all() 获得的 成功结果数组里的 数据顺序,和 promise.all() 接收 异步方法数组的 顺序是一致的,举个栗子:
  • 假设执行 promise.all([p1, p2]),即便 p1 结果 获取的比 p2结果晚,最终 p1结果在前
  • 作用:没有逻辑关系的异步方法,在 onMounted 中同时调用
  • 注意:promise.all() 让方法同时执行,而不是先后执行

  • async/await 可以控制方法执行的顺序,不是同步执行异步方法
  • 假设现在有一个页面:里面包含了需要接口请求的下拉框及列表,列表的内容是根据下拉框的内容决定的,此时就应该考虑 async/await 决定异步请求顺序
  • 也就是说,必须 await 下拉框请求,且拿到结果之后,才能执行列表获取请求
  • 此时不能使用 promise.all(),因为此方法只能保证结果获取的顺序,而不能保证方法执行的顺序,也就是说,会同时执行 下拉框获取 / 列表获取 两个方法,而不是先执行下拉框获取并且拿到结果,再执行列表获取方法

8. await 最好返回 promise 防止意外错误发生

  • await 后面必须跟一个 promise,即使该 promise 返回空值;返回空值的情况下,也必须 resolve(), 否则,await getSelectOptions() 之后的代码都将无法执行
  • 错误场景回顾:当时我写 await getSelectOptions() ,后面执行 getListData(),getListData() 方法内部使用了 state.selectValue,getSelectOptions() 没写 resolve(),这直接导致加载错误的 bug

  • 解决方法:
    const getSelectOptions = (): Promise<void> => {
      return new Promise((resolve, reject) => {
        setTimeout(() => {
          state.eventTypeOptions.push({
            label: '行政许可',
            value: '行政许可',
          });
          state.eventTypeModel = state.eventTypeOptions[0].value;
          resolve();
        }, 2000);
      })
    };
  • 一般情况下,获取下拉列表,都应返回首个选中的值,否则方法耦合度会高

9. ion-select 使用过程中遇到的问题

  • ion-select 自带属性 和 自定义配置项 会同时生效
  • 自带属性:cancelText="取消" 
  • 自定义配置项: :interface-options="customActionSheetOptions"
  •     const customActionSheetOptions = {
          cssClass: 'my-custom-interface', // 自定义类名
          header: '事件类型', // 下拉框标题
          translucent: true, // 让选中项高亮
        };
<ion-select
  v-model="eventTypeModel"
  @ionChange="handleSecOrInpChange($event)"
  cancelText="取消"
  :interface-options="customActionSheetOptions"
  interface="action-sheet"
>
    <ion-select-option
        v-for="(item, index) of eventTypeOptions"
        :value="item.value"
        :key="index">
              {{ item.label }}
    </ion-select-option>
</ion-select>

  • 关于双向绑定:
  • 官方给的示例是 :value="eventTypeModel" 绑定下拉框当前绑定的值
  • 如果想使用 vue 实现 --- 双向绑定 --- 的话,可替换为 v-model="eventTypeModel"
  • 引入和声明 ionic 组件之后,才能让浏览器把它们当成 vue 组件,识别 vue 语法哦

  • 关于下拉框列表获取方式【枚举 vs 接口获取】:
  • 应该通过接口获取下拉框列表
  • 假设本地使用了枚举,如果需求变更,就需要修改枚举,重新打包发布 app,并让用户安装以获取更新,用户体验感会降低,因此必须使用接口获取下拉列表

  • 使用枚举示例:
  • // 事项类型枚举
    export enum eventType {
      XZXK = '行政许可',
      XZQR = '行政确认',
    }
  • // 下拉框双向绑定的值
    eventTypeModel: eventType.XZXK,
          // 下拉框列表
          eventTypeOptions: [{
            value: eventType.XZQR,
            label: eventType.XZQR,
          }],

  • 当下拉框列表发生变化时,可在 html 中传入 $event,监听变化
  • $event.detail 可以查看当前绑定的 value
  •     const handleSecOrInpChange = (ev: any) => {
          console.log(ev.detail)
        };

10. Vue3 获取路由信息及路由传参

  • 路由跳转并传参【动词,router】:
  • import { useRouter } from 'vue-router';
    const router = useRouter();

          router.push({
            path: 'projectListPage',
            query: {
              eventName: item.eventName,
            },
          });


  • 路由参数获取【名词,route】:

  • import { useRoute } from 'vue-router'
    const route = useRoute();
    eventName: route.query.eventName,


11. 在 ionic 中使用 Vuex【以登录为栗子】

  • 关于安装版本的问题:
  • 最开始是直接去 vuex 官网安装,但是官网的版本是 3.x.x,本项目使用的是 ionic/vue3,因此要使用 4.0.0 以上的 vuex
  • 综上所述,安装正确版本的方法 —— 修改 package.json:"vuex": "^4.0.2",然后 yarn

  • 在页面中使用 vuex:
  • src/main.ts:
  • import store from './store/index';
    const app = createApp(App)
      .use(store);


  • src/store/index.ts:

 import { createStore } from 'vuex';
  // 全局变量
  const state = {
    // 用户信息
    userInfo: {
      userId: '',
      userName: '',
      phone: '',
    }
  }

  // mutations
  const mutations = {
    // 更新用户信息
    UPDATAUSERID(states: any, userinfo: object){
      states.userInfo = userinfo;
    }
  }

  // actions
  const actions = {
    // 更新用户信息(异步)
    upDataUserInfo(context: any, userinfo: object) {
      console.log('当前登录用户信息', userinfo);
      context.commit('UPDATAUSERID', userinfo);
    }
  }
  
 export default createStore({
  actions,
  mutations,
  state,
})

  • src/views/login/login.vue:
  • import { useStore } from 'vuex';
  • const store = useStore();
  • const upDataUserInfo = (userInfo: any) => store.dispatch('upDataUserInfo', userInfo); // 异步更新用户信息
  •       upDataUserInfo({
            userId: '2333',
            userName: state.loginInfo.loginName,
            phone: '110',
          });

12. 通用 vue 模板 / 其他细节模块 / 路由模块化

  • vue 通用模板:
<template>
  <ion-page>
    <ion-header>
      <ion-toolbar color="primary">
        <ion-title>搜索</ion-title>
      </ion-toolbar>
    </ion-header>
    <ion-content> 搜索 </ion-content>
  </ion-page>
</template>

<script lang="ts">
import {
  IonPage,
  IonHeader,
  IonToolbar,
  IonTitle,
  IonContent,
} from '@ionic/vue';
import { defineComponent } from 'vue';
import { useRouter } from 'vue-router';

export default defineComponent({
  name: 'Login',
  components: {
    IonHeader,
    IonToolbar,
    IonTitle,
    IonContent,
    IonPage,
  },
  setup(props, context) {
    const router = useRouter();

    return {
    }
  }
});

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

</style>

  • tab 模块:

Ionic/Vue3 北京政务App 问题记录(1)


  • types 文件夹,定义项目中需要的 typescript 类型
  • 还可以加 enums 文件夹,定义项目中需要的 枚举enum 类型

Ionic/Vue3 北京政务App 问题记录(1)


  • 路由根据 tab 可以分成多个模块,写在不同的 .ts 中,主路由模块中会加方法,将 router 文件夹下的所有路由 .ts 文件,添加到主路由模块中
  • 如果带了 子路由,展示地址: localhost:8080/tabs/home
  • 如果不带 子路由,展示地址: localhost:8080/project-list-page

Ionic/Vue3 北京政务App 问题记录(1)


  • 一个技巧:将路由路径存储到单独的 .ts 文件里,需要路由跳转时,通过变量代替直接写地址,这样可以避免后期修改路径名,需要全局挨个修改的麻烦
  • Ionic/Vue3 北京政务App 问题记录(1)
// 路由变量
import { RouteApp } from '@/enums/route-config';
      router.push({
        path: RouteApp.ProjectList,
        query: { ... },
      });

13. 移动端原型工程中的 http 相关配置

  • 首先需要修改 public/config.js 文件夹中的全局地址
  • Ionic/Vue3 北京政务App 问题记录(1)

  • 区分三种接口类型:
  1. 模拟接口,即通过 Rap2 或其他接口平台构建的模拟接口,在提供接口文档之后,前端负责编写
  2. 接口平台地址,即通过 token/interface/run.action 等访问接口数据,后端编写,在 Network 中,通过 run 过滤此类请求
  3. 自定义接口地址,即通过 getData.vm 这种访问接口数据

  • 在 utils 文件夹中,包含 接口路径拼接 / axios设置 / 封装http请求 / 配置 token 等内容
  • 在 service 文件夹中,配置 具体业务的 http请求

Ionic/Vue3 北京政务App 问题记录(1)

  • 以上图 事件列表 为例:
  1. 模拟接口复制 Rap2模拟接口平台中 写的地址即可
  2. 后端接口平台复制 interfaceID 字段即可
  3. 自定义开发接口复制 getData.vm 这种带.vm 的字段即可
  4. 在 useApi 中,控制当前使用哪种接口 

  • 注意:后端接口平台接口,需要配置 token,get/post 请求都需要

Ionic/Vue3 北京政务App 问题记录(1)


  • 可以直接在 service 下的模块中,直接定义 接口所需参数类型 / 接口回复数据类型,也可以把这两个定义在 types 下的模块中

Ionic/Vue3 北京政务App 问题记录(1)

  •  接口请求模板定义举例:

Ionic/Vue3 北京政务App 问题记录(1)

  • 上述示例说明如下:
  1. 上面使用了 get/post 两种请求,都已经在 utils 里封装了,使用只有方法名的不同,没有别的区别
  2. 方法内部传入了当前使用的接口名,接口所需参数,是否显示加载等待
  3. param 指定接口参数类型,Promise 里接受泛型,传入 接口返回数据类型

14. 获取事项列表的思路及遇到的问题

  • 页面初始化时,执行了 获取下拉列表 / 获取事项列表的方法,为什么会发送 两次 获取事项列表数据?
  • Ionic/Vue3 北京政务App 问题记录(1)
  • 原因:我给 ionselect 绑定了 ionChange 方法,当获取到下拉列表后,下拉列表就已经发生了改变,执行了 ionChange 方法;而我在初始化中,又写了一次获取事项列表的请求,因此发送了两次请求
上一篇:ionic input 标签的使用


下一篇:Ionic在android中返回键的处理问题