一 canvas
一个好消息是小程序基础库 v2.9.0 正式开放一套全新的 Canvas 接口。该接口符合 HTML Canvas 2D 的标准,实现上采用 GPU 硬件加速,渲染性能相比于现有的 Canvas 接口有一倍左右的提升。
新版Canvas 2D接口与Web 几乎完全一致了。这对H5和小程序的同构有很大的便利。
要注意的就是新版的Canvas可以不需要canvas-id,但是必须要type="2d";
目前是两种 context 是共存的。
kbone里通过?getContext的方式画图,canvas节点里必须要有canvas-id;通过 ?prepare的需要有type="2d"
canvas 在小程序里空白
初次使用canvas,常会遇到在小程序里空白的问题,踩过的坑如下:
1 canvas 没显式定义宽高
没有显式定义宽高的情况下,web还能显式正常,默认宽高是300**150:

miniprogram里没有显式定义宽高的情况下,虽然默认宽高也是300**150,但是画布空白(这一点kbone可以做到才对,计划有时间就去看下这个问题):

以下2种方式设置宽高都可以,看业务场景选择,但是注意不能用style设置宽高,内联的也不行:
1、

2、

显式设置后再看下web和mp的表现:


2 canvas 获取dom未成功
还有一种情况是在小程序里获取dom没有成功。 可以将在获取dom后将dom打印出来看看。 遇到的一个没有结论的问题是:
通过ref获取canvas dom还是通过querySelector/getElementById

通过ref获取,可以看到web是没有问题的,和用id获取是一致的。但是mp里,曾经遇到过canvas.js里res节点为null的问题,即?prepare回调函数的参数domNode为null。但是后面再跑又莫名消失了。尚未定位原因。

3 canvas clearRect
在web中,当设定 domNode的宽高时,画布会自动清空内容,如下图显示:


而在小程序中,需要显式设置 ctx.clearRect(0,0,domNode.width,domNode.height)
二 request
request:本来是计划用 kbone-api里面提供的request api,但是它的request里对url要求是http https完整路径的请求格式:

这种情况下无法用devserver的proxy功能(除非自己起一个接口服务)。为了开发方便,更换为了axios和axios-miniprogram-adapter,下面是我们二次封装的request模块:
// src/request/http.js
/* eslint-disable */
import axios from 'axios'
import mpAdapter from 'axios-miniprogram-adapter'
import QS from 'qs'
if (process.env.isMiniprogram) {
axios.defaults.adapter = mpAdapter
}
// 请求拦截
axios.interceptors.request.use(
(config) => {
// config.headers = {
// 'Content-Type': 'application/x-www-form-urlencoded;charset=UTF-8',
// }
return config
},
(error) => Promise.error(error)
)
// 响应拦截
axios.interceptors.response.use(
(response) => {
let {
data
} = response
if (response.status === 200) {
if (data && data.code != '0') {
// data.code非0则接口异常
return Promise.reject(data)
}
return Promise.resolve(data.resultData)
} else {
return Promise.reject(data)
}
},
// 服务器状态码不是2开头的的情况
// 这里可以跟后台开发人员协商好统一的错误状态码
// 然后根据返回的状态码进行一些操作,例如登录过期提示,错误提示等等
// 下面列举几个常见的操作,其他需求可自行扩展
(error) => {
const {
response
} = error
if (response) {
switch (response.status) {
// 401: 未登录
case 401:
// 未登录则跳转登录页面,并携带当前页面的路径
// 在登录成功后返回当前页面,这一步需要在登录页操作。
break
// 403 token过期
case 403:
// 登录过期对用户进行提示toast或者dialog
// 清除本地token和清空vuex中token对象
// 跳转登录页面
break
// 404请求不存在
case 404:
// 对用户进行提示toast或者dialog
break
// 其他错误,直接抛出错误提示
default:
// 其他对应处理或者直接对用户进行提示toast或者dialog
}
return Promise.reject(response.data)
} else {
// 这里处理断网的情况 进行提示
}
}
)
/**
* get方法,对应get请求
* @param {String} url [请求的url地址]
* @param {Object} params [请求时携带的参数]
*/
export function get(url, params) {
return new Promise((resolve, reject) => {
axios
.get(url, {
params: params,
})
.then((res) => {
resolve(res)
})
.catch((err) => {
reject(err)
})
})
}
/**
* post方法,对应post请求
* @param {String} url [请求的url地址]
* @param {Object} params [请求时携带的参数]
*/
export function post(url, params) {
return new Promise((resolve, reject) => {
axios
.post(url, QS.stringify(params))
.then((res) => {
resolve(res)
})
.catch((err) => {
reject(err)
})
})
}
// src/request/api.js
const url = {
test: '/api/forward?apiType=micro_service'
}
console.log(process.env.NODE_ENV)
if (process.env.NODE_ENV === 'production' || process.env.isMiniprogram) {
Object.keys(url).forEach((item) => {
url[item] = `https://xxxx.com${url[item]}`
})
}
export default url
在main.js里绑定为vue的全局api

在业务中调用:
import url from '../../request/api'
this.$get(url.test, {})
.then((res) => {
this.$api.showToast({
title: '请求成功',
})
console.log('--------requestTest----------')
console.log('url.test:' + url.test)
console.log(res)
})
.catch(() => console.log('promise catch err'))
三 屏幕适配
kbone的官网上介绍它没有用小程序的rpx进行屏幕适配,取而代之的是使用更为传统的 rem 进行开发。
理论上支持vw没问题。这里采用 postcss-px-to-viewport 自动将px转换为vw,进行屏幕适配。
首先
npm install postcss-px-to-viewport --save-dev
或者使用yarn安装
yarn add postcss-px-to-viewport -D
在工程目录下建 postcss.config.js
postcss-loader默认是会从项目根目录获取这个配置项。但是有优先级,webpack里配置的options优先级是高于独立配置文件的。
而kbone的几个构建方式有差异,option在每个webpack里不完全相同,无法公用同一个postcss.config.js.所以我们在 postcss.config.js里只存放公用的插件配置,引入webpack的几个配置文件中。
需要注意的是,postcss-loader的options里配置plugins时只接受array或者以及function,不接受object(与自动加载项目根路径的postcss.config.js接受object的常见写法不同)。
kbone的配置里已经是数组形式,所以我们也继续写为数组形式,以匹配原来的配置。
具体代码如下:
// ./postcss.config.js
const pxtovw = require('postcss-px-to-viewport');
module.exports = {
plugins: [
new pxtovw({
unitToConvert: 'px', //需要转换的单位,默认为"px";
viewportWidth: 375, //设计稿的视口宽度
unitPrecision: 3, //单位转换后保留的小数位数
propList: ['*'], //要进行转换的属性列表,*表示匹配所有,!表示不转换
viewportUnit: 'vw', //转换后的视口单位
fontViewportUnit: 'vw', //转换后字体使用的视口单位
selectorBlackList: ['.ignore', '.hairlines'], //不进行转换的css选择器,继续使用原有单位
minPixelValue: 1, //设置最小的转换数值
mediaQuery: false, //设置媒体查询里的单位是否需要转换单位
replace: true, //是否直接更换属性值,而不添加备用属性
exclude: [/node_modules/] //忽略某些文件夹下的文件
})
]
};
以webpack.dev.config.js为例:
// ./build/webpack.dev.config.js
const postcssConfig = require('../postcss.config')
...
module: {
rules: [{
test: /\.(less|css)$/,
use: [{
loader: 'vue-style-loader',
}, {
loader: 'css-loader',
}, {
loader: 'postcss-loader',
options: {
plugins: [
autoprefixer, postcssConfig.plugins[0]
],
}
}, {
loader: 'less-loader',
}],
}],
},
...
reference: