1 Star 3 Fork 5

eric.fang / easy-mobile

加入 Gitee
与超过 1200万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
克隆/下载
贡献代码
同步代码
取消
提示: 由于 Git 不支持空文件夾,创建文件夹后会生成空的 .keep 文件
Loading...
README
MIT

Easy Mobile

功能

  • 完善的路由系统,提供常规前进路由功能,同时支持返回钩子、强制刷新、返回跳过等功能;
  • 全局布局组件,提供上中下三层布局结构;
  • 无限滚动组件,提供下拉刷新和下拉加载功能;
  • 页面切换动画效果,类似 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 方法

    方法 作用 参数 备注
    to 跳转到某一个页面 String : 路由path, Object : vue-route的参数 第二参数可不填
    toQuery 带 query 参数跳转 String : 路由path, Object: query 参数 第二参数可不填
    toParams 带 params 参数跳转 String : 路由path, Object: params 参数 第二参数可不填
    back 常规返回上一页
    backInvoke 返回上一页并执行钩子函数 String : 上一页的函数名, ... params : 参数 返回后将执行上一页 methods 中的指定方法
    backSkip 返回并跳过上一页

路由配置和混入

  • 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 中有比较详细的演示,这里提供一个对 vantDialog.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 对象中包含了返回回调函数 和 待办列表队列,这里只列出经常使用到的待办相关方法

    方法 功能 参数 返回 备注
    addWaitTask 添加待办任务 Function: 待办函数 WaitForTask : 待办任务
    removeWaitTask 移除待办任务 WaitForTask : 待办任,| String: 待办任务id 留空则清空所有待办任务
  • 待办任务 WaitForTask 结构,当使用 Events.addWaitTask 的时候, id 会自动生成一个 uuid,无需手动生成 id

    export class WaitForTask {
        constructor(id, task) {
            this.id = id;
            this.task = task;
        }
    
        id = '';
        task = null;
    }
MIT License Copyright (c) 2020 eric.fang Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

简介

快速搭建移动端单页(SPA)应用,解决让人繁琐的前后跳转动画、无限滚动、请求操作、整体布局等等问题,帮助开发人员快速搭建基础功能。 展开 收起
JavaScript
MIT
取消

发行版

暂无发行版

贡献者

全部

近期动态

加载更多
不能加载更多了
JavaScript
1
https://gitee.com/ericfang/easy-mobile.git
git@gitee.com:ericfang/easy-mobile.git
ericfang
easy-mobile
easy-mobile
master

搜索帮助