改头换面:迁移既有项目到微信小程序

小程序基础请参考之前的文章: 一个简单的微信小程序DEMO

在既有的html5移动端项目基础上,考虑到其形态和体量很适合转化为微信小程序,遂花费了不长的时间撸起袖子试试看,并将期间遇到的踩坑心得记录在此

目录

  • 复用的mock

  • 素材图片处理

  • 样式的转化

  • 小程序中几种不同的跳转

  • 小失所望的兼容性

  • 差强人意的小程序“组件”

  • 在小程序中实现表格

1. 复用的mock

之前的项目中使用express模拟前后端通信数据(mock),对其稍加改造,就可以在保留对原项目的支持的同时,满足小程序的测试了

1.1 识别请求来源为小程序

//小程序中的每次请求
wx.request({
      url: `http://127.0.0.1:3201${url}`,
      data: assign(
        data, 
        {
          _from_weapp: 1, //添加特殊标记,以作区分
          code: _globalData['wx_code'],
          openid: wx.getStorageSync('openid')
        }
      ),
      
      ...
});
//mock中的过滤器
app.all('/api/*', function(req, res, next) {  

    //判断来源是不是小程序
    const IS_WEAPP = req.method == 'GET'
        ? req.query._from_weapp == 1 
        : req.body._from_weapp == 1;
        
        ...     
});

1.2 登录态和权限管理

  • 服务器端通过用户唯一标识openid识别用户

  • 小程序通过api获得code,传递给服务器换取并缓存openid

  • 每次请求都携带openid

  • 登出或超时后服务器在响应中返回状态码401触发重新登录

1.3 跨域ajax设置

app.all('/api/*', function(req, res, next) {  
    res.header("Access-Control-Allow-Origin", "*");
    res.header("Access-Control-Allow-Credentials", true);
    res.header("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept");  
    res.header("Access-Control-Allow-Methods","PUT,POST,GET,DELETE,OPTIONS");  
    res.header("Content-Type", "application/json;charset=utf-8");  
    next();  
});
  • 要允许小程序跨域访问,服务器端应做必要的设置

  • 最主要的响应头Access-Control-Allow-Origin,在实际测试时不能为通配符 *,应该写为小程序实际发起请求的域名,也就是https://servicewechat.com

2. 素材图片处理

和之前的经验相比,小程序中的素材图片需要考虑以下几点

  • 微信小程序限制总体积,一些资源宜改为远端读取

  • 样式表中直接引用的图片要求绝对路径,对于更改域名等调试操作不便

因此,基本的运用原则就是:最小化使用素材图片,并且除了系统 tabBar 等处用到的图标等需要把图片文件打包到发布结构中,其他素材图片尽量 base64 转码后放入 wxss

/*在wxcc中的引用*/
.figure {
  width: 27rpx;
  height: 25rpx;
  display: inline-block;
  background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABsAAAAZCAYAAADAHFVeAAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAALEgAACxIB0t1+/AAAABd0RVh0Q3JlYXRpb24gVGltZQAyMDE3LjUuMjKXkY//AAAAHHRFWHRTb2Z0d2FyZQBBZG9iZSBGaXJld29ya3MgQ1M26LyyjAAAAgVJREFUSImtldGRokAQhj+te9cQyED22alamAlgyWDZDAxhjeC8CGQjWBKA5YF7381AM8AIvIdpcJxDC8WpskBo/q+b+buZ4K2yqANgBYRADmTaqMaPG7qOx2N3PvVAKfANJHLpN1CVRT2/F+auDiagLVABoTYqAp6AQIDhQ2AitAUOwAtSmTbqG4geBWwr2wB7Ef0BtlKpCwR4HwWT/XgG3sUI0QVgDozau19Y14E1BtqopizqCMgEiMS8AusxsIkIf2mjJv7NsqgzgQB8aKPSWwG91pf+8lclx/U9IH9NgZ2c9zmtTSAfCwKYaqN2WCemPfczbDs8rs9E9MUXlEQi+fvQPjsAmT+avD4bBewcWBZ1Anxieyzyh68YKMfuYyRJ4MWkcr/RRm3g3I2TnuDtFeAc69AAWGmjMudehm2TAzBrNWK97DTOpr48/AYs6Jn2zoTZ4UwYB7TWRs1dja/yb6fxXyPfWOFCYhZYR4dtrGhsJLEk1svdWWV3VPgBNMAf7NzsYkUjwr7y/GJlQyv0YkNOE6czkKMR91Y2tEIv9lKLdAlerczJus3u1goT7L4FQDAI5gH3QKqNqq7EtsCZXHqL9TIbDBORCLvZM6w5cm1U7sXMOVU0a0Ew8DX2iK3k12b+w2lvnuW4B9JYL6v22ZthHjjBfppCrPUb7Bc/b93ojqt/8akRua+fVJwAAAAASUVORK5CYII=');
  background-position: 0 50%;
  background-repeat: no-repeat;
  background-size: contain;
  margin-right: 12rpx;
}
//转码的脚本
const base64Img = require('base64-img');
const imgs = Array.from(process.argv).slice(2);

console.log(imgs.map(imgPath=>{
    let rst = imgPath + '\n-------------------\n';
    rst += base64Img.base64Sync(imgPath);
    rst += '\n\n';
    return rst;
}).join('\n'));

3. 样式的转化

由于之前的项目以较合理的方式运用了 rem 尺寸,稍加改造就可以方便的转化到小程序要求的 rpx

/*既有项目中的LESS预处理*/

@remUIWidth: 720; /*之前的设计图尺寸*/

.px2rem(@px, @name: font-size){
    @{name}: unit(@px, px);
    @{name}: unit(@px / (@remUIWidth / 20), rem);
}

...

.logout {
    .px2rem(130px, margin-left);
}
/*编译结果*/
.logout {
  margin-left: 130px;
  margin-left: 3.61111111rem;
}

改为小程序的 rpx 格式,并依旧用 Less 预处理:

@WEAPP-WIDTH: 750;
@ui-width: 720;

.px2rpx(@px, @name: font-size){
  @{name}: unit(@px, px);
  @{name}: unit( floor(@px * @WEAPP-WIDTH / @ui-width), rpx);
}

...

.logout {
    .px2rpx(130px, margin-left);
}
/*编译结果*/
.logout {
  margin-left: 130px;
  margin-left: 135rpx;
}

4. 小程序中几种不同的跳转

小程序现在并不允许外链,但即使是应用内的跳转,却也分出了好几种不同的方式,即便不爽还是必须了解的:

  • wx.navigateTo() 保留当前页面,跳转到应用内的某个非 tabBar 的页面

  • wx.redirectTo() 关闭当前页面,跳转到应用内的某个非 tabBar 的页面

  • wx.switchTab() 跳转到 tabBar 页面,并关闭其他所有非 tabBar 页面

  • wx.navigateBack() 关闭当前页面,返回上一页面或多级页面

  • wx.reLaunch() 关闭所有页面,打开到应用内的某个页面

<navigator /> 组件中有一个 open-type 属性,分别对应以上类型:

  • navigate 对应 wx.navigateTo 的功能

  • redirect 对应 wx.redirectTo 的功能

  • switchTab 对应 wx.switchTab 的功能 

  • reLaunch 对应 wx.reLaunch 的功能

  • navigateBack 对应 wx.navigateBack 的功能

5. 小失所望的兼容性

小程序虽然已经出台多时,但在很多方面都在不断改变和完善,es6和css的语法方面,可以通过“开启 ES6 转 ES5 ”和“开启 上传代码时样式文件自动补全”来解决,但一些所谓新API,还是要手动判断处理:

旧版本微信客户端不支持 showLoading() / hideLoading()

const hide_loading = () => {
  if (wx.hideLoading) {
    wx.hideLoading()
  } else {
    wx.hideToast()
  }
};

旧版本微信客户端不支持 reLaunch,分情况用不同方法代替

if (wx.reLaunch)
    wx.reLaunch({
      url: rst.route
    })
else 
    wx.switchTab({
      url: rst.route,
    })

某些ios客户端中,程序甫一启动时,立即调用 reLaunch() 会报错,需要延时处理

if (res.statusCode == 401) {
  setTimeout(function() {
    if (wx.reLaunch)
      wx.reLaunch({
        url: '/pages/login/login'
      });
    else
      wx.redirectTo({
        url: '/pages/login/login'
      })
  }, 500);
  return;
}

兼容处理 <navigator /> 组件的 reLaunch 跳转

该例因为是不同参数的本页跳转,在旧版客户端中尝试了几种旧有属性值都无法实现,故特殊处理:

<navigator wx:if="{{ tabs.current !== tab.key }}" 
    url="{{ tabs.links[idx] }}" 
    data-url="{{ tabs.links[idx] }}"
    open-type="{{ tabs.openType }}"
    catchtap="onTabClick">{{ tab.label }}</navigator>
const openType = wx.reLaunch ? 'reLaunch' : 'navigate';

...

//在 onLoad(opts) 中
this.setData({
    tabs: {
        openType,
        current: opts.key,
        tabs: result.tabs,
        links: result.tabs.map(
            tab =>`/pages/path?time=${opts.time}&key=${tab.key}`
        )
    },
    ...
});

...

onTabClick(evt) {
    if (openType === 'reLaunch') return;
    const {url} = evt.currentTarget.dataset;
    const [m, time, key] = url.match(/time\=(.*?)\&key\=(.*?)$/);
    this.onLoad({time, key});
}

其他一般的兼容处理方法见官方文档: https://mp.weixin.qq.com/debug/wxadoc/dev/framework/compatibility.html

6. 差强人意的小程序“组件”

小程序当前并不支持原生的“组件”概念,只能用 js / wxml / wxss 中可用的模块化方法变通替代实现

对于较简单的可复用组件,如果没有较复杂的逻辑,只考虑模版和样式即可:

<!-- tabs.wxml -->
<template name="tabs">
  <view class="top-tabs">
    <block wx:for="{{ tabs.tabs }}" wx:for-item="tab" wx:for-index="idx" wx:key="key">
      ...
    </block>
  </view>
</template>

<!-- rank.wxml -->
<import src="tabs.wxml" />
...
<template is="tabs" data="{{ tabs }}" />
/* tabs.wxss */
.scope {
  overflow: hidden;
}
.top-tabs {
  ...
}

/* rank.wxss */
@import './tabs.wxss';
...

7. 在小程序中实现表格

小程序提供的组件中并不包含tabletheadtr等,但是用css属性和<view />组件旧可以完美模拟一个文首展示的表格

/*table by <view>*/
.table {
    border-collapse:collapse;
    border-spacing:0;
    width:100%;
    display: table;
}
.table .thead {
  display: table-header-group;
}
.table .tbody {
  display: table-row-group;
}
.table .tr {
  display: table-row;
}
.table .th,
.table .td {
  display: table-cell;
}

* 原创文章转载请注明出处

-------------------------------------

长按二维码关注我们的公众号哦:

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值