编程开源技术交流,分享技术与知识

网站首页 > 开源技术 正文

EZMobile基于Vue的移动WebApp快速轻松的基础轻量级框架

wxchong 2024-10-15 17:00:56 开源技术 9 ℃ 0 评论

Easy Mobile

  • Easy Mobile 用于快速搭建移动端 WebApp 的简易框架。
  • 演示地址: http://ezmobile.demo.fangjc1986.com
  • git地址:https://gitee.com/ericfang/easy-mobile.git
  • 邮件讨论:fangjc1986@qq.com


功能

  • 完善的路由系统,提供常规前进路由功能,同时支持返回钩子、强制刷新、返回跳过等功能;
  • 全局布局组件,提供上中下三层布局结构;
  • 无限滚动组件,提供下拉刷新和下拉加载功能;
  • 页面切换动画效果,类似 APP 的前进后退效果;
  • 所有动画效果均采用 CSS 动画,无论是无限滚动组件还是页面切换动画均丝滑流畅。
  • 可直接封装至 hybird APP 打包,无需再做原生页面跳转等繁琐功能;

  • 路由跳转函数

      <!-- 使用原型链助手函数 -->
      <div @click="$navigate.to('path')"></div>
    
      <!-- webStorm 貌似现在不支持自动提示手动加载 Vue 上的原型连方法,因此特地加入的全局助手函数混入。 -->
      <!-- 使用全局混入助手函数 -->
      <div @click="g_navigate.to('path')"></div>
    • 跳转到某个页面并传入参数
    <!-- params 传参-->
      <div @click="$navigate.to('path', {params: {id:5}})"></div>
      <div @click="$navigate.toParams('path', {id:5})"></div>
    
      <!-- query 传参 -->
      <div @click="$navigate.to('path', {query: {id:5}})"></div>
      <div @click="$navigate.toQuery('path', {id:5})"></div>
    • 返回上一页
    <!-- 正常返回上一页 -->
      <div @click="$navigate.back()"></div>
    
      <!-- 返回并跳过上一页,可添加 p1,p2 等参数 -->
      <div @click="$navigate.backSkip(p1,p2)"></div>
    
      <!-- 返回并执行上一页 methods 中的 hook 函数,可传入 p1,p2 等参数 -->
      <div @click="$navigate.backInvoke('hook', p1,p2)"
    • 返回跳过上一页继承

    事实上,返回跳过上一页,只是执行了 $navigate.backInvoke('BACK_SKIP', ... params )。

    而 PageMixin 混入中有默认的 BACK_SKIP 函数会被触发。

    如果在 PageMixin 混入的页面中 将 PAGE_BACK_SKIP_INHERIT 参数设置为 true, 则会继续继承跳转并执行以上函数,因此所传递的参数将被保留和传递到更上一页,中间也可以有页面覆盖 BACK_SKIP 函数来拦截并自由操作。

    具体使用可参考案例源码;

    • navigate 方法



    路由配置和混入

    • NavigateMixin 组件级导航混入

    组件级混入,可在任意组件中使用,将会自动判断当前组件所在页面是否为前进还是后退,并相应执行需要钩子函数。

    当页面是从其他页面前进而来,则自动执行组件methods中的init()函数。

    相反的,如果当前页是从其他页面返回而来,则自动执行组件 methods 中的 backInit() 函数。

    import {NavigateMixin} from "@/mixin/navigate.mixin";
    
    export default {
        name: 'component',
        mixins: [NavigateMixin],
        data() {
            return {
                // 强制刷新,无论是返回还是打开
                NAV_FORCE_RELOAD: false,
                // 初始化执行延迟时间(尽量和切换动画时间一致,防止动画在执行js时卡顿)
                // 页面切换后多少 ms 后执行 init() 函数
                NAV_INIT_DELAY: 400,
                // 返回钩子函数执行延时
                // 页面切换返回后多少 ms 后执行 backInit() 函数
                NAV_BACK_HOOK_DELAY: 1,
            }
        },
        methods: {
            // 当页面混入添加了 NavigateMixin 后
            // 同时页面是被前进到此(打开页面)
            // 则 init() 函数将会被自动回调
            init() {
                // 初始化页面操作(获取数据、刷新页面等)
            },
            // 与 init 正好相反,返回到此页 执行
            backInit(){
                // 如果是返回到此页的话
            },
        }
    };
    • PageMixin 页面级导航混入

    如果当前组件为路由页面,则使用 PageMixin 混入,此混入包含返回跳过等功能和配置

    import {PageMixin} from "@/mixin/navigate.mixin";
          
      export default {
          name: 'component',
          mixins: [PageMixin],
          data() {
              return {
                  // 自动返回,当页面为返回情况下,自动再次返回到上一页
                  PAGE_AUTO_BACK: false,
                  // 返回跳过继承,上一页如果是返回跳过的话是否本页也继承跳过
                  PAGE_BACK_SKIP_INHERIT: false,
              }
          },
          methods: {
              // 当页面混入添加了 NavigateMixin 后
              // 同时页面是被前进到此(打开页面)
              // 则 init() 函数将会被自动回调
              init() {
                  // 初始化页面操作(获取数据、刷新页面等)
              },
              // 与 init 正好相反,返回到此页 执行
              backInit(){
                  // 如果是返回到此页的话
              },
          }
      };

    请求使用

    • request 方法介绍

    request 方法是由 axios 封装而来,添加了请求拦截和响应拦截。

    文件位置: src/utils/request.util.js ;

    • 请求拦截添加延时反馈,用于调试 mockjs 瞬间返回请求等问题;添加 serialize 识别,在 headers 中添加 serialize : true 则自动将 data 参数做 urlEncode 操作, 默认使用 json 格式做 post 提交;
    • 响应拦截添加标准格式解析,默认接受后端反馈标准格式为 :
     resp = {
          "code": 200,    // 状态码 100:常规错误带message提示;200:正常;
          "message": "",  // 文本信息
          "data": null    // 内容,可以是任意格式
      }   

    拦截器会自动识别 code 状态,当 code === 200 时,将 data 返回,因此使用 request 函数, then 中回调参数是 data, 而不是整个反馈内容。

    如果 code !== 200 则会执行 src/utils/response.error.util.js 中定义的对应 code[code] 函数,不存在则忽略,可自行在以上文件中定义不同的 code 回调函数;

    更多自定义可根据自身需求在对应文件中修改。

    • request 使用方法1

    直接传入 axios 的 option 配置返回 Promise 对象

     import {request} from "@/utils/request.util";
    
       request({
           url : 'api/address',
           method: 'get',
           params: {
               id: 1
           }   
       }).then( resp => {
           // 这里的 resp 返回的是已经经过处理后的 data 内容
           console.log( resp );
       })
    • request 使用方法2

    链式调用 request 函数

    import {request} from "@/utils/request.util";
    
    // 目前仅提供 get 和 post 方法,其他需要可自行添加。
    request("api/address").get({id : 1}).then( resp => {
          console.log( resp );
    })

    无限滚动

  • 基础组件为 better-scroll ,在此组件上封装了一层业务逻辑,让开发变得轻松一些;
  • 无限滚动组件需要和 Paginate 配合使用,Paginate 实现比较简单,可自行查看源码;
  • 如需修改下拉和上拉样式,可自行修改 ezm-scroll-box 组件;
  • 下拉加载和上拉加载的完整案例
  • <template>
          <div class="">
              <ezm-layout>
                  <van-nav-bar
                      slot="nav"
                      title="下拉刷新加上拉加载更多"
                      left-arrow
                      @click-left="g_navigate.back()"
                  ></van-nav-bar>
                  <!-- 无限滚动组件 -->
                  <!-- 如需下拉或上拉功能,则必须传入分页对象 -->
                  <ezm-scroll-box
                      :pull-down="true"
                      :pull-up="true"
                      :paginate="paginate"
                  >
                      <van-cell
                          v-for="item in list" :key="item.id"
                          :title="item.title"
                          :label="item.label"
                          :value="item.id"
                      ></van-cell>
                  </ezm-scroll-box>
              </ezm-layout>
          </div>
      </template>
      
      <script>
          import EzmLayout from "@/components/layout/ezm-layout";
          import EzmScrollBox from "@/components/scroll/ezm-scroll-box";
          import Paginate from "@/utils/paginate.util";
          import {mockUtil} from "@/utils/common.util";
          import {request} from "@/utils/request.util";
          import {PageMixin} from "@/mixin/navigate.mixin";
      
          export default {
              name: 'BetterScrollAll',
              mixins: [PageMixin],
              components: {EzmScrollBox, EzmLayout},
              data() {
                  return {
                      // 生成分页对象
                      // 分页接受两个参数 Function : 下拉或上拉的回调方法,(可选)Integer : 每页数量
                      paginate: new Paginate(this.getList),
                      list: [],
                  }
              },
              methods: {
                  /**
                   * 进入页面时将自动触发 init() 函数
                   * 返回到此页则不会被执行
                   */
                  init() {
                      // 自动触发下拉刷新操作
                      this.paginate.autoPullDown();
                  },
                  /**
                   * 将会被下拉和上拉回调的函数
                   * paginate 在回调此函数的时候会自动传入 refresh 参数
                   * 下拉刷新则 传入 true, 上拉加载更多则传入 false
                   * @param refresh 是否为下拉刷新
                   */
                  getList(refresh = false) {
                      // 预先使用 mockjs 模拟数据,如有真实接口则无需模拟
                      this.mockData();
                      // 请求 BetterScrollAll 的 get 接口,并传入分页参数
                      // this.paginate.getRequestParams() 可以从分页对象中提取后端需要的分页参数
                      request('BetterScrollAll')
                          .get(this.paginate.getRequestParams())
                          .then(resp => {
                              // 将数据并入 list 或覆盖 list
                              this.list = refresh ? resp.records : this.list.concat(resp.records);
                              // 完成数据加载
                              // 记得一定要传入 resp ,paginate 会根据 resp 结果判定是否还有下一页
                              // 分别显示不同的底部内容,如 ’没有更多了‘ 等;
                              this.paginate.finishLoading(resp);
                          })
                          // 如果请求失败,则必须调用完成数据加载
                          // 无需传递参数,仅结束加载动画
                          .catch(_ => this.paginate.finishLoading());
                  },
                  /**
                   * 模拟 2 页 完整数据,
                   * 第三页数据为 5 条
                   */
                  mockData() {
                      mockUtil.mock(/BetterScrollAll/i, 'get', {
                          code: 200,
                          message: '',
                          data: {
                              current: this.paginate.toPage,
                              size: this.paginate.size,
                              [`records|${this.paginate.toPage > 2 ? 5 : this.paginate.size}`]: [{
                                  'id|+1': (this.paginate.toPage - 1) * this.paginate.size + 1,
                                  'title': '@cname',
                                  'label': '@name',
                              }],
                          }
                      })
                  }
              }
          };
      </script>

    待办队列

  • 我们都知道单页应用都存在一些小问题,比如:打开一个 dialog, 之后点击浏览器返回按钮,发现 dialog 不会消失,因此在弹出 dialog 的时候,可以把 关闭 dialog 的函数添加到 待办队列, 并且在关闭 dialog 的时候,把之前添加进去的 待办函数 移出 待办队列。
  • 待办列表中的函数会在页面离开之前执行,如果强行点击浏览器返回按钮,则一次性执行全部待办函数,如调用 navigate 中的方法进行前进或后退,则会依次(倒序)执行待办函数 (点一次执行一个待办);
  • 具体案例在 demo 中有比较详细的演示,这里提供一个对 vant 的 Dialog.config 封装案例
  • let confirm = (content, title = "确认信息", type = 'warning') => {
        let dialog = Dialog.confirm({
            title: title,
            message: content,
        });
        let task = Events.addWaitTask(() => Dialog.close());
        return dialog.then(() => {
            Events.removeWaitTask(task);
            return Promise.resolve();
        }).catch(() => {
            Events.removeWaitTask(task);
            return Promise.reject();
        })
      }
    • Events 对象中包含了返回回调函数 和 待办列表队列,这里只列出经常使用到的待办相关方法


    • 待办任务 WaitForTask 结构,当使用 Events.addWaitTask 的时候, id 会自动生成一个 uuid,无需手动生成 id,
    export class WaitForTask {
        constructor(id, task) {
            this.id = id;
            this.task = task;
        }
    
        id = '';
        task = null;
    }

    Tags:

    本文暂时没有评论,来添加一个吧(●'◡'●)

    欢迎 发表评论:

    最近发表
    标签列表