专栏首页韦弦的偶尔分享微信小程序 router 封装

微信小程序 router 封装

美女镇楼

小程序中的path很多都是相对路径,导航也是一样,但是导航用起来并不是很方便,特别是层级比较多的时候。当然还有从分享页打开时跳转的path,此时要是能设置绝对路径就非常方便了,直接从app.json中拷贝过来就好。

所以做了一个router封装,核心思想是将相对路径例如:../search/search动态的改成../../pages/search/search,而我们要做的就是计算并添加前面的../

举个例子:下面两种写法都是OK的

  wx.navigateTo({
      url: "../search/search"
  })


  wx.navigateTo({
      url: "../../pages/search/search"
  })
一、使用getCurrentPages()获取当前路径path
//在 pages/home/home 中的onLoad中
console.log(getCurrentPages())

打印结果如下:

getCurrentPages()结果1.png

可以看到结果数组的第一个obj的route是我们要的,同时显示的length为1,当我navigate到下一个页面时打印的结果如下:

getCurrentPages()结果2.png

此时第二个页面处于处于结果数组的第二个obj,同时length为2.
因此,获取当前路径的方法为如下:
    const length = getCurrentPages().length;
    const currentRoute = getCurrentPages()[length - 1].route;
二、动态添加前置../

根据相对路径我们知道,当前路径内的/个数代表当前路径的层级,添加相同个数的../即可到达根目录那为了实现我们的目的,可按如下操作:

    //在首页使用
    //path 需要导航的路径的 绝对路径 例如:pages/search/search
    let path = 'pages/search/search'
    const length = getCurrentPages().length;
    const currentRoute = getCurrentPages()[length - 1].route;  //pages/home/home
    const pathIndex = currentRoute.split('/').length;  //3
    let url = ""
    for (let i = 0; i < pathIndex - 1; i++) {
      url += '../'
    }
    path = url + path //  ../../pages/search/search

这个时候我们就获取到了我们需要路径,封装一个方法:

  export function navigateTo(path) {
    const length = getCurrentPages().length;
    const currentRoute = getCurrentPages()[length - 1].route; 
    const pathIndex = currentRoute.split('/').length; 
    let url = ""
    for (let i = 0; id < pathIndex - 1; i++) {
      url += '../'
    }
    path = url + path 
    wx.navigateTo({
      url: path
    })
}
此时我们可以导入这个函数后按如下方式使用:
import { navigateTo } from "../../utils/router.js"
    
navigateTo("pages/search/search")
三、导航已经能用了,但是数据的话,只能拼接在路径后面了,并不是很方便,所以接下来我们继续封装参数

我们拿到参数params,拿到所有的键值对,用?, = , &手动拼接在路径后面

function joinParam(url,param) {
 let keys = Object.keys(params);
  finalUrl = keys.reduce((url, key) => {
    return url + key + "=" + params[key] + "&";
  }, url + "?");
}
//关于reduce函数,这里就不讲了
//实现了循环添加所有key=params[key],并在url后面拼接了'?'

此时我们的函数可以改为:

export function navigateTo(data = { path="", params } = {}) {
    const length = getCurrentPages().length;
    const currentRoute = getCurrentPages()[length - 1].route; 
    const pathIndex = currentRoute.split('/').length; 
    let url = ""
    for (let i = 0; id < pathIndex - 1; i++) {
      url += '../'
    }
   let path = url + data.path 

   if (data.params) {
       path = this.joinParam(path, data.params)
   }
   
    wx.navigateTo({
      url: path,
    })
}

function joinParam(url,param) {
  let keys = Object.keys(params);
  finalUrl = keys.reduce((url, key) => {
    return url + key + "=" + params[key] + "&";
  }, url + "?");
}

使用则改为:

import { navigateTo } from "../../utils/router.js"
    
navigateTo({
  path: "pages/search/search",
  params: {searchId: "1010101"}
})

这里只处理了单纯的路径和参数分开,后续详细版封装了所有情况,比如路径已经有部分参数,后面params又添加了参数,可至文末查看。

四、返回封装,这个就和绝对路径导航没啥关系了,但是作为router的一员,不能厚此薄彼
/**
 * 设置上一页面的数据,并返回
 */
export function navigateBack(data = {}) {
  if (data) {
    const length = getCurrentPages().length;
    var prePage = getCurrentPages()[length - 2]
    if (prePage) {
      prePage.setData(data)
    } 
  }
  wx.navigateBack()
}

// 使用
navigateBack(nickName:"我是新设置的昵称")

当我们需要回调数据至上一个页面时,我们带上参数,不需要回调时,就不写,当然参数名需要同上一个页面一致,这里就没封装跨界面返回回调数据了,用的情况比较少

五、我们还有redirectTo , switchTab , reLaunch这些导航方法,下面分享项目中的router.js,对这些方法做了统一的封装
/**
 *
 * 这里重新封装了导航方法,navigate、redirect、switchTab、reLaunch分别对应着微信的导航方法,
 * 与微信提供的API不通过的是,这里参数data里面的path是静态配置,即app.json文件的页面路径;
 * params为链接查询参数;
 * @example
 * navigate({
 *      path:'pages/index/index',
 *      params:{
 *          id:123
 *      }
 * });//跳转到index页面,index页面的options可以读取到id。
 *
 */

let CURRENT_ROUTE = "";

/**
 * 封装后的 navigate 方法
 * @param {path:静态路径,params: {}}
 */
export function navigate(data = {
  path = "",
  params
} = {}) {
  return route(data, "navigateTo")
}

/**
 * 封装后的 redirect 方法
 * @param {path:静态路径,params: {}}
 */
export function redirect(data = {
  path = "",
  params
} = {}) {
  return route(data, "redirectTo")
}

/**
 * 封装后的 switchTab 方法
 * @param {path:静态路径,params: {}}
 */
export function switchTab(data = {
  path = "",
  params
} = {}) {
  return route(data, "switchTab");
}

/**
 * 封装后的 reLaunch 方法
 * @param {path:静态路径,params: {}}
 */
export function reLaunch(data = {
  path = "",
  params
} = {}) {
  return route(data, "reLaunch");
}

/**
 * 设置上一页面的数据,并返回
 */
export function navigateBack(data = {}) {
  if (data) {
    const length = getCurrentPages().length;
    var prePage = getCurrentPages()[length - 2]
    if (prePage) {
      prePage.setData(data)
    } 
  }
  wx.navigateBack()
}


function route(data, method) {
  try {
    const length = getCurrentPages().length;
    const currentRoute = getCurrentPages()[length - 1].route;
    if (currentRoute == CURRENT_ROUTE) {
      //防止在用一个事件下多次导航到同一个页面
      return;
    }
    CURRENT_ROUTE = currentRoute;
    clearCurrent();
    if (data.path == currentRoute) {
      //不能导航到自己
      return;
    }

    const pathIndex = currentRoute.split('/').length;
    const path = joinPath(pathIndex, data.path)
    const url = joinParams(data.params, path)
    const obj = { ...data,
      url
    };

    //调用微信的router方法
    wx[method].call(null, obj);

  } catch (e) {
    console.log(`error in router: +${e}`)
  }
}

function joinPath(index, url) {
  let str = ""
  for (let i = 0; i < index - 1; i++) {
    str += "../";
  }
  return str + url;
}

function joinParams(params, url) {

  //没有参数,直接返回url
  if (!params) {
    return url;
  }

  let keys = Object.keys(params);
  let finalUrl = ""

  //参数没有key 返回url
  if (keys.length == 0) {
    return url;

  } else {

    //url没有拼接 ?
    if (url.indexOf("?") === -1) {
      finalUrl = keys.reduce((url, key) => {
        return url + key + "=" + params[key] + "&";
      }, url + "?");
    } else {

      //url以 ? 号结尾
      if (url.endsWith("?")) {
        finalUrl = keys.reduce((url, key) => {
          return url + key + "=" + params[key] + "&";
        }, url);

      } else {

        //url以 & 结尾
        if (url.endsWith("&")) {
          finalUrl = keys.reduce((url, key) => {
            return url + key + "=" + params[key] + "&";
          }, url);

        } else {

          //直接拼接
          finalUrl = keys.reduce((url, key) => {
            return url + key + "=" + params[key] + "&";
          }, url + "&")
        }
      }
    }
  }

  return finalUrl.endsWith("&") ?
    finalUrl.slice(0, finalUrl.length - 1) :
    finalUrl;
}


function clearCurrent() {
  setTimeout(() => {
    CURRENT_ROUTE = "";
  }, 0);
}

希望开源这个静态导航能给大家带帮助!

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • SwiftUI:自定义 Shape 使用 InsettableShape 协议实现向内绘制边框

    如果创建的形状没有特定大小,它将自动扩展以占据所有可用空间。例如,这将创建一个填充我们视图的圆,并为其提供40点蓝色边框:

    韦弦zhy
  • 100 Days of SwiftUI —— Day 3:运算符和条件控制

    今天,我们将深入了解Swift的真实细节:运算符和条件控制。这有时会使人们在学习时绊倒,因为正如约瑟夫·坎贝尔(Joseph Campbell)曾经说过的那样,...

    韦弦zhy
  • Swift 删除链表的倒数第N个节点 - LeetCode

    构建双指针first与sec,first先走n步,然后一同运动,当first指向表尾,sec指向的next即是倒数第N个节点,删除即可(next指向next的n...

    韦弦zhy
  • Kernel panic – not syncing: Attempted to kill init

    系统启动的时候,按下‘e’键进入grub编辑界面,编辑grub菜单,选择“kernel /vmlinuz-2.6.23.1-42.fc8 ro root=/de...

    孙杰
  • Spring Cloud(七)服务网关 Zuul Filter 使用

    上一篇文章中,讲了Zuul 转发,动态路由,负载均衡,等等一些Zuul 的特性,这个一篇文章,讲Zuul Filter 使用,关于网关的作用,这里就不再次赘述了...

    搜云库
  • 转:Java 8 重要语言特性:lambda 表达式

    注:本文是笔者在上述地址学习 Java SE 8 Lambda 表达式的笔记。笔者的学习习惯,是在学习过程中将内容敲打一遍,记忆会更加深刻。本文只节选了原文一部...

    剑影啸清寒
  • 工业控制PID系统的十五个基本概念

    PID调节系统PID功能由PID调节器或DCS系统内部功能程序模块实现,了解与PID调节相关的一些基本概念,有助于PID入门新手快速熟悉调节器应用,在自动调节系...

    机器人网
  • 【BDTC 2015】大数据安全分论坛:数据驱动安全

    2015年12月10-12日,由中国计算机学会(CCF)主办,CCF大数据专家委员会承办,中国科学院计算技术研究所、北京中科天玑科技有限公司与CSDN共同协办,...

    CSDN技术头条
  • WebVR或许是我们的未来,但目前还难成主流

    VRPinea
  • 制作nginx+php的docker镜像及其使用技巧

      docker镜像的制作有2种方法,一种是启动一个容器并在容器里操作,再将容器提交为一个新的镜像;一种是写Dockerfile,然后执行dockerfile由...

    菲宇

扫码关注云+社区

领取腾讯云代金券