一、需求:
微信小程序部分页面需要一键长图的功能。
通过html2canvas插件可以实现,具体可参考微信小程序实现一键长图并保存图片到相册。由于该插件只能在H5项目中使用,则需要截图的小程序页面点击后跳转到H5页面,把所需的token及接口参数带过去,在H5页面进行长截图并保存或转发,点击左上角返回即回到小程序。
二、思路:
首先,考虑需要长截图的页面根据需求可能会迭代增加,新建了一个vue项目,基于vue-cli
脚手架创建了一个项目;
其次,H5页面最重要的就是适配,决定使用rem,根据相关资料发现使用postcss-pxtorem和lib-flexible可以实现vue项目自动将px转成rem
,进行相关下载,配置,在写具体页面时可直接使用px。
最后,打包部署到服务上,微信小程序通过web-view加载该H5页面,在H5页面中引入html2canvas
插件实现页面长截图。
1. 搭建项目,通过rem适配机型
2. 页面请求、路由跳转、插件引入、rem配置、跨域问题
3. 截图样式,滚动、提示
4. 小程序跳转H5传参,H5接收参数
5. 动态表头匹配问题、截图时新结构的添加
6. 取消截图,通过点击触发实现
7. 项目打包部署,替换小程序中跳转的服务地址
8. git创建仓库,上传代码
三、代码:
H5项目
首先安装这两个包
npm install amfe-flexible --save
npm install postcss-pxtorem --save-dev
app.vue
<template>
<div id="app">
<router-view></router-view>
</div>
</template>
<script>
export default {
name: "app",
data () {
return {
// token: ''
}
},
created() {
let params = window.location.href.split("?")[1]
let token = params.substring(params.lastIndexOf("=")+1)
sessionStorage.setItem('token', token)
}
};
</script>
<style>
*{
margin: 0;
padding: 0;
}
html,body{
width: 100%;
height: 100%;
}
#app {
font-family: "Avenir", Helvetica, Arial, sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
color: #2c3e50;
width: 100%;
height: 100%;
overflow-x:hidden;
}
</style>
main,js
import Vue from "vue";
import App from "./App.vue";
import {
Toast,
} from "vant";
import "amfe-flexible/index.js";
import router from "./router";
import axios from 'axios'
import html2canvas from 'html2canvas'
Vue.prototype.$html2canvas = html2canvas
Vue.prototype.$http = axios
// import Echarts from 'echarts'
// Vue.prototype.echarts = Echarts
// Vue.use(Echarts)
Vue.use(Toast);
Vue.config.productionTip = false;
new Vue({
router,
render: h => h(App)
}).$mount("#app");
untils/request.js
import axios from 'axios'
const service = axios.create({
// 请求基础路径
// baseURL: process.env.VUE_APP_BASE_API,
baseURL: '/jupiter/i',
timeout: 5000 // 请求超时时间5秒
})
// 请求拦截器 给请求头设置token
service.interceptors.request.use(
request => {
// 携带token
let token = sessionStorage.getItem('token')
if (token) {
request.headers['authorization'] = token
}
if (request.method === 'post') {
request.params = {
}
}
// eslint-disable-next-line no-unused-expressions
error => {
return Promise.reject(error)
}
return request
}
)
// response interceptor
service.interceptors.response.use(
response => {
const res = response.data
console.log('axios的res', res)
const {
status} = res
switch (status) {
// token失效!
case 710:
console.log('token失效,请返回小程序')
break
case 0:
console.log('请返回小程序')
break
// 统一处理200和错误message
case 200:
return res.data
default:
console.log
}
},
// 作用 catch的处理
error => {
const {
response } = error
if (response && response.status === 404) {
return Promise.reject(error)
}
if (response && response.status === 500) {
return Promise.reject(error)
}
if (response && response.status === 405) {
return Promise.reject(error)
}
return Promise.reject(error)
}
)
export default service
api/test.js
import service from '../untils/request.js';
// 列表
export function boxDataList (data) {
return service({
url: '/box/day/boxData/list',
method: 'get',
params: data
})
}
// 大盘数据
export function boxDataMax (data) {
return service({
url: '/box/day/boxData/max',
method: 'get',
params: data
})
}
vue.config.js
module.exports = {
publicPath: '/',
css: {
loaderOptions: {
postcss: {
plugins: [
require("postcss-pxtorem")({
// 把px单位换算成rem单位
rootValue: 75, // vant官方使用的是75
selectorBlackList: ["vant", "mu"], // 忽略转换正则匹配项
propList: ["*"]
})
]
}
}
},
devServer: {
open: true, //是否自动弹出浏览器页面
host: "0.0.0.0",
port: "8081",
https: false,
hotOnly: false,
proxy: {
"/jupiter/i": {
target: "https://testdata.aaa.com",
ws: true, //代理websockets
changeOrigin: true, // 虚拟的站点需要更管origin
pathRewrite: {
//重写路径 比如'/api/aaa/ccc'重写为'/aaa/ccc'
"^/": ""
}
}
}
}
};
router.index.js
import Vue from "vue";
import VueRouter from "vue-router";
Vue.use(VueRouter);
const router = new VueRouter({
mode: 'history',
base: '/',
routes: [
{
path: '/dayList',
name: '日榜',
component: () => import('./../components/dayList.vue')
},
// {
// path: "/home",
// name: "年榜",
// component: () => import("./../components/Home.vue")
// },
]
});
export default router;
components/dayList.vue
<template>
<div class="dayListBox" @click="cancel">
<div ref="area">
<div class="logoBox" style="display: none">
<img src="../assets/1.png" alt="">