小程序开发时,会可能会需要开发一个预览码,那么需要怎么开发,下面是开发详细流程及发布过程
最重要的事情莫过于看看微信开发者工具有没有给我们提供这样的接口让我们去操作,经过一番查阅文档我们会发现,果然有!
https://developers.weixin.qq....
会发现,文档给我们提供了两种方式的接口,命令行调用以及HTTP调用。有了接口,一切都好办了,无非就是调一下接口,拿到二维码,贴到页面上去而已嘛,很简单。
梳理开发流程
我们就把这个简单的事情,用流程图说明一下:
https://www.processon.com/vie...
所需技术
工欲善其事,必先利其器,我们要搞这个东西,还是先要把用到的技术整理一下。
好像没别的东西了,用到了再说吧。
为了省事,直接把前后端的东西放在一起。项目目录:
可以看到server这个目录下放的都是后端的东西。
server/index.js
先看看入口文件index.js,从这里我们可以知道后端要做两件事情,第一要能访问到前端build出来的静态资源,第二要能与前端通过HTTP接口进行交互。见代码:
const path = require('path') const Koa = require('koa') const koaStatic = require('koa-static') const bodyParser = require('koa-bodyparser') const router = require('./router') const app = new Koa() const port = 9871 app.use(bodyParser()) // 处理静态资源 这里是前端build好之后的目录 app.use(koaStatic( path.resolve(__dirname, '../dist') )) // 路由处理接口 app.use(router.routes()).use(router.allowedMethods()) // 监听端口 app.listen(9871) console.log(`[demo] start-quick is starting at port ${port}`)
静态资源方面的话使用koa-static即可,重点是怎样给前端提供接口,这就要看路由了。
server/router/index.js
const Router = require('koa-router') // 业务逻辑 const wx = require('../controller/wx') const router = new Router({ // 接口前缀 比如open接口 请求路径就是/api/open prefix: '/api' }) router.get('/open', wx.open) .get('/login', wx.login) .get('/preview', wx.preview) .get('/build', wx.build) module.exports = router
这里可以清晰看到,后端提供了四个接口,但具体每个接口的业务逻辑则封装在controller里的wx.js,如果以后还有别的业务逻辑,就在controller加相应的模块即可。
server/controller/wx.js
// 微信开发者工具接口调用逻辑 const {open, login, preview, build} = require('../utli/wxToolApi') // 处理成功失败返回格式的工具 const {successBody, errorBody} = require('../utli') class WxController { /** * 根据环境对mpvue项目进行打包 * @returns {Promise<void>} */ static async build (ctx) { // 前端传过来的get参数 const query = ctx.request.query if (!query || !query.env) { ctx.body = errorBody(null, '构建项目失败') return } const [err, data] = await build(query.env) ctx.body = err ? errorBody(err, '构建项目失败') : successBody(data, '构建项目成功') } /** * 打开微信开发者工具 * @returns {Promise<void>} */ static async open (ctx) { const [err, data] = await open() ctx.body = err ? errorBody(err, '打开微信开发者工具失败') : successBody(data, '打开微信开发者工具成功') } /** * 登录微信开发者工具 * @returns {Promise<void>} */ static async login (ctx) { const [err, data] = await login() ctx.body = err ? errorBody(err, '登录二维码返回失败') : successBody(data, '登录二维码返回成功') } /** * 查看预览码 * @returns {Promise<void>} */ static async preview (ctx) { const [err, data] = await preview() ctx.body = err ? errorBody(err, '预览二维码返回失败') : successBody(data, '预览二维码返回成功') } } module.exports = WxController
为了代码更加清晰,这里将具体操作微信开发者工具的接口逻辑抽到util/wxToolApi.js里去了,仅仅处理怎样以统一格式返回给前端。
util/wxToolApi.js
const {promiseWrap, successBody, errorBody} = require('../utli') const {INSTALL_PATH, PROJECT_PATH, PORT_PATH, PORT_FILE_NAME, HOST} = require('../const') const {readFile} = require('../utli/nodeApi') const shell = require('shelljs') const axios = require('axios') module.exports = { /** * 根据环境对mpvue项目进行打包 * @param env [doc, pre, prd] * @returns {*} */ build (env) { return promiseWrap(new Promise((resolve, reject) => { // 进入项目目录 shell.cd(PROJECT_PATH) // 执行打包命令 shell.exec(`npm run build:${env}`, function (code, stdout, stderr) { resolve(stdout) }) })) }, /** * 打开微信开发者工具 * @returns {*} */ open () { return promiseWrap(new Promise((resolve, reject) => { // 进入项目目录 shell.cd(INSTALL_PATH) // 执行微信开发者工具接口“命令行启动工具” shell.exec(`cli -o ${PROJECT_PATH}`, function (code, stdout, stderr) { if (stderr) return reject(stderr) resolve(stdout) }) })) }, /** * 获取微信开发者工具端口号 * @returns {Promise<*>} */ async getPort () { shell.cd(PORT_PATH) // http 服务在工具启动后自动开启,HTTP 服务端口号在用户目录下记录,可通过检查用户目录、检查用户目录下是否有端口文件及尝试连接来判断工具是否安装/启动。 const [err, data] = await readFile(PORT_FILE_NAME) return err ? errorBody(err, '读取端口号文件失败') : successBody(data, '读取端口号文件成功') }, /** * 微信开发者工具进行登录 * @returns {*} */ login () { return promiseWrap(new Promise(async (resolve, reject) => { // 获取端口号 const portData = await module.exports.getPort() if (portData.code !== 0) { reject(portData) return } const port = portData.data axios.get(`http://${HOST}:${port}/login?format=base64`) .then(res => { resolve(res.data) }) .catch(e => { reject(e) }) })) }, /** * 微信开发者工具获取预览码 * @returns {*} */ preview () { return promiseWrap(new Promise(async (resolve, reject) => { const portData = await module.exports.getPort() if (portData.code !== 0) { reject(portData) return } const port = portData.data axios.get(`http://${HOST}:${port}/preview?format=base64&projectpath=${encodeURIComponent(PROJECT_PATH)}`) .then(res => { resolve(res.data) }) .catch(e => { reject(e) }) })) } }
这里有一点需要注意,为什么只有open接口需要用命令行调用方式?那是因为HTTP调用方式必须加端口,比如open接口
# 打开工具 http://127.0.0.1:端口号/open # 打开/刷新项目 http://127.0.0.1:端口号/open?projectpath=项目全路径
如果你根本都没有打开微信开发者工具,在以下地方就会找不到端口:
端口号文件位置: macOS : ~/Library/Application Support/微信web开发者工具/Default/.ide Windows : ~/AppData/Local/微信web开发者工具/User Data/Default/.ide
所以作为一个全自动化打码工具,怎么可能还要自己去手动打开微信开发者工具呢!
后端的东西基本就那么多,终于到前端了,前端十分简单,就不多说了:
<template> <div> <group title="请选择环境"> <radio :options="envOption" v-model="env"></radio> </group> <x-button class="btn" type="default" @click.native="handlePreviewProject">点击预览</x-button> <div v-if="loginImg" class="code"> <divider>请先登录</divider> <img class="code-img" :src="loginImg" </div> <div v-if="preImg" class="code" id="preImg"> <divider>预览二维码</divider> <img class="code-img" :src="`${base64Prefix}${preImg}`" </div> </div> </template> <script> import {openProject, login, previewProject, buildProject} from 'SERVICES/index' import {showLoading, hideLoading} from 'UTILS' import { Divider, XButton, Radio, Group } from 'vux' export default { data () { return { // data表示取得数据的协定名称,image/png 是数据类型名称,base64 是数据的编码方法,逗号后面就是这个image/png文件base64编码后的数据。 base64Prefix: 'data:image/png;base64,', // 登录二维码 loginImg: '', // 预览二维码 preImg: '', // 环境 默认为doc env: 'doc', // 所有的环境选项 envOption: ['doc', 'pre', 'prd'] } }, components: { Divider, XButton, Radio, Group }, methods: { handleError (msg) { alert(msg) }, async login () { const {data: {code, data, msg}} = await login() if (code !== 0) { this.handleError(msg) return code } this.loginImg = data return code }, async previewProject () { const {data: {code, data, msg}} = await previewProject() if (code !== 0) { this.handleError(msg) return code } this.preImg = data return code }, async handlePreviewProject () { showLoading() // 重置二维码 this.resetImg() // 打开微信开发者工具 const {data: {code}} = await openProject() if (code !== 0) { // 登录微信开发者工具 await this.login() hideLoading() return } // 根据环境打包 await buildProject(this.env) // 预览 await this.previewProject() hideLoading() }, resetImg () { this.loginImg = '' this.preImg = '' } } } </script> <style lang='less'> .btn { width: 90%!important; margin: 30px auto 30px auto; } .code { display: flex; align-items: center; flex-direction: column; .code-img { width: 300px; height: 300px; } } </style>
这里有一个坑就是,login返回的base64是带了data:image/jpeg;base64,前缀的,所以可以直接放到img的src里,但是获取预览码的preview返回的却没有这个前缀!所以需要自己加上去,就是那个base64Prefix:'data:image/png;base64,'
其实到这里已经基本实现了整个打码功能,但如果真的要可以用还有很多事情没做。
小程序工具提供多类型商城/门店小程序制作,可视化编辑 1秒生成5步上线。通过拖拽、拼接模块布局小程序商城页面,所看即所得,只需要美工就能做出精美商城。更多小程序商店请查看:小程序商店
全国7x24小时客服热线
所有故障均24小时内解决
项目一次性收费安心
技术人员均从业5年以上
通过技术营销传播企业服务价值
丰富的行业实战经验积累
基于需求研发多款产品
针对需求提供精细化服务