Contents
前言
最近新接触了小程序开发领域,在工作中使用 Taro
进行微信小程序相关开发,一如既往,踩坑记录也要留下。
Taro 是一个开放式跨端跨框架解决方案,支持使用 React/Vue/Nerv
等框架来开发 微信 / 京东 / 百度 / 支付宝 / 字节跳动 / QQ 小程序 / H5 / RN 等应用。
现如今市面上端的形态多种多样,Web、React Native、微信小程序等各种端大行其道。当业务要求同时在不同的端都要求有所表现的时候,针对不同的端去编写多套代码的成本显然非常高,这时候只编写一套代码就能够适配到多端的能力就显得极为需要。
微信小程序开发相关
I. 微信小程序像素单位rpx
Taro 默认以 750px 作为换算尺寸标准,如果设计稿不是以 750px 为标准,则需要在项目配置 config/index.js 中进行设置让微信正确将 rpx 转换为实际屏幕物理像素。例如设计稿尺寸是 640px,则需要修改项目配置 config/index.js 中的 designWidth 配置为 640,如果设计稿是 375px,不在以上三种之中,那么你需要把 designWidth 配置为 375,同时在 DEVICE_RATIO 中添加换算规则如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
| const config = { projectName: '', designWidth: 750, deviceRatio: { '375': 2 / 1, '640': 2.34 / 2, '750': 1, '828': 1.81 / 2 }, mini: { postcss: { pxtransform: { enable: true, config: { onePxTransform: true, unitPrecision: 5, propList: ['*'], selectorBlackList: [], replace: true, mediaQuery: false, minPixelValue: 0, } }, }, ... };
module.exports = config;
|
rpx 即 responsive pixel,可以根据屏幕宽度进行自适应的像素单位,比如规定屏幕宽为 750rpx。以 iPhone6 为例,屏幕宽度为 375px,共有 750 个物理像素,则 750rpx = 375px = 750 物理像素,1rpx = 0.5px = 1 物理像素。
小程序中默认配置会将所有的 px 单位转换为 rpx,有大写字母的 Px 或 PX 则会被忽略,可以自己在配置中设置自动转换规则(config.mini.postcss.pxtransform)。
II. 微信小程序自定义导航头适配胶囊按钮高度
如果某个小程序页面需要自定义导航头部的话,就需要启用相应页面的自定义导航头功能,可以在相关的 page.config
里面配置,比如:
1 2 3 4 5 6 7
| export default { navigationBarTitleText: '首页', navigationBarTextStyle: 'white', navigationStyle: 'custom', navigationBarBackgroundColor: '#2F66FE', enableShareAppMessage: true, };
|
1)原理:根据系统API - getMenuButtonBoundingClientRect
获取小程序右上角胶囊按钮的位置和宽高信息:
导航头垂直居中的情况下,导航头高度即为:bottom - height / 2
(胶囊按钮底部位置 - 胶囊按钮高度的一半)
- bottom [number] 下边界坐标,单位:px
- height [number] 高度,单位:px
- left [number] 左边界坐标,单位:px
- right [number] 右边界坐标,单位:px
- top [number] 上边界坐标,单位:px
- width [number] 宽度,单位:px
2)自定义导航头部源代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45
| import React, { Component } from 'react' import Taro from "@tarojs/taro"; import { View, Image, Text, Button } from '@tarojs/components';
import './index.scss';
export default class XbHeader extends Component {
state = { navHeight: '48rpx' } componentDidMount () { this.setNavSize(); } setNavSize = () => { const sysinfo = Taro.getSystemInfoSync(); const { top, height, bottom } = Taro.getMenuButtonBoundingClientRect(); const navHeight = bottom - height / 2;
this.setState({ navHeight: `${navHeight}px` }); }
render () { const { navHeight, statusHeight } = this.state;
return ( <View className='xb-header' style={{ top: navHeight }}> <View className='iconfont icon-xiebaojia'></View> <View className='title'> <View className='title-text'>纳斯达克上市</View> <View className='title-text'>全国保险经纪牌照</View> </View> </View> ); } }
|
III. 微信小程序底部导航条适配 Iphonex
1. 原生小程序适配
> 底部导航条页面结构(fixed定位到屏幕底部):
1 2 3 4 5 6 7 8 9 10 11 12 13
| <View className='member-identify-footer' style={{paddingBottom: utils.isIphoneX() ? utils.getScreenContentRect().padding : '10rpx' }} > <View className='footer-item-wrapper' onClick={this.goBack}> <View className='item-icon'></View> <View className='item-title'>{ routerAction[from].text }</View> </View> <View className='footer-item-wrapper' onClick={this.importAction}> <View className='item-icon'></View> <View className='item-title'>导入信息正确人员</View> </View> </View>
|
> 原理:通过API获取屏幕尺寸参数和屏幕安全区域参数,利用 getScreenContentRect 函数得到计算值:
- 安全内容区域顶部坐标
top
:可用于其它元素进行顶部位置定位 - 安全内容区域底部坐标
bottom
:可用于其它元素进行底部位置定位 - 底部非安全内容区域内容高度
padding
:可用于其它元素进行位置定位
> 屏幕安全内容区域计算函数:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
|
const getScreenContentRect = (_footerHeight='85rpx', _systemInfo=null, _menuInfo=null) => { const systemInfo = _systemInfo || Taro.getSystemInfoSync(); const menuInfo = _menuInfo || Taro.getMenuButtonBoundingClientRect(); const { screenHeight, safeArea } = systemInfo const { bottom } = safeArea;
return { top: `${menuInfo.bottom + 10}px`, bottom: `calc(${screenHeight - bottom}px + 10rpx + ${_footerHeight})`, padding: `calc(${screenHeight - bottom}px + 10rpx)` }; }****
|
> 示意图:
位置标识图1:
真机标识图2:
2. 内嵌 H5 适配
> js 简易判断是否是 iphonex 以上的机型:
1 2 3 4 5 6 7 8 9
| function isIphonex() { return ( window && navigator.userAgent.indexOf('iPhone') > -1 && window.screen.height >= 724 && window.devicePixelRatio >= 2 ); },
|
> 如果是 iphonex 机型则添加相应的适配类名:
1 2 3 4 5 6 7 8 9 10
| $(function() { var isIphonex = T.check.isIphonex(); $('div[data-action=iphonex]').each(function() { if (isIphonex) { $(this).addClass('iphonex'); } else { $(this).removeClass('iphonex'); } }); });
|
> 样式表:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| .page-footer { display: flex; flex-direction: row; position: absolute; bottom: 0; left: 0; right: 0; padding: rem(10px) rem(48px) rem(10px); background-color: white;
&.iphonex { padding-bottom: rem(88px); } }
|
IV. H5页面唤起指定的小程序并打开特定页面
>>> 官方文档链接
原理:使用官方的 scheme url 生成接口生成系统可识别的小程序链接,类似于:weixin://dl/business/?t=DQftHzg06Tj
Node.js (Express) 端生成 url 示例代码:
值得注意的是前端不能将 path 路径参数使用 encodeURIComponent
进行特殊字符编码,否则微信接口不能识别。最后网页端拿到后直接:location.href = [url]
就可以在网页唤醒微信指定页面了。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60
| const miniApps = { appId: "小程序id", appSecret: "小程序秘钥" };
router.post(/^(?:\/m)?\/get\/wechatUrlSchema\/?$/, function(req, res) { let url = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=" + miniApps.appId + "&secret=" + miniApps.appSecret;
const { path = '', query = '' } = req.body;
request.get({ url: url }, function(err, httpResponse, body) { if (!err && httpResponse.statusCode == 200) { const data = JSON.parse(body); const access_token = data.access_token; url = "https://api.weixin.qq.com/wxa/generatescheme?access_token=" + access_token; request .post({ url: url, json: true, body: { is_expire: true, expire_type: 1, expire_interval: 1, jump_wxa: { path: path, query: query } } }, function(error, response, body) { if (!error && response.statusCode == 200) { res.json(body); } else { res.json({ success: false, code: response.statusCode, msg: error || '获取小程序码失败' }); } }); } else { res.json({ success: false, code: httpResponse.statusCode, msg: err || '获取小程序密钥失败' }); } }); });
|
V. 实现将任意 dom 元素内部 innerText 复制到剪贴板
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
|
function copyElementText($elem) { var input = document.createElement('textarea'); var issuccess = false;
input.setAttribute('readonly', 'readonly'); input.setAttribute('type', 'text'); input.value = $elem.innerText; document.body.appendChild(input); input.select(); if (document.execCommand && document.execCommand('copy')) { document.execCommand('copy', false, null); issuccess = true; } document.body.removeChild(input);
return issuccess; }
|