基于vue-next(vue3)企业微信H5搭建

959 阅读3分钟

背景

业务需要,需要编写一个服务在企业微信里面的H5应用。需要解决的问题有:

  • UI库选型
  • 响应式布局
  • 按需引入组件
  • 企业微信登录
  • 本地预览
  • http请求
  • 水印
  • 企业微信桌面端支持

UI库选型

已有的移动端组件库(vue)有。

根据实际需求,选择适合自己的组件库。个人推荐 vant。一直持续更新中。

响应式布局

利用的是postcss-pxtorem 这个库

vue.config.js 里面配置下就行了

module.exports = {
    css:{
        loaderOptions:{
            postcss:{
                plugins:[
                    pxtorem({
                            rootValue: 37.5, // 375 是视觉稿尺寸。
                            propList: ['*'],
                            minPixelValue: 2 // min pixel value
                        })
                ]
        }   
    }
}

按需引入组件

利用的是 babel-plugin-import 组件

对于 vant 的配置

babel.config.js 文件里面

module.exports ={
    plugins: [
    [
      'import',
      { libraryName: 'vant', libraryDirectory: 'es', style: true },
      'vant',
    ],
  ],   
}

然后就可以按需引入组件了。

// 插件会自动将代码转化为方式二中的按需引入形式
import { Button } from 'vant';

企业微信登录

对于企业微信登录,需要用到微信提供的url

const oauthUrl =  `https://open.weixin.qq.com/connect/oauth2/authorize?appid=${appid}&redirect_uri=${encodeURIComponent(redirectUrl)}&response_type=code&scope=snsapi_base&state=STATE#wechat_redirect`

其中 appid 是企业微信的 appid, redirect_uri 是获取到code 之后,重新跳转到的url。

我使用的是vue-router 库,通过方法 router.beforeEach()router.afterEach() 拦截路由变化

在 beforeEach方法里面


router.beforeEach((to,form,next)=>{
    // 先检查是否已经登录了。
    
    // 检查参数中是否有code 参数
    if(to.query.code){
        // 拿code 请求服务器端,获取到用户信息。
        
        // 然后走后续的流程。。
        next({...to, replace: true});
    }
    else{
        // 跳转微信授权。
        const currentHref = window.location.href;
        window.location.href = getWxOauth2Url(currentHref);
    }
})

在 afterEach 方法里面

router.afterEach((to,from,next)=>{
    // 更改titile 
    document.title = (to.meta && to.meta.title) || '';
})

本地预览

当执行了vue-cli

{
    "build": "vue-cli-service build",
}

之后,生成了 dist 目录之后,如何预览呢,这个时候就需要一个http服务,并支持代理接口。

/**
 * 使用nodejs创建本地的http服务
 * */
var http = require('http');
var url = require('url');
var path = require('path');
var fs = require('fs');
var httpProxy = require('http-proxy');
var proxy = httpProxy.createProxyServer(); // See (†)

var requestType = {
    "css": "text/css",
    "js": "text/javascript",
    "html": "text/html"
};

var config = {
    target: 'http://service.com',
    port: 3000,
    host: 'local.service.com',
    dir: '../dist',
    prefix: '/api', // api prefix 
    debug: true
};

var proxyConfig = {
    target: config.target,
    changeOrigin: true,
};

//
http.createServer(function (request, response) {
    var pathName = url.parse(request.url).pathname;
    var realName = path.join('.', pathName);
    var ext = path.extname(pathName);
    ext = ext ? ext.slice(1) : 'unknown';

    // 走转发走
    if (pathName.indexOf(config.prefix) !== -1) {
        config.debug && console.log(`Rewriting path from "${pathName}" =====> to "${proxyConfig.target}${pathName}"`);
        proxy.web(request, response, proxyConfig);
        return;
    }

    config.debug && console.log(pathName);
    if (pathName.indexOf('css') === -1 && pathName.indexOf('js') === -1 && pathName.indexOf('img') === -1) {
        pathName = '/index.html';
    }

    realName = path.join(__dirname, config.dir, pathName);

    config.debug && console.log(realName);

    fs.exists(realName, function (exists) {
        if (!exists) {
            response.writeHead(404, {'Context-type': 'text/plain'});
            response.write('this request url ' + pathName + ' was not found on this server.');
            response.end();
        } else {
            fs.readFile(realName, 'binary', function (err, file) {
                if (err) {
                    response.writeHead(500, {'Context-type': 'text/plain'});
                    response.end(err);
                } else {
                    var contentType = requestType[ext] || "text/plain";
                    response.writeHead(200, {'Context-type': contentType});
                    response.write(file, 'binary');
                    response.end();
                }
            });
        }
    });
}).listen(config.port, config.host);

console.log(`server running at http://${config.host}:${config.port}/`);

这里就是一个最简单的 http 服务,并依赖 http-proxy 库 走api 的转发。

http请求

对于 http的请求,我选择的是 axios 这个库,当然也有其他更好的库选择。

水印

一般在企业微信里面,都需要添加水印来保护公司的一些信息不被乱传播出去。这个时候就需要使用水印。

所使用的库是 watermark-dom

企业微信桌面端支持

企业微信是有手机端,也有桌面端,所以在支持手机端的同时最好也适配下桌面端。

Vant 是一个面向移动端的组件库,因此默认只适配了移动端设备,这意味着组件只监听了移动端的 touch 事件,没有监听桌面端的 mouse 事件。

如果你需要在桌面端使用 Vant,可以引入我们提供的 @vant/touch-emulator,这个库会在桌面端自动将 mouse 事件转换成对应的 touch 事件,使得组件能够在桌面端使用。

# 安装模块
npm i @vant/touch-emulator -S

// 引入模块后自动生效
import '@vant/touch-emulator';

demo地址

demo bosscheng.github.io/vue3-mobile…

github github.com/bosscheng/v…